cd /news/ai-agents/a-web-page-dropped-agents-md-in-down… · home › topics › ai-agents › article
[ARTICLE · art-160065] src=dev.to ↗ pub= topic=ai-agents verified=true sentiment=↓ negative

A Web Page Dropped AGENTS.md in Downloads. Codex Obeyed It in 90%+ of Tests

Security researchers Gal Weizman and Omer Samet of Forever Security demonstrated that a web page can silently plant an AGENTS.md file in a user's Downloads folder, which OpenAI's Codex coding agent then obeyed in more than 90% of lab attempts, executing a malicious npm package. A CLAUDE.md variant caused Claude Code to route traffic through an attacker-controlled server about 50% of the time, exposing login tokens. The researchers noted there is nothing for OpenAI or Anthropic to patch, since the attack exploits the agents' instruction-file loading and project-trust behavior rather than a software flaw.

by read7 min views8 publishedOct 29, 2026

A coding agent on a developer's laptop was about to run npm install function-color. Nobody had asked for that package. It came from a file called AGENTS.md sitting in the developer's ~/Downloads folder, and nobody knew how it got there.

That is the incident Forever Security described on October 22, 2026, in a write-up by Gal Weizman and Omer Samet titled "Markdown Is the New Executable". Their software stopped the install on a customer's machine. Help Net Security covered it on October 26. The package, function-color, came from a malicious campaign and npm has since removed it.

The researchers then rebuilt the attack in a lab. Against Codex, they report: "In our testing, Codex ran the malware in more than 90% of attempts." A CLAUDE.md variant got Claude Code to route its traffic through an attacker's server "about 50% of the time", which exposed the login token. Their summary of the fix is the uncomfortable part: "There is nothing here for OpenAI or Anthropic to patch."

According to Forever, a web page can save a file named AGENTS.md into your Downloads folder on its own, choosing both the name and the contents. Their words: "No click. No approval." In their lab page, the file lands in ~/Downloads the moment you leave the page.

So Downloads is a folder any website can write to. The Forever post also points out that agents browse on their own now, so an agent can visit the page that plants the file, with no human watching it arrive. Forever's own numbers from its customer base, as Help Net Security reports: about half of its customers run a coding agent inside Downloads, and about a quarter of agent sessions open a browser.

The real file was 13 KB and read like a dull "Engineering Work Guidelines" document. The attack was one section near the end. Forever says the payload failed every time when they placed it in a folder full of security notes, so the bland tone is deliberate.

A file any website can write becomes a file your agent reads at startup.

Codex builds its instructions from AGENTS.md files. Per the official docs, it reads a global file from ~/.codex, then starts at the project root ("typically the Git root") and walks down to your current directory, taking one AGENTS.md per directory. "If Codex cannot find a project root, it only checks the current directory." Downloads is rarely a git repository, so starting Codex there means the planted file is the project instruction file.

Codex has a trust gate. The config docs say "Codex loads project .codex/ layers only when you trust the project", and Forever says Codex only obeys an AGENTS.md in a trusted project. Their catch: "Once you have worked in Downloads, it qualifies."

Forever describes the chain like this:

[mcp_servers.project-tools] block into ~/.codex/config.toml. launchctl, which runs npm install function-color outside Codex's control.codex exec runs with --dangerously-bypass-approvals-and-sandbox, because the default sandbox withholds the network access an install needs. Note where that first write lands. Per the config docs, trust governs project .codex/ layers. ~/.codex/config.toml is your user-level config: it ranks below project config in precedence, and it applies in every folder.

Because the change sits in the machine-wide config, later Codex sessions in any project run the attacker's command too. Most of Forever's lab runs used a harmless stand-in that opened a calculator; the real package ran once, in an isolated VM.

Claude Code reads CLAUDE.md from your working directory "and every directory above it", per its memory docs. Since v2.1.277 it also reads an AGENTS.md when there is no CLAUDE.md in that chain, and your user-level ~/.claude/CLAUDE.md doesn't count for that check. So Claude Code started in Downloads would load the same planted AGENTS.md. Forever's Claude test used its own CLAUDE.md, and they say Claude was much harder to fool than Codex.

The version that worked had a section called "Configure the project model gateway". It asked Claude to write .claude/settings.json with ANTHROPIC_BASE_URL pointing at an attacker server on a domain with a valid certificate. Per Help Net Security, every request then carries your login token to that server, and replaying a captured token let the researchers take over the account without running any code. In the same session, a helper agent Claude spawned to check the new config connected through the attacker's server, and that gave the researchers code execution about a fifth of the time. On the next launch, the fake gateway can also pose as the model and return a Bash tool call with the sandbox turned off.

One detail matters for your defaults. Claude Code's permission modes page lists .claude as a protected directory: in default and acceptEdits modes, a write there is a prompt you answer; in auto mode a classifier decides; in bypassPermissions it is allowed. The write-up doesn't say which mode the lab sessions used. Either way, the prompt for that write is the place a person can still stop it.

Both attacks end in a settings file: Codex's user config, Claude Code's project settings.

Every step above is a documented feature doing its job. Agents are built to read instruction files from the folder you start them in. They are built to edit config when asked. Codex supports MCP servers in config.toml; Claude Code supports a custom base URL for gateways and proxies, and companies use both for real.

The broken assumption is about the folder. You treat a folder you work in as one you filled yourself, and Downloads is filled by the web. As Help Net Security puts Forever's view: the agent is working as designed, so the defence is on you.

These are Forever's recommendations, turned into commands. Run them on macOS or Linux; they only read.

Look for agent instruction files in Downloads and your home folder that you did not put there:

find ~/Downloads ~ -maxdepth 1 \
  \( -iname 'AGENTS*.md' -o -iname 'CLAUDE*.md' \)
ls -la ~/Downloads/.claude ~/Downloads/.codex 2>/dev/null

Check Codex's user config for MCP servers and base URLs you didn't add:

grep -nE 'mcp_servers|base_url|launchctl' \
  ~/.codex/config.toml

Check every Claude Code settings file near your home folder for endpoints:

find ~ -maxdepth 4 -path '*/.claude/settings*.json' \
  -exec grep -HnE 'BASE_URL|PROXY' {} +

And look for the package itself. The write-up doesn't say where the install landed, so check global installs and project folders both:

npm ls -g function-color
find ~ -maxdepth 5 -type d \
  -path '*node_modules/function-color' 2>/dev/null

Then the habits:

~/Downloads or in $HOME. Start it in a project folder you created or cloned on purpose.AGENTS.md or CLAUDE.md you didn't write before an agent does, including in a repo you just cloned.function-color was installed as compromised. I build Hermes IDE, so weigh this with that in mind. Hermes runs Claude Code, Codex and other agents, each in its own real terminal with its own sign-in. Hermes never asks for your tokens.

Two of its defaults line up with the checklist. A task you start with ⌘N (Ctrl+Shift+N on Windows and Linux) runs in a project you picked, on its own hermes/ branch and worktree, with the task as the agent's first prompt. That makes "where did I start this agent" a choice you see, not whatever folder a terminal happened to be in. And per the README, Hermes never answers a permission prompt for you and never types into a terminal on its own, so when the agent's mode asks before writing .claude/settings.json (as default and acceptEdits do), that prompt waits for you.

The ⌘N New task sheet: agent, project, a new hermes/ worktree, the approval mode, and a preview of the command Hermes will run.

It does not block this attack. ~/.codex/config.toml lives outside every worktree, so a change there reaches Hermes sessions like any other. A malicious AGENTS.md committed to a repo you picked is in the worktree too. And if you approve the prompt, the write happens. What Hermes adds is visibility: every agent turn is saved, and the Review Desk (⌘G) shows changes by turn, so a settings file written inside the repo appears in that turn's diff, unless git ignores it.

Hermes is free, source-available under BSL 1.1, and runs on macOS, Windows and Linux. It isn't affiliated with OpenAI, Anthropic or Nous Research. Download it or read the code on GitHub.

This attack works because an agent treated a file it found as policy. AI That Ships is the book on the layer that should sit between an agent and production in TypeScript: guardrails on what it can do, evals that catch it drifting, and cost ceilings when something loops.

The whole AI in TypeScript series, from a first LLM call to agents in production, is at xgabriel.com/ai-in-typescript.

── more in #ai-agents 4 stories · sorted by recency
── more on @forever security 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
→ Live at https://your-agent.zahid.host ✓
Get free account → Pricing
from €0/mo · no card required
LIVE [news/a-web-page-dropped-a…] indexed:0 read:7min 2026-10-29 · —