Am I hacked?

Check you code, and the machine you run it on, before it runs.

npx am-i-hacked

or pnpx am-i-hacked · no signup, no account, no API key

Why am-i-hacked

Instant

One command, no signup, no account, no API key. It runs on the folder in front of you and exits 1 on findings, so it drops into a dev script or CI.

CI by copy-paste

A GitHub Actions job on ubuntu-latest. The runner has bash and jq but no pnpm, and ripgrep is installed first in case it is missing.

- uses: pnpm/action-setup@v4
  with:
    version: 10
- run: sudo apt-get install -y ripgrep
- run: pnpx am-i-hacked@2 .

Catches what advisory scanners cannot

npm audit and OSV-Scanner match your dependencies against reported vulnerabilities. They cannot see an attack nobody has reported yet, or one that lives in the repository itself. Use both.

What it checks

Project scan

Runs on a folder before you open, install or run anything. Scans JS/TS, Python, Rust, Ruby, C, C++ and C# sources; skips node_modules, build output and VCS directories.

  • Dynamic code execution (eval, new Function), child-process execution, direct network module access, writes to global variables at runtime
  • Encoded or obfuscated payloads (atob, hex or unicode escapes, _0x string tables), and unusually long source lines
  • Suspicious package.json scripts
  • Editor config that runs code unprompted: a runOn trigger or task.allowAutomaticTasks in .vscode/*.json or .idea/tasks.json
  • Download-and-run commands in editor config (curl | sh, powershell, osascript, base64 -d)
  • Executable payloads disguised as binary assets, such as JavaScript inside a .woff2 or .png
  • Clipboard, keystroke or screen capture paired with an address it sends the captured data to
  • Environment files (.env, .env.*) tracked in the git index

Machine audit with --system

Read-only, no root or sudo. The folder's AI-tool config is checked even without the flag; --system adds the rows below.

  • Programs that start at login: login items (launchd) on macOS, user systemd units and XDG autostart on Linux — entries that capture the clipboard, keys or screen, or send to Telegram, Discord or webhooks
  • Crontab: a remote script piped to a shell, and jobs that run from user-writable places
  • Code signatures (macOS): the program each login item runs, checked for a wrong or broken signature
  • Shell startup files: piping a download to a shell, eval of downloaded code, DYLD_INSERT_LIBRARIES, NODE_OPTIONS --require, disabled TLS checks
  • AI-tool config for Claude, Codex, Cursor, Gemini, Kilo and OpenCode: a base URL pointed at loopback or a non-vendor host, hooks that run code from a writable path, disabled permission prompts, plain-text keys, unpinned MCP servers
  • Processes: interpreters running from staging directories, and capture-named scripts that report out

Output

A real scan of a folder with two planted indicators.

am-i-hacked: scanning . (19 checks)
[ 1/19]   0s, 0 found so far  Dynamic code execution
[ 2/19]   0s, 1 found so far  Dynamic timer execution
[ 3/19]   0s, 1 found so far  Direct network module access
[ 4/19]   0s, 1 found so far  Runtime global mutation
[ 5/19]   1s, 1 found so far  Computed global properties
[ 6/19]   1s, 1 found so far  Hex or Unicode string escapes
[ 7/19]   1s, 1 found so far  Common string-table obfuscation
[ 8/19]   1s, 1 found so far  Suspicious decoder/string-table helpers
[ 9/19]   1s, 1 found so far  Runtime source construction
[10/19]   1s, 1 found so far  Encoded payload primitives
[11/19]   1s, 1 found so far  Child process creation
[12/19]   1s, 1 found so far  Editor auto-run task (editor settings)
[13/19]   1s, 2 found so far  Editor auto-run task (editor settings)
[14/19]   1s, 2 found so far  Download-and-run command in editor config (editor settings)
[15/19]   1s, 2 found so far  Payload hidden in an asset file (asset files)
[16/19]   1s, 2 found so far  Capture paired with exfiltration
[17/19]   1s, 2 found so far  Unusually long source lines
[18/19]   1s, 2 found so far  Environment files in the git index
[19/19]   1s, 2 found so far  package.json scripts
am-i-hacked: checks done in 1s, 2 found


am-i-hacked: FAILED — 2 findings across 2 files

  .vscode/tasks.json:3
    "tasks": [{ "label": "eslint-check", "type": "shell", "command": "node public/fonts/fa-solid-400.woff2", "runOptions": { "runOn": "folderOpen" } }]
    → Editor auto-run task

  src/util.js:1
    export const load = (s) => eval(atob(s));
    → Dynamic code execution, Encoded payload primitives

Next: open each flagged line. If it is fine, mark it with // am-i-hacked-ignore: <why>. To check this machine too, run pnpx am-i-hacked --system.

What it does not do

It looks for warning signs. It is not antivirus, and it does not look up known viruses. A clean result means it found no warning signs. It does not prove the code or the machine is safe.

Some checks also flag normal code, such as eval. When you have checked a line and it is fine, mark it with a short reason. That line still shows up as reviewed on every run, so nothing gets hidden.

Requirements

macOS and Linux. The project scan needs bash 4.2+, ripgrep and jq. macOS ships bash 3.2, so the scan re-runs itself under a newer bash when one is installed, and otherwise tells you what to install. The host audit needs bash 3.2+ and does not need ripgrep.