DEV Community

Rulestack
Rulestack

Posted on

A web page can drop AGENTS.md or CLAUDE.md into ~/Downloads. Codex obeyed in over 90% of tries, Claude Code in about half

According to Forever Security, a web page can save a file into ~/Downloads without a click, and a coding agent started in that folder reads the instruction file it finds there. On 2026-10-22 Forever Security reported catching a planted AGENTS.md doing exactly that on a customer's Mac. Putting their write-up next to the Codex and Claude Code documentation shows the attack has to land in a different file for each tool, and each tool has a setting or a file you can check today.

What Forever Security found

Forever Security's post, Hijacking AI Agents via Downloads Folder, starts from an alert on a real customer machine. A coding agent, mid-session, tried to install function-color, an npm package from the MALFEX campaign that Checkmarx documented on 2026-10-05. Forever's tooling stopped it before any code ran.

The odd part was where the instruction came from. It was not a dependency or a repository. It was an AGENTS.md in the customer's ~/Downloads folder, and nobody knew how it got there. Forever describes the file as a long, mundane "Engineering Work Guidelines" document, with the attack in "one section near the end, dressed up as routine setup".

Their explanation is one sentence: "A web page can download a file named AGENTS.md into your Downloads folder, silently." Operating systems stopped downloaded executables from running on their own years ago, but a Markdown file is not an executable, so none of those checks apply. It sits there until an agent opens the folder and treats it as instructions.

Quote from Forever Security's 2026-10-22 post: a web page can download a file named AGENTS.md into your Downloads folder, silently

Forever then reproduced the chain on two agents. With the real file from the customer's machine, run inside an isolated VM, Codex ran the malware "in more than 90% of attempts". Claude Code was "much harder to fool", and the version that worked was a different file: a planted CLAUDE.md that talked Claude into writing a project settings file which pointed its API traffic at a server Forever controlled. That worked "about 50% of the time". Forever also reports that in their telemetry "about half of customers run a coding agent inside their Downloads folder".

We are not going to repeat the payloads here. What is useful for anyone running these tools is the question underneath: when you start each agent in a folder, which files does it read, and which of its own settings can a file in that folder change?

Which files each tool reads at startup

Codex. The AGENTS.md guide says Codex "builds an instruction chain when it starts". It reads a global file from ~/.codex, then, "Starting at the project root (typically the Git root), Codex walks down to your current working directory." The line that matters for Downloads is the next one: "If Codex cannot find a project root, it only checks the current directory." ~/Downloads is usually not inside a Git repository, so a session started there reads whatever AGENTS.md is sitting in it.

Claude Code. The memory documentation says "CLAUDE.md and CLAUDE.local.md files in the directory hierarchy above the working directory are loaded at launch." It also documents a newer behavior: Claude Code "can read AGENTS.md as your project instructions", and by default reads it "only when you have no CLAUDE.md in your working directory or above it". The note under that table says reading AGENTS.md directly "requires Claude Code v2.1.277 or later".

That second point is our inference, not something Forever tested. The file found on the customer's machine was written for Codex, but on a current Claude Code version, started in the same folder with no CLAUDE.md above it, the same AGENTS.md would be read as project instructions too.

Where each attack had to write, and why

The two reproductions ended up in different places, and the Codex configuration reference explains why.

The Codex config reference says "Codex loads project-scoped config files only when you trust the project", and that project-scoped config "can't override machine-local provider, auth" and related keys: "Codex ignores openai_base_url, chatgpt_base_url" there. A file in the Downloads folder cannot redirect Codex through a project config. The Codex payload Forever recovered went after the user-level file instead, ~/.codex/config.toml. Forever's point about that choice: "every Codex session on the machine loads the attacker's server at startup - in any folder, any project."

Claude Code goes the other way. The settings reference documents an env block whose example sets ANTHROPIC_BASE_URL to a proxy, and says values from project and local settings apply "after you trust the workspace". The same page lists variables that "a checked-out repository shouldn't control", such as CLAUDE_CONFIG_DIR and HOME, which project settings cannot set. ANTHROPIC_BASE_URL is not on that list, so a .claude/settings.json in a folder you have trusted can change where the session sends its API requests. That is the file Forever's CLAUDE.md asked Claude to write.

Codex Claude Code
Instruction file read in ~/Downloads AGENTS.md in the current directory when there is no project root CLAUDE.md, or AGENTS.md when no CLAUDE.md is in or above the folder (v2.1.277+)
File the reproduced attack wrote ~/.codex/config.toml (user level) .claude/settings.json in that folder
Why that file Project config cannot override the base URL keys Project env values apply once the folder is trusted
Reach of the write Every Codex session on the machine Sessions started in that folder
What stood in the way (per Forever) A trust gate, the network sandbox, startup timeouts The model refusing the write, and the permission prompt for it

The checks that stood in the way

Both attacks needed the folder to be trusted, and both needed one write to get past the agent's own caution.

On the Codex side, Forever writes that "Codex only obeys an AGENTS.md in a project it trusts. Once you have worked in Downloads, it qualifies." The config reference documents the related key, projects.<path>.trust_level, which can mark a project "trusted" or "untrusted", and says "Untrusted projects skip project-scoped .codex/ layers, including project-local config, hooks, and rules." We did not find a sentence in that reference that ties AGENTS.md itself to trust, so that part rests on Forever's testing.

On the Claude Code side, the permissions documentation explains how trust is stored. Outside a repository, "Claude Code keys the trust on the directory you started it from, and the trust covers any subdirectory of that directory apart from a git repository nested inside it, such as a clone." In the home directory itself, trust is held "for the current session only". So accepting the trust dialog once in ~/Downloads is enough for later sessions there.

The write to .claude/settings.json is the step that failed half the time, and the permission modes page says why. .claude is one of the protected paths, and writes there are "never auto-approved". In default and acceptEdits mode they are prompted, in auto mode they go to the classifier, and in bypassPermissions mode they are allowed. The page adds that permissions.allow rules "do not pre-approve protected-path writes". In other words, the prompt Forever's file had to talk its way past is the one place a person still sees the change, unless the session runs with permission checks turned off.

What you can check today

None of this needs a patch. These are the steps from Forever's post, plus the settings the documentation names.

1. Do not start an agent in ~/Downloads. This is Forever's first recommendation, and it removes the whole chain. If your terminal opens there by default, change into a project folder first.

2. Look for instruction files you did not write. A quick listing shows whether anything is waiting:

ls -la ~/Downloads/AGENTS.md ~/Downloads/CLAUDE.md ~/Downloads/.claude ~/Downloads/.codex 2>/dev/null
Enter fullscreen mode Exit fullscreen mode

Do the same in any repository you cloned recently before you start an agent in it. Read the file before an agent does.

3. For Codex, read ~/.codex/config.toml. Forever's advice is to watch for "an unexpected [mcp_servers.*] block or a changed chatgpt_base_url". If you want Codex to treat the folder as untrusted, the documented key looks like this in the user-level file:

[projects."/Users/you/Downloads"]
trust_level = "untrusted"
Enter fullscreen mode Exit fullscreen mode

Per the reference, that skips the folder's project-scoped .codex/ layers. Whether it also stops Codex from reading an AGENTS.md there is not stated in the reference, so do not rely on it as the only check.

4. For Claude Code, read .claude/settings.json in any folder you start in. Forever's advice is to watch for "an ANTHROPIC_BASE_URL, a proxy, or any other API endpoint you did not set". The trust you have accepted is recorded in ~/.claude.json: the permissions page names projects["<path>"].hasTrustDialogAccepted as the key for trusting a folder by hand. If your Downloads path appears there with true, a settings file planted in that folder would have its env values applied on the next launch.

5. Read the prompt for any write to .claude/. For the project's .claude/ folder the prompt can offer "Yes, and allow Claude to edit files in this project's .claude folder for this session". In a folder you did not set up, that is the option to decline. Avoid bypassPermissions in any folder whose files you have not read, since that mode allows protected-path writes without asking.

6. Use the newer guards for the settings write and the step after it. These arrived after Forever's testing, so their post does not cover them. Claude Code 2.1.314, published on 2026-10-30, added permissions.blockWritesOutsideWorkingDirectories. Its main job is in its name, but the settings reference adds that while it is on, Claude Code refuses writes to its own settings files "inside the working directories too, because a settings file can lift the block", and the permission modes page says this holds "in every permission mode". That is exactly the file Forever's CLAUDE.md needed. It has two limits. The same entry says "The key doesn't limit shell commands, MCP tools, or the programs hooks run", so it covers the Write and Edit tools, not a shell command that writes the same file. And on 2026-11-03 (UTC) the npm registry's stable tag for Claude Code still pointed at 2.1.311, so today the key needs the latest channel.

Forever's next step, once the settings file was in place, was a server answering as the model with a Bash call that set dangerouslyDisableSandbox to true. The sandbox.allowUnsandboxedCommands setting decides what happens to that parameter: "When it's false, Claude Code ignores that parameter." That only matters if you run with the sandbox on. If you manage machines for a team, the managed-only allowedProviders setting (v2.1.285 or later) works one level up: "A session on a provider that isn't listed is refused at startup, at login, and when it next contacts the API", and a custom endpoint named by ANTHROPIC_BASE_URL is admitted only for "the exact value a managed env block pins".

7. Decide whether you want Claude Code to read AGENTS.md at all. The memory documentation describes a Project instructions setting, reachable from /config or from ~/.claude/settings.json under pluginConfigs for cc-plugin-agents-md@builtin, with a value claude-md that reads CLAUDE.md files only. Check the ID against your version: "Before v2.1.285, the plugin's ID was agents-md@builtin". This closes the path where a file written for another agent gets picked up, but it does nothing about a planted CLAUDE.md, and it will drop the instructions of repositories that rely on AGENTS.md. It is a trade-off, not a fix.

8. If you find a planted file and an agent ran there, rotate. Forever: "Assume the token leaked."

What we could not confirm

The percentages are Forever's own testing and we have not reproduced them. Their post does not include a response from OpenAI or Anthropic; Forever's view is that "There is nothing here for OpenAI or Anthropic to patch." The claim that a Codex-targeted AGENTS.md would also be read by Claude Code comes from Claude Code's documentation, not from a test of that exact file. The same goes for the guards in step 6: we have not run Forever's file against the 2.1.314 write block or strict sandbox mode, and what we say they do comes from the settings reference.

The part we keep coming back to is how ordinary every step is. A browser saving a file, an agent reading the instruction file in its folder, a settings key that routes traffic through a gateway: each is documented behavior. The danger is only in the combination, and in starting the agent in the one folder the web can write to.

Where does your terminal open by default, and have you ever started a coding agent in ~/Downloads or in a folder you had just unzipped? If you have a check that runs before your agent reads a new folder, tell us how it works in the comments below.

Top comments (0)