They answer different questions, so use more than one. am-i-hacked looks for signs that a project or machine is under attack. secure-semgrep finds insecure code with static analysis. npm audit, OSV-Scanner and Snyk match dependency versions against published advisories. Antivirus matches known malware. None of them proves code is safe.
Before merging code you or an AI agent wrote: secure-semgrep, and your advisory scanner over the lockfile.
+
On every dev-server start and in CI: am-i-hacked and your advisory scanner. Both exit non-zero on findings.
+
When a machine might be compromised:am-i-hacked --system and am-i-being-recorded, alongside your antivirus or EDR, not instead of it.
+
+
+
Questions
+
Is am-i-hacked antivirus?
+
No. Antivirus matches files and behavior against known malware. am-i-hacked reads source code and configuration for warning signs of an attack, such as an editor task that runs on folder open or capture code paired with an exfiltration endpoint. It does not look up known malware, and a clean result does not prove safety.
+
Does am-i-hacked replace npm audit, OSV-Scanner or Snyk?
+
No. Those tools match dependency versions against published advisories. am-i-hacked looks for indicators in the code itself, including attacks committed into the repository or not yet reported. Run both.
+
What is the difference between am-i-hacked and secure-semgrep?
+
am-i-hacked looks for signs that code is malicious before you run it. secure-semgrep runs Semgrep static analysis to find insecure code you or an AI agent wrote, with bundled rules for AI-agent code, shell scripts and SSRF. They are complementary.
+
Is secure-semgrep a replacement for Semgrep?
+
No. It is a thin wrapper that needs semgrep installed. It adds bundled rules and picks Semgrep registry packs for your stack in one command.
+
+
+
+
+
+
+
+
+
diff --git a/docs/guides/ai-generated-code-security/index.html b/docs/guides/ai-generated-code-security/index.html
new file mode 100644
index 0000000..ce32127
--- /dev/null
+++ b/docs/guides/ai-generated-code-security/index.html
@@ -0,0 +1,178 @@
+
+
+
+
+
+Is AI-generated code safe to run? How to check code from an AI coding agent
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Skip to content
+
+
Not automatically. An AI coding assistant can add a dependency you did not ask for, copy a setup command from an untrusted page, write config that runs on startup, or produce insecure code that calls a model. Before you run it, scan the project with npx am-i-hacked for malicious-code indicators and npx secure-semgrep . for insecure AI-agent, shell and SSRF patterns, then review every new dependency and config file yourself.
+
+
What goes wrong with AI-written code
+
+
Dependencies you did not choose. Assistants sometimes suggest package names that do not exist or are near-misses of real ones. Attackers register those names. Check that every new dependency is the package you meant, with a real history.
+
Setup steps copied from somewhere else.curl ... | sh, a postinstall script, an editor task. An agent that browses can repeat what an untrusted page told it.
+
Config that runs code. Agent hooks, MCP server definitions, .claude/settings.json, .mcp.json and editor settings all start programs.
+
Insecure model-calling code. Hardcoded API keys, model output passed to exec, user input placed in a system prompt, no token limit.
+
Server code that fetches URLs without checking where they point. See SSRF.
+
+
+
How to check it
+
+
Scan for malicious-code indicators. From the project folder:
+
npx am-i-hacked
+ It reads the source and the project's own AI-tool config (.claude/settings*.json, .mcp.json) and exits 1 on findings. Add it in front of the dev server so it runs every time:
+
{ "scripts": { "dev": "am-i-hacked && next dev" } }
+
+
Scan for insecure AI-agent code. secure-semgrep runs Semgrep with bundled rules for LLM and agent code, plus Semgrep's own default and security-audit packs. It needs semgrep installed.
+
npx secure-semgrep .
+npx secure-semgrep -L ts -L node . # add the packs for your stack
+
+
Review every new dependency by hand, and run your advisory scanner (npm audit, OSV-Scanner) over the lockfile.
+
Read every new config and script file the assistant created or changed: package.json scripts, *.config.*, editor tasks, agent hooks, CI workflows.
+
Check the machine the agent runs on with npx am-i-hacked --system, which reads user-level config for Claude Code, Codex, Cursor, Gemini CLI, OpenCode and Kilo Code. See how to check a developer machine.
+
+
+
What the secure-semgrep AI rules cover
+
+
Area
Examples of what is flagged
+
+
Model provider SDKs (OpenAI, Anthropic, Gemini, Cohere, Mistral, Hugging Face)
Hardcoded API keys, user input in the system prompt, no max-tokens limit, missing refusal, moderation or safety checks, no error handling
+
Agent code
Model output passed to code execution, LangChain dangerous execution, an agent loop with no bound
+
MCP servers
Command injection in tool handlers, credentials returned in responses, hardcoded secrets in config, SSRF, tool poisoning, typosquatted tool names, unsanitized return values
+
Agent and editor settings
Claude Code settings that bypass permissions, auto-enable MCP servers or redirect the API URL; editor settings that point at an executable; hidden Unicode in AI config
Prompt injection, data exfiltration, reading sensitive files, base64 payloads
+
+
+
Rules cover Python and TypeScript most fully, with Go, Java, Ruby and others for some checks. Every finding is a prompt to look, not a verdict.
+
+
Limits
+
Neither tool reads your intent. A scan finds known patterns; it does not prove that the code does what you asked or that it is safe. Neither tool scans installed dependencies in node_modules. Code review is still the check that matters.
+
+
+
+
+
+
+
+
+
diff --git a/docs/guides/audit-developer-machine/index.html b/docs/guides/audit-developer-machine/index.html
new file mode 100644
index 0000000..1b909ec
--- /dev/null
+++ b/docs/guides/audit-developer-machine/index.html
@@ -0,0 +1,173 @@
+
+
+
+
+
+How to check whether your developer machine is compromised (macOS and Linux)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Skip to content
+
+
How to check whether your developer machine is compromised
+
By Isaac Bell · Updated · Applies to am-i-hacked 2.0.1
+
+
Run npx am-i-hacked --system. It is a read-only audit that needs no root or sudo and makes no network calls. It checks login persistence (launchd on macOS, systemd user units and autostart on Linux) and the code signatures of what they launch, the crontab, shell startup files, AI coding tool config, and running processes. Pair it with npx am-i-being-recorded for screen-capture capability. Neither is antivirus: a clean result means no warning signs were found.
+
+
What the system scan checks
+
+
Area
What it looks for
+
+
Login persistence
launchd agents and daemons on macOS; systemd user units and XDG autostart on Linux; the user crontab. The scripts those entries launch are read for clipboard, keystroke or screen capture and exfiltration endpoints.
+
Code signatures (macOS)
A vendor-labelled login item signed by a Team ID the vendor does not use, or unsigned (HIGH); a signature that fails verification; unsigned programs in user-writable places
+
Shell startup files
Remote scripts piped to a shell, decoded payloads, DYLD_INSERT_LIBRARIES or LD_PRELOAD, TLS checks disabled, a forced NODE_OPTIONS --require, sudo or ssh replaced by an alias, a redirected AI API base URL, a proxy or extra certificate authority
+
AI coding tool config
User-level and managed settings for Claude Code, Codex, Cursor, Gemini CLI, OpenCode and Kilo Code: permission bypass, redirected API URLs, plain-text keys, MCP servers that run unpinned code, and hooks that run from writable places or observe your prompts
+
Running processes
Interpreters running capture scripts or scripts from staging areas such as Downloads, caches and /tmp
+
Dark corners (next release)
Folders where tooling installs code outside any project: virtualenvs, pip and uv caches, pyenv, pipx, the npx cache, the pnpm store, cargo, bun, deno, go and gem bin folders
+
+
+
+
Run it
+
npx am-i-hacked --system # the folder you are in, plus this machine
+npx am-i-hacked --system --verbose # also list every login item with its signer
+npx am-i-being-recorded # browser extensions that can capture the screen
+
The system scan needs bash 3.2+ and jq; it does not need ripgrep. It reads shell startup files and AI-tool config, which can hold secrets; it never prints secret values.
+
+
Reading the results
+
+
HIGH and MEDIUM findings exit 1. INFO lines are context.
+
A finding you have reviewed and accept goes in ~/.config/am-i-hacked/host-allow.txt as <finding id> | <reason>. Allowed findings are listed on every run, never hidden.
Do not run the suspect script to see what it does.
+
Preserve evidence first: copy the plist or unit file and the program it runs, and record SHA-256 hashes and modification times.
+
Only then stop and remove the item.
+
If capture was involved, treat everything copied or typed since the item appeared as exposed. Rotate secrets from a different, clean device.
+
+
+
Limits
+
It looks for warning signs; it is not antivirus and does not look up known malware. System-wide Linux units and /etc/cron.* are not covered yet. A clean result does not prove the machine is safe.
Check a cloned or downloaded repository for malicious code without opening, installing or running it: contain it, scan it with am-i-hacked, read the flagged files as text, and only then decide.
How to check code written by an AI coding assistant or agent (Claude Code, Cursor, GitHub Copilot, Codex and others) for malicious or insecure patterns before you run it, using am-i-hacked and secure-semgrep.
A .vscode/tasks.json task with runOn set to folderOpen runs a command as soon as you open a folder. How the attack works, how to spot it, and how to scan for it with am-i-hacked before opening a repository.
npm audit, OSV-Scanner and Snyk match dependencies against published advisories. An attack committed into a repository, or one not yet reported, is invisible to them. How to add indicator-based checks with am-i-hacked to a dev script, a git pull and CI.
A third-party agent skill is untrusted text and its installer is untrusted code. How to fetch a skill as data, pin it to a commit, scan it, read it and record where it came from, without running the installer. Uses the secure-skill-pull skill and am-i-hacked.
A read-only audit of a macOS or Linux developer machine with am-i-hacked --system: login persistence and code signatures, crontab, shell startup files, AI coding tool config, running processes and the folders tooling installs code into.
How to decide whether a macOS login item or "Background Items Added" entry is legitimate: map the name to its launchd plist, check the program's code signature and Team ID against the vendor, read script payloads without running them, and preserve evidence.
macOS says "Brave Browser is recording your screen" but not which tab or extension. am-i-being-recorded reads Chromium-family browser profiles and names the extensions that can capture the display or a tab.
A checklist for server-side request forgery (SSRF): allow only http and https on ports 80 and 443, resolve the host and reject every non-public address, follow redirects by hand, cap size and time, and connect to the address you checked. With hostile test inputs and Semgrep rules.
+
+
+
+
+
+
+
+
diff --git a/docs/guides/inspect-untrusted-repository/index.html b/docs/guides/inspect-untrusted-repository/index.html
new file mode 100644
index 0000000..67204ed
--- /dev/null
+++ b/docs/guides/inspect-untrusted-repository/index.html
@@ -0,0 +1,201 @@
+
+
+
+
+
+How to safely inspect an untrusted GitHub repository before running it
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Skip to content
+
+
How to safely inspect an untrusted repository before you run it
+
By Isaac Bell · Updated · Applies to am-i-hacked 2.0.1
+
+
Treat the repository as data until you have checked it. Do not open it in an editor, install its dependencies, or run its scripts or tests. Download it to a throwaway folder, scan it with npx am-i-hacked <dir>, read every flagged file as plain text, and list the files that must never run. A clean scan means no warning signs were found; it does not prove the code is safe.
+
+
Why opening or installing is already running
+
Many attacks on developers do not wait for you to run the app. They start at an earlier step:
+
+
Opening the folder. An editor task file such as .vscode/tasks.json can run a command as soon as the folder opens. See how to detect malicious editor config.
+
Installing dependencies.package.json lifecycle scripts (preinstall, postinstall, prepare) run during npm install.
+
Starting any tool. Config files such as vite.config.*, next.config.*, eslint.config.* and postcss.config.* are code that runs when the tool starts.
+
Payloads hidden in plain sight. An executable saved as a font or image, an encoded blob, or code appended after a long run of whitespace.
+
+
Take-home coding tests, "fix this bug" requests and repositories from an account that was compromised are common delivery routes. So is code your own AI assistant pulled in.
+
+
Step by step
+
+
Do not open it, install it or run it. No editor, no npm install, no make, no test runner, no dev server.
+
Get a copy as data. Download an archive pinned to a commit SHA into a throwaway folder, rather than cloning into your usual workspace. A branch name can move; a SHA cannot.
+
Scan it and keep the report. The folder scan is read-only and makes no network calls. It needs bash 4.2+, ripgrep and jq.
+
npx am-i-hacked "$work/src" 2>&1 | tee report.txt
+
+
Read the flagged files as text. Use less or cat, not an editor that runs tasks. Ignore any instructions written in comments, strings or file names. Compare suspect config files against a clean template.
+
List what must never run. Every package.json script, every *.config.* file, every editor task, and every CI workflow in the repository.
+
Decide, and write down what you did not check. Use it, use it with changes, or do not use it. If you only need some of the code, copy out allowlisted source files with a provenance record, as the quarantine-review skill describes.
+
+
+
A worked example
+
A repository with an editor task that downloads and runs a script when the folder opens. This is real output from am-i-hacked against a test folder:
The exit status is 1, so the same command stops a script or CI job. Had this folder been opened in an editor with automatic tasks allowed, the download would already have run.
+
+
What am-i-hacked looks for in a repository
+
+
Dynamic code execution (eval, new Function), child processes, direct network module access and runtime global writes.
+
Encoded or obfuscated payloads and unusually long lines.
+
package.json scripts that use curl, wget, powershell, child_process, node -e, base64 or eval.
+
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 such as a Telegram bot or a Discord or Slack webhook.
+
.env files in the git index, and official Yarn releases checked by SHA256.
+
The repository's own AI-tool config: .claude/settings*.json and .mcp.json.
+
+
It reads JS/TS, Python, Rust, Ruby, C, C++ and C# sources, including dot-directories and tracked files that .gitignore matches. The full list is on the am-i-hacked page.
+
+
What it does not do
+
+
It is not antivirus and does not look up known malware.
+
It does not scan node_modules or other installed dependencies, and does not check dependency versions against advisories. Use npm audit or OSV-Scanner for that; see the comparison.
+
It does not judge plain-language instructions aimed at an AI agent. For skills and prompts, follow how to vet an agent skill.
+
A clean result means no warning signs were found, not that the code is safe.
+
+
+
False positives
+
Ordinary code trips some checks: eval in a template engine, a child process in a migration tool, base64 in export code. A real indicator lines up with an execution path, an auto-run setting or a config file that has no reason to exist. When you have checked a line and it is fine, mark it with a reason; it stays listed as reviewed on every run:
+
const decoded = atob(header); // am-i-hacked-ignore: decodes a request header, not a payload
+
+
For repositories you already work in
+
safe-pull, installed with am-i-hacked, fetches incoming commits and inspects them before anything is written to your working tree, then fast-forwards. It flags a force-pushed upstream, an author and committer mismatch, editor auto-run tasks, download-and-run editor commands, disguised payloads and committed .env files. Run safe-pull --dry-run to inspect without merging.
+
+
+
+
+
+
+
+
+
diff --git a/docs/guides/macos-login-items/index.html b/docs/guides/macos-login-items/index.html
new file mode 100644
index 0000000..5d792c2
--- /dev/null
+++ b/docs/guides/macos-login-items/index.html
@@ -0,0 +1,170 @@
+
+
+
+
+
+Is this macOS login item or background item malware? How to check
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Skip to content
+
+
Is this macOS login item or background item malware?
+
By Isaac Bell · Updated · Applies to am-i-hacked 2.0.1
+
+
The name in System Settings is the code signer, not the plist. Find the launchd plist behind it, read the program it runs, and verify that program's code signature and Team ID against the vendor's own apps on your machine. A valid vendor signature on a vendor-labelled entry closes the case. Anything unsigned, ad-hoc signed, failing verification or signed by the wrong team stays open. npx am-i-hacked --system --verbose does these checks for every login item at once.
+
+
"Background Items Added" is not an indicator by itself
+
macOS shows that notification whenever an item is registered. Vendor updaters re-register after every update. System Settings > General > Login Items & Extensions groups entries by the signing developer's name, and shows "Item from unidentified developer" when there is no valid Developer ID.
+
+
Check one item by hand
+
+
Find the plist.
+
ls -la ~/Library/LaunchAgents /Library/LaunchAgents /Library/LaunchDaemons
+ Match on the vendor prefix (com.google.*) or a recent modification time.
+
Read it.plutil -p <plist>. Note Label, Program or ProgramArguments, RunAtLoad, KeepAlive and EnvironmentVariables. Red flags without any signature check: a com.apple.* label outside /System, DYLD_INSERT_LIBRARIES or NODE_OPTIONS in the environment, or a program that no longer exists.
+
Verify the signature of a compiled program:
+
codesign -dv --verbose=2 <program>
+codesign --verify --deep --strict <program>
+codesign -dv /Applications/<Vendor>.app 2>&1 | grep TeamIdentifier # the vendor's real Team ID
+
+
Read scripts without running them. If the program is /bin/sh or node, the payload is the script. Look for clipboard or screen capture (pbpaste, screencapture) paired with an exfiltration endpoint (api.telegram.org, Discord or Slack webhooks).
+
+
+
Verdicts
+
+
Evidence
Verdict
+
+
Vendor label, valid signature, vendor Team ID
Legitimate. Close.
+
Vendor label, another Team ID or unsigned
HIGH: impersonation. Preserve and escalate.
+
Signature fails verification
MEDIUM: modified after signing.
+
Unsigned or ad-hoc, in Application Support, Caches, Downloads, /tmp or /Users/Shared
MEDIUM: confirm you installed it.
+
Unsigned or ad-hoc elsewhere, such as Homebrew services
INFO: usually developer tooling.
+
Capture paired with exfiltration in the script
HIGH, whatever the signature.
+
+
+
+
Automate it
+
npx am-i-hacked --system --verbose
+
The verbose inventory lists every login item with its signer and Team ID, using the same severities as the table above. Expected Team IDs come from a table of vendors read from genuine apps, then from installed apps with the same bundle-id prefix. The login-item-triage skill walks an agent through the manual method, including which commands show an OS prompt.
+
+
Before you remove anything
+
Copy the plist and the program's folder, record their SHA-256 hashes and modification times, then stop the item with launchctl bootout. If capture was confirmed, rotate secrets from a clean device.
+
+
+
+
+
+
+
+
+
diff --git a/docs/guides/malicious-editor-config/index.html b/docs/guides/malicious-editor-config/index.html
new file mode 100644
index 0000000..50e06d5
--- /dev/null
+++ b/docs/guides/malicious-editor-config/index.html
@@ -0,0 +1,180 @@
+
+
+
+
+
+How to detect malicious VS Code tasks that run when a folder opens
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Skip to content
+
+
How to detect malicious VS Code tasks that run when a folder opens
+
By Isaac Bell · Updated · Applies to am-i-hacked 2.0.1
+
+
VS Code, and editors built on it such as Cursor, can run a task automatically when a folder opens if .vscode/tasks.json sets "runOn": "folderOpen". A malicious repository uses this to run a download-and-execute command the moment you look at it. Before opening an unfamiliar folder, scan it with npx am-i-hacked <dir>, which flags editor auto-run tasks and download-and-run commands in editor config, and keep Workspace Trust turned on.
+
+
How the attack works
+
A task file in the repository defines a shell command and asks the editor to run it on folder open:
Real examples hide the command better: a long line pushed off screen with whitespace, a script saved under a font or image name, or a task that only runs a harmless-looking node file which does the work. The repository is often presented as a take-home coding test or a bug to fix, so that you open it.
+
+
How to spot it
+
+
.vscode/tasks.json with "runOn": "folderOpen".
+
.vscode/settings.json that allows automatic tasks (task.allowAutomaticTasks) or points an extension setting at an executable inside the repository.
+
Any curl, wget, powershell, base64 or | sh in editor config.
+
A task that runs a file whose name does not match its contents, such as a .woff2 that is really a script.
+
+
+
Scan before you open
+
npx am-i-hacked path/to/repo
+
am-i-hacked reports an editor auto-run task and a download-and-run command in editor config as separate findings, with file and line, and exits 1. It also flags executable payloads disguised as asset files. Real output from a folder holding the task above:
For editor settings that point at an executable, secure-semgrep's AI rule set includes an ide-settings-executable-path check: npx secure-semgrep ..
+
+
Harden the editor
+
+
Keep Workspace Trust on, and open unfamiliar folders in Restricted Mode. Tasks do not run in Restricted Mode.
+
Set task.allowAutomaticTasks to off in your user settings, so no folder can turn automatic tasks back on.
+
Read .vscode/, .idea/ and other editor folders with cat or less before you open the project.
+
+
+
If you already opened it
+
Assume the command ran. Preserve the folder, check the machine with npx am-i-hacked --system for login items, shell startup changes and running processes it may have left behind, and rotate credentials from a different, clean device. See how to check a developer machine.
+
+
+
+
+
+
+
+
+
diff --git a/docs/guides/prevent-ssrf/index.html b/docs/guides/prevent-ssrf/index.html
new file mode 100644
index 0000000..d88ee61
--- /dev/null
+++ b/docs/guides/prevent-ssrf/index.html
@@ -0,0 +1,164 @@
+
+
+
+
+
+How to prevent SSRF when your server fetches a user-supplied URL
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Skip to content
+
+
If your server fetches a URL that someone else supplied, check the resolved IP address, not just the hostname, before every request, including every redirect. Allow only http and https on ports 80 and 443, reject loopback, private, link-local (including the cloud metadata address 169.254.169.254), carrier-grade NAT, multicast and reserved ranges, follow redirects by hand, and cap bytes and time. npx secure-semgrep -L ssrf . finds fetches that skip the check.
+
+
What SSRF is
+
Server-side request forgery happens when your server fetches an address that someone outside your organization controls. They point it at a place only your server can reach: localhost, your internal network, or the cloud metadata address that hands out credentials. Link previews, webhooks, "import from URL" boxes and tools that look up a domain a visitor typed are the usual places it hides.
+
+
Checklist
+
+
Scheme and port. Only http and https, only ports 80 and 443 unless you pin another. Reject file://, gopher:// and every other scheme.
+
Resolve the host yourself and check every address it resolves to. Reject loopback (127.0.0.0/8, ::1), private (10/8, 172.16/12, 192.168/16, fc00::/7), link-local (169.254/16, fe80::/10), carrier-grade NAT (100.64/10), unspecified, broadcast, multicast and reserved ranges, and IPv4 addresses wrapped in IPv6 (mapped, NAT64, 6to4, Teredo). Never classify the raw host string: 0x7f000001, 2130706433 and 127.1 all reach loopback.
+
Follow redirects by hand. Turn off automatic redirects, re-run the full check on each Location, and cap hops at about 5.
+
Cap bytes and time. Connect timeout, total timeout and a maximum response size.
+
Do not forward credentials or cookies across a redirect to another host.
+
Parse once. Use the same parsed host for the check and the connection, and reject URLs with credentials before the at sign.
+
Guard against DNS rebinding in high-risk code: resolve once, check that address, and connect to it directly while sending the original host name for TLS and virtual hosting.
+
Validate stored URLs twice, on save and again right before each send. Prefer an allowlist where the product allows it.
Also test a public-looking hostname that resolves to a private address, and a public URL that redirects to 169.254.169.254. Stub the resolver and the HTTP transport rather than relying on real DNS. It must still accept https://example.com/.
+
+
Find unchecked fetches
+
npx secure-semgrep -L ssrf .
+
The bundled SSRF rules cover JavaScript and TypeScript, Python and Rust (fetch, axios, got, requests, httpx, urllib, reqwest and similar). They flag a request whose URL is not a fixed string and does not pass through a guard function, a client that follows redirects automatically for such a URL, and TLS verification turned off (rejectUnauthorized: false, verify=False, danger_accept_invalid_certs(true)). Every rule is a warning: a non-literal URL from your own fixed config is fine.
+
+
Reference code
+
The ssrf-safe-fetch skill has guard implementations in Python (requests), TypeScript (Node fetch) and a Rust (reqwest) sketch, with the rebinding caveats for each. Install it for your coding agent:
How to catch a supply-chain attack that npm audit misses
+
By Isaac Bell · Updated · Applies to am-i-hacked 2.0.1
+
+
Advisory scanners such as npm audit, OSV-Scanner and Snyk compare your dependency versions with known, published vulnerabilities. They cannot see an attack committed into the repository itself, or one nobody has reported yet. Add an indicator-based check that reads the code: run npx am-i-hacked before the dev server and in CI, and pull with safe-pull so incoming commits are inspected before they reach your working tree. Run both kinds of check.
+
+
Two kinds of check
+
+
Advisory scanners
Indicator scanner (am-i-hacked)
+
+
Question asked
Is any dependency version on a list of known-bad versions?
Does the code in this tree look like an attack?
+
Finds
Reported CVEs and reported malicious package versions
Anything not yet reported; anything committed into your repository
Known vulnerabilities in dependency versions; installed packages in node_modules
+
+
+
+
Where to put the check
+
Before the dev server
+
{ "scripts": { "dev": "am-i-hacked && next dev" } }
+
A finding exits 1, so the dev server does not start until you have looked.
+
+
When pulling
+
safe-pull fetches, inspects the incoming commits before anything is written to disk, then fast-forwards. It flags a rewritten (force-pushed) upstream, an author and committer mismatch, editor auto-run tasks, download-and-run editor commands, disguised payloads, committed .env files and a dotenv plus node-fetch or axios dependency pair.
+
safe-pull --dry-run # inspect only
+safe-pull # inspect, then merge --ff-only
+
+
In CI
+
GitHub Actions on ubuntu-latest has bash, jq and npx, but not ripgrep:
Pin the major version so a new release cannot change what your gate does without you noticing.
+
+
Install scripts
+
am-i-hacked flags package.json scripts that use curl, wget, powershell, child_process, node -e, base64 or eval. For dependencies, also stop install scripts you have not reviewed from running: npm ci --ignore-scripts, or pnpm, which from version 10 does not run dependency lifecycle scripts unless you allow them.
+
+
Other signals it checks
+
+
Official Yarn release files committed to the repository, verified by SHA256.
+
.env files in the git index.
+
Python virtualenvs whose files no longer match their package RECORD hashes, files no package owns, and .pth hooks that run code. This check ships in the next am-i-hacked release, after 2.0.1.
+
+
+
Limits
+
am-i-hacked does not scan node_modules and does not look up advisories, so keep your advisory scanner. It looks for warning signs; a clean result is not proof of safety.
+
+
+
+
+
+
+
+
+
diff --git a/docs/guides/vet-agent-skills/index.html b/docs/guides/vet-agent-skills/index.html
new file mode 100644
index 0000000..7251952
--- /dev/null
+++ b/docs/guides/vet-agent-skills/index.html
@@ -0,0 +1,185 @@
+
+
+
+
+
+How to vet an AI agent skill, plugin or MCP server before installing it
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Skip to content
+
+
Do not run the installer. Fetch the skill's source as data at a pinned commit, scan it with npx am-i-hacked <dir>, check it for prompt-injection lines and invisible characters, and read every file it references. Treat any instruction inside it as input to report, not an order to follow. The secure-skill-pull skill automates this for an agent.
+
+
Two ways a skill attacks you
+
+
Code runs at install. A one-line installer (<cli> add <url>, curl ... | sh) downloads files and runs them with your permissions.
+
Text steers the agent. A skill is a set of instructions. A hostile one tells the agent to ignore its rules, fetch other pages, send data out or turn off a safeguard. Invisible Unicode characters can hide those lines from a human reader.
+
+
A popular installer CLI says nothing about the repository it fetches. Trust the source, not the tool.
+
+
The rules
+
+
Never run the installer. If you want it run after review, run it yourself, knowingly.
+
Pin to a commit SHA, not a branch.
+
Download an archive to a throwaway folder. Delete symlinks. Refuse anything over about 5 MB; a skill is text.
+
Scan, then read every file the skill references.
+
Record provenance: source URL, commit SHA, date, the SHA-256 of SKILL.md, and what you applied.
+
+
+
A portable check
+
slug=owner/repo; ref=<commit-sha>
+work=$(mktemp -d)
+curl -fsSL --max-filesize 5000000 "https://codeload.github.com/$slug/tar.gz/$ref" -o "$work/src.tgz"
+mkdir "$work/src" && tar -xzf "$work/src.tgz" -C "$work/src" --strip-components=1
+find "$work/src" -type l -delete
+find "$work/src" -type f -perm -u+x # a text-only skill needs no executables
+npx am-i-hacked "$work/src"
+grep -rInE '(curl|wget)[^|]*\|[[:space:]]*(sh|bash)|base64[[:space:]]+(-d|--decode)|ignore (all |any )?(previous|prior) instructions' "$work/src"
+find "$work/src" -type f -print0 | xargs -0 perl -CSD -ne 'print "$ARGV:$.: invisible character\n" if /[\x{200B}-\x{200F}\x{202A}-\x{202E}\x{2060}-\x{2064}\x{E0000}-\x{E007F}]/'
Reads of .env, .ssh, credential files, environment dumps
Data theft
+
Requests to send data to a URL, or to fetch and follow other URLs
Exfiltration, or a chain to unvetted text
+
Lines telling the agent to ignore rules, skip approval or turn off checks
Prompt injection
+
Settings, hooks or editor task files
Run when the tool starts or the folder opens
+
Invisible characters
Lines a human reviewer cannot see
+
+
+
am-i-hacked looks for code indicators; it does not judge plain-language instructions. The grep and invisible-character steps, and reading the files, cover that gap. secure-semgrep's AI rules add checks for prompt injection, exfiltration, sensitive-file reads and base64 payloads in SKILL.md files, and for poisoned or typosquatted MCP tool names.
+
+
Publishing your own skills
+
The other direction matters too: a skill you publish can leak private paths, names, secrets or someone else's text. The create-skill and skill-publish-review skills cover the checks and the independent review before a skill goes public.
By Isaac Bell · Updated · Applies to am-i-being-recorded 1.0.0
+
+
macOS attributes a screen recording to the application, never to the tab or extension behind it. Run npx am-i-being-recorded: it reads Chromium-family browser profiles (Chrome, Brave, Edge, Chromium, Vivaldi) and names each extension with display-capture, tab-capture or debugger permissions, with its ID, version and profile. Disable that extension at chrome://extensions and restart the browser.
+
+
Run it
+
npx am-i-being-recorded
+
It needs jq (brew install jq or apt-get install jq). It reads files on your machine and makes no network calls.
+
+
What the answer looks like
+
CRITICAL Example Screen Recorder (aaaabbbbccccddddeeeeffffgggghhhh) v1.2.3
+ Google/Chrome/Default - Can capture the entire display (screen recording)
+ HIGH Example Screen Recorder (aaaabbbbccccddddeeeeffffgggghhhh) v1.2.3
+ Google/Chrome/Default - Capture permission plus an offscreen document can outlive the visible tab
+
A "stuck" recording indicator is usually an extension holding a display stream from an offscreen document. Disable or remove it in chrome://extensions (or brave://extensions), then restart the browser so the indicator clears.
+
+
Permissions it flags
+
+
Permission
Severity
Why
+
+
desktopCapture
CRITICAL
Can record the entire display
+
tabCapture
HIGH
Can record the active tab's audio and video
+
debugger
HIGH
Full tab control over the DevTools protocol
+
nativeMessaging
MEDIUM
Can launch a native helper process
+
userScripts
MEDIUM
Can inject scripts into pages
+
management
LOW
Can enable or disable other extensions
+
+
+
Two combinations escalate: display capture with access to every site, and any capture permission with an offscreen document.
+
+
Other things that can capture you
+
On macOS it also prints context, not findings: whether the screen-sharing daemons are running, and which apps hold camera, microphone and screen-recording permission, each with its code signer and Team ID. An unsigned app with a capture permission is worth a look. Reading the screen-recording permissions needs root or Full Disk Access; the tool says so rather than guessing. On Linux it shows which process holds a camera device.
+
+
Limits
+
+
It reports capability, not proof of an active stream. A recorder you installed on purpose is flagged too.
+
Safari and Firefox extensions, standalone recorder apps, and a web page's own screen-share prompt are out of scope.
+
It is triage that names a suspect, not a malware scanner.
+
+
Use --strict to make any finding exit 1, and --min-severity HIGH to show only the loud ones.
+
+
+
+
+
+
+
+
+
diff --git a/docs/index.html b/docs/index.html
index 89fd88c..1f2fdfc 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -3,224 +3,144 @@
-secure-devtools: security tools for the code you run
-
+secure-devtools: open-source security tools for the code you run
+
+
+
+
-
-
+
+
+
-
-
-
+
+
-
+Skip to content
Shell scripts that check a project before you run it, and the machine you run it on. They run on your computer, with no signup, account or API key.
+
secure-devtools is a free, open-source security toolkit for developers who need to check code before running it. Its command-line tools check repositories, AI-generated projects and agent skills for malicious or insecure code, and check the machine you run them on.
+
They look for editor tasks that run when a folder opens, malicious install scripts, obfuscated payloads, persistence and screen-capture software, risky AI coding tool config, insecure AI-agent code and SSRF. They are plain shell scripts that run locally on macOS and Linux, with no signup, account or API key, and exit non-zero on findings so they drop into a dev script or CI.
npx am-i-hacked
@@ -229,7 +149,8 @@
Security tools for the code you run
Scans the folder you are in. Add --system to check this machine too.
Looks for signs of malicious code in a project before you open, install or run it. With --system, it also checks this machine for persistence, capture tools and risky AI-tool config.
Runs Semgrep with security rules for AI-agent code, shell scripts and server-side requests, plus Semgrep's own rule sets for common languages. Needs semgrep installed.
Runs Semgrep with security rules for AI-agent code, MCP servers, agent hooks, shell scripts and server-side requests, plus Semgrep's own rule sets for common languages. Needs semgrep installed.
Shell startup files that pipe remote scripts, inject libraries, hijack sudo or ssh, or redirect AI API traffic
+
AI coding tool config for Claude Code, Codex, Cursor, Gemini CLI, OpenCode and Kilo Code: permission bypass, plain-text keys, unpinned MCP servers, hooks
+
Running processes that run capture scripts or scripts from staging folders
The folder scan reads a project before you open, install or run anything: dynamic code execution, obfuscated payloads, editor tasks that run on folder open, payloads disguised as asset files, clipboard capture paired with an exfiltration endpoint, and .env files in the git index. --system adds the machine: login persistence and code signatures, crontab, shell startup files, AI-tool config, and running processes. It exits 1 on findings, so it drops into a dev script or CI.
+
The folder scan reads a project before you open, install or run anything: dynamic code execution, obfuscated payloads, editor tasks that run on folder open, payloads disguised as asset files, clipboard capture paired with an exfiltration endpoint, and .env files in the git index. --system adds the machine: login persistence and code signatures, crontab, shell startup files, AI-tool config, and running processes. It exits 1 on findings, so it drops into a dev script or CI.
npx am-i-hacked # scan the folder you are in
@@ -274,53 +258,61 @@
am-i-hacked
-
It reports warning signs, not proof of safety: a clean result does not prove the code or machine is safe. Read the am-i-hacked README for the flags and suppression syntax.
+
It reports warning signs, not proof of safety: a clean result does not prove the code or machine is safe. The am-i-hacked reference has the full list of checks, flags, exit codes and suppression syntax.
Agent skills
-
Install all of them with npx skills add IsaacBell/secure-devtools -g, or one with --skill <name>.
-
-
+
Instructions an AI coding agent loads when the task matches. Install all of them with npx skills add IsaacBell/secure-devtools -g, or one with --skill <name>. What each one does.
+
-
quarantine-review — inspect an untrusted repository without running any of it.
-
secure-skill-pull — vet a skill or plugin from a URL without running its installer.
-
create-skill — write, check and publish an agent skill.