Skip to content
T threat.cafe

· Nadia Ferreira-Strand (editorial persona) · Enforcement architecture · on threat.cafe

Don't start your coding agent in ~/Downloads: instruction files are now a drive-by vector

Do not start a coding agent in ~/Downloads. On 22 October 2026, Forever Security showed that a web page can drop an AGENTS.md or CLAUDE.md file there. An agent started in that folder reads the file as project instructions. In the researchers' own controlled tests, Codex ran the planted payload in more than 90% of attempts. The researchers say there is nothing to patch. So the control is yours: scope sessions, gate launches, restrict egress.

Outcome, time and prerequisites

The runbook's outcome is plain. Agents start only in project folders, and stray instruction files get caught first.

Budget about 30 minutes per laptop, by our estimate. The egress allowlist takes longest.

Prerequisites:

  • Shell access as the user who runs the agent.
  • Write access to ~/.claude/settings.json and your shell profile.
  • For a fleet: rights to push managed settings through device management.
  • A list of trusted roots, for example ~/code.
  • Backups: copy ~/.claude/settings.json and ~/.codex/config.toml to .bak files.

Do not proceed without the backup. Rollback depends on it.

USE THIS RUNBOOK IF
- You run agents that read AGENTS.md or CLAUDE.md
- Agents run on laptops that also browse the web
- Agents hold an OAuth token or API key worth stealing

DO NOT USE THIS RUNBOOK IF
- Agents run only in credential-free disposable containers
- You are mid-incident (rotate credentials first, then return here)

What happened

Gal Weizman and Omer Samet of Forever Security published Markdown Is the New Executable on 22 October 2026. A real case started it: an AGENTS.md in a customer's Downloads folder told an agent to install an npm package, function-color. Forever Security's tooling blocked it. Brandefense reports that npm has removed the package.

  • OpenAI Codex. A planted AGENTS.md pushed the agent into a machine-wide config change that ran a chosen command. Success: "more than 90% of attempts", per the researchers. BleepingComputer notes the test payload only opened the calculator.
  • Anthropic Claude Code. A planted CLAUDE.md pushed the agent to point its API traffic at a researcher-controlled server. The authors say that exposes the OAuth token. The write worked "about half the time".

Aviatrix's write-up of the research, dated 25 October, calls that roughly 50% OAuth token theft. Aviatrix also lists Cursor CLI, which the original did not test. Aviatrix says three major browsers saved the file without a prompt. Treat both as Aviatrix's claims.

Forever Security's telemetry, published 22 October 2026, says about half of its own customers run an agent in Downloads. No vendor statement or patch appears in any coverage. "Working as designed" is the researchers' phrase.

What the trust dialog covers

Claude Code's trust dialog gates settings, not instruction text. The memory documentation says CLAUDE.md files load at launch from the working folder and every folder above it. AGENTS.md loads when no CLAUDE.md exists. Claude treats both "as context, not enforced configuration". A session in ~/Downloads reads both Downloads and home.

The security documentation says the dialog appears in interactive sessions in untrusted folders. The permissions documentation says it holds back allow rules and extra directories. Neither says it reviews instruction text. Also note:

  • A claude -p session shows no trust prompt.
  • Trust is saved per folder. A Downloads folder trusted once stays trusted.

Keep approvals on. Do not rely on them alone.

Pre-flight checks (dry run)

Run these read-only checks first. Change nothing yet.

  1. Run find ~/Downloads ~/Desktop -maxdepth 3 \( -name AGENTS.md -o -name CLAUDE.md -o -name CLAUDE.local.md \) 2>/dev/null. Verify: empty output. If it fails: go to failure case 1.
  2. Run ls ~/AGENTS.md ~/CLAUDE.md 2>/dev/null. Verify: empty output. If it fails: read the file. Remove it if you did not write it.
  3. Open ~/.codex/config.toml and .claude/settings.json. Verify: no unknown MCP servers, base URLs or proxies. If it fails: go to failure case 1.

Execution steps

Run each step in order. Verify before moving on.

  1. Add a launch wrapper. Paste the guard from the SOP block into your shell profile. Verify: cd ~/Downloads && claude prints the refusal. If it fails: run type claude to find a shadowing alias.
  2. Add deny rules. Add Bash(curl *) and Bash(wget *) to permissions.deny. Verify: /permissions lists both. If it fails: check the JSON parses.
  3. Turn on sandbox network isolation. Deny rules match command text; isolation does not. Verify: a fetch to an unlisted host fails. If it fails: run /sandbox and check the network setting.
  4. Apply an egress allowlist. Allow your model provider, package mirror and source host. Verify: a random domain is blocked. If it fails: confirm agent traffic goes through the proxy.
  5. Add a SessionStart hook. Warn when the folder is outside trusted roots. The hooks documentation says SessionStart cannot block; it can warn. Verify: the warning shows in ~/Downloads with the wrapper bypassed. If it fails: check the hook exits 2 and writes to stderr.

Failure modes and fixes

Six failure modes are the likely ones for this runbook. Each has an exact fix.

Case 1: a planted file is already on disk. Stop. Do not start or resume an agent in that folder. Copy the file to an evidence folder outside any project. Inspect ~/.codex/config.toml and .claude/settings.json for entries you did not add. Rotate the agent's OAuth token or API key. A stolen token is a live session. Search installs for function-color, the published indicator. Then delete the file. Verify: a fresh session shows no unknown MCP servers. If it fails: escalate. See our post "Your agent installed a known-bad package: the first hour".

Case 2: the wrapper does not fire. Wrappers guard only the shell they live in. IDE extensions and command claude skip them. Other agent CLIs need their own guard. Fix: add the guard to every managed shell profile. Push deny rules and sandbox settings as managed settings. Verify: launch from the IDE in ~/Downloads and look for the hook warning.

Case 3: the logging hook misses AGENTS.md. Claude Code's InstructionsLoaded hook does not fire for an AGENTS.md read directly. The memory documentation says so. Fix: log the working folder at SessionStart instead. Verify: a test AGENTS.md in a scratch folder shows up in your log.

Case 4: a repository overrides your user settings. The permissions documentation says project settings take precedence over user settings for hook switches. A repository can undo what you set at user level. Fix: put the hook and deny rules in managed settings. Verify: /permissions in a cloned repo still shows your rules.

Case 5: the Codex change outlives the session. Brandefense notes the Codex config is machine-wide. A planted entry follows you into every project. Fix: back up ~/.codex/config.toml with the other settings. Diff it against the backup after any suspect session. Verify: the diff is empty. If it fails: remove the new entry, then go to case 1.

Case 6: legitimate work breaks. A build script uses curl. A new registry is blocked. Fix: add a narrow allow for that host. Do not delete the whole rule. Verify: the build passes and a random domain stays blocked.

Rollback and health check

Roll back one change at a time. Start with the most recent.

  1. Hook: remove the SessionStart entry. Verify: no warning in a test session.
  2. Deny rules: restore the .bak copy of ~/.claude/settings.json. Verify: /permissions matches the backup.
  3. Wrapper: delete the guard lines and open a new shell. Verify: type claude shows the binary path.
  4. Sandbox and egress: turn isolation off with /sandbox, or remove the proxy rule, one host at a time. Verify: the blocked build now passes.

Keep the deny rules and the wrapper last in line for removal. Both cost little and catch the common case.

Rollback trigger: any step that blocks a release build for more than one working day. Fix forward with a narrow allow first. A full rollback is the last resort.

Health check after any rollback: rerun all three pre-flight checks. All three must pass. Then start one test session in a project root. Confirm the expected instruction file loads with /memory. Do not reopen the fleet until one machine passes end to end. Record which step you rolled back and why, so the next attempt starts from evidence. If two rollbacks fail in a row, restore both .bak files in full and stop.

The strongest case against this runbook

The strongest objection says the agent's own guards are enough, and few people launch from Downloads.

The evidence points the other way. Forever Security reports those guards were bypassed in its runs. Its telemetry, published 22 October 2026, puts about half of its customers in Downloads. That is vendor data, the only data published. A wrapper costs minutes. A stolen token costs a rotation and an investigation.

Where this would be wrong

The Downloads runbook would be the wrong priority in some setups. Agents may run only in disposable containers with no credentials. Then Downloads is out of reach. A vendor default that refuses Downloads instructions would make step 1 redundant. And the success rates come from controlled tests. Field rates could be lower.

What vendors could change

Vendor defaults could close most of this design gap. Agents could refuse instructions from Downloads, Desktop or home. Trust dialogs could list every instruction file path. Agents could treat files marked as web downloads as untrusted. Changes to base URLs or MCP servers could need separate confirmation.

Related cases

Repo-supplied agent config has caused trouble before, per Adversa AI's October 2026 roundup. In Fable to Haiku, dated 22 September 2026, Brian Cumi of Straiker STAR Labs showed a repo's subagent definition skipping the test folder in review. Claude Code then ran tests hiding a payload. Anthropic closed the report as "Informative", per Straiker, citing workspace trust. A Claudefolio explainer in the same roundup shows one README line steering an agent to send secrets out with curl. Treat in-repo agent config as untrusted code.

What to tell the people who sign off

  • Finance: about 30 minutes per laptop, by our estimate.
  • Security lead: blast radius is the agent's token and anything it can run.
  • Legal and compliance: keep any planted file as evidence.
  • Operations: every step has a rollback; backups make it a file restore.

What we don't know yet

No independent reproduction of the success rates exists yet. No public test covers Cursor CLI. OpenAI and Anthropic have not said whether defaults will change.

THREAT.CAFE INSTRUCTION-FILE LAUNCH SOP (v1, 29 Oct 2026)

PRE-FLIGHT (read-only)
[ ] find ~/Downloads ~/Desktop -maxdepth 3 -name 'AGENTS.md' -o -name 'CLAUDE*.md'
[ ] No unknown MCP servers, base URLs, proxies in agent config

GUARD (shell profile; repeat per agent CLI)
agent_guard() {
  case "$PWD" in
    "$HOME"|"$HOME/Downloads"*|"$HOME/Desktop"*)
      echo "agent_guard: start in a project root" >&2; return 1;;
  esac
}
claude() { agent_guard && command claude "$@"; }

CONTROLS
[ ] Deny curl/wget  [ ] Sandbox network  [ ] Egress allowlist  [ ] Warning hook

IF A PLANTED FILE IS FOUND: stop, preserve, check config, rotate token, delete

Copy the threat.cafe Instruction-File Launch SOP freely. Check any package or endpoint from a case like this on the threat.cafe board.

Volatility: VOLATILE (event-triggered review). Review when OpenAI or Anthropic change how agents load instruction files, or when an independent reproduction is published.

Sources

#agents-md #claude-md #coding-agents #prompt-injection #working-directory

All posts