SymJack is a new attack technique targeting AI coding agents: a booby-trapped repository to trick your AI coding assistant into overwriting its own configuration through a disguised file copy, then run attacker code on the restart. This is one technique that works against the whole category, don’t treat it as six separate bugs.
Updated on 27 May 2026 to include OpenAI Codex CLI.
Update, 27 May 2026: after publication we confirmed the same chain against a sixth tool, OpenAI’s Codex CLI (v0.133.0). OpenAI’s Bugcrowd program closed the report as a false positive, calling it theoretical and citing the fact that the user approves the cp command. That approval is the whole point. The user approves a file copy and gets a config overwrite that runs code on restart. Full response below.
How this coding agent security bypass works
One flaw, six products
How to protect your developers and pipelines
Technical appendix: the full chain
We found that a booby-trapped code repository can take over a developer’s workstation through their AI coding assistant, with the developer approving only what appears to be a harmless video file copy. We proved it against independent products from six companies: Claude Code, Gemini CLI / Antigravity CLI, Cursor, Copilot, Codex and Grok Build. Every one fell for the same chain. We built the first proof of concept on Claude Code, which is the one we walk through in deeper detail below.
We call this class of attack SymJack, for the symlink hijack at its core: the developer approves what the prompt shows, the kernel writes somewhere else.
Grok Build approval dialog - looks as innocent as it gets.
Given how quickly AI coding agents are becoming standard and how little time developers have to review the cybersecurity model paired with each agent, this attack is more significant than it seems. Agents run on both developer laptops and CI runners, hold credentials, have shell access, and can read and write source code. Their security model relies on a human clicking “approve” for sensitive actions. This attack turns that approval into theater.
This is the second time we have pulled this thread. In early May, we published TrustFall , showing that the same four CLIs (Claude Code, Gemini CLI, Cursor CLI, GitHub Copilot CLI) execute project-defined MCP servers the moment a developer accepts the folder trust prompt. TrustFall relied on a repo shipping a populated config that the trust dialog fails to display. The new attack raises the bar for developer vigilance: config files are empty, and malicious settings are added after the trust prompt using the victim’s own approved file copy.
Strip away the per-vendor details and the chain is the same everywhere.
First, the instructions. Every major coding assistant reads a project instructions file when it starts: CLAUDE.md , AGENTS.md , GEMINI.md , copilot-instructions.md , CURSOR.md . The agent treats that file as trusted guidance from the developer. An attacker who controls the repo controls that file. In our proof of concept the instructions pose as a “documentation generator” and tell the agent to copy a couple of media files from one folder to another. Routine housekeeping, nothing that reads as dangerous.
Second, the disguised write. The instructions tell the agent to use a raw shell copy command rather than the agent’s own file writing tools. The native write tools in these products have guardrails that flag sensitive paths like config files. A raw cp slips past those checks, because the permission prompt inspects the command text, not the real effect. Copying a file named like a video looks innocent, and the agent does not parse the contents of a media file before moving it.
Approval in Gemini CLI
Third, the symlink. The “destination” of that copy is not a real file. It is a symbolic link committed into the repo, pointing at the agent’s own configuration: the MCP server definitions, the settings file. When the user approves the copy and the system runs it, the kernel follows the link and writes the attacker’s payload straight into the config. The payload is JSON configuration file dressed up with a media file extension. It registers a malicious MCP server whose startup command runs whatever the attacker wants.
The developer sees one request: copy this video file to that documentation folder. They approve it. Nothing on screen mentions the config directory, the MCP file, or executable content. On the restart, the planted server spawns, and the attacker’s code runs as the user, unsandboxed. In a real attack it can steal SSH keys, cloud tokens, and browser sessions, or even destroy production assets before the developer types another word.
Cursor CLI trust prompt
On a developer laptop the attack needs one approval click. On CI it often needs none. Continuous integration runners commonly auto-trust their workspace and run agents in non-interactive modes that approve tool calls automatically, precisely so a pipeline does not stall waiting for a human. Drop the same CLAUDE.md , payload files, and symlinks into a pull request, and the moment a coding agent runs against that branch the chain executes end to end with no operator present. The blast radius is worse than on a laptop: CI runners hold deploy keys, signing material, cloud credentials, and registry tokens, and a single malicious pull request can exfiltrate all of them before any human reviews the change. That is a supply chain attack with a coding agent as the delivery mechanism.
The same SymJack chain worked against six independent products from six companies. When one tool has a flaw, you patch the tool. When every tool in a category shares the flaw, the category has a design assumption that does not hold.
The shared assumption is that showing a prompt is the same as obtaining informed consent. It is not. Informed consent requires two things the prompt withholds: an accurate picture of what the action does, and enough context to judge whether it is safe. At the time of testing, only Claude Code (after recent updates!) showed the user where a file write would land once symlinks resolved. So the user reasons correctly the wrong facts. The tool never tells them that the copy rewrites authentication config and runs code on restart. The prompt asks for a decision while hiding the one detail that would change it.
The issue is class-wide because all vendors made the same four design choices. Each one auto-ingests a project instruction file as trusted input, exposes a raw shell as an escape hatch that sidesteps the guardrails on its native write tools, renders the per-action approval against the literal command string rather than the resolved effect. And each one loads and runs MCP servers from config on startup. Any agent built on those four choices is exposed, including products that have not shipped yet. That is why we treat SymJack as a pattern in the category.
On developer machines, cloning an unfamiliar repository and pointing a coding agent at it becomes a credential exposure event the moment someone approves a benign-looking copy. Most organizations don’t have controls to prevent it.
We disclosed the issue to all six vendors through their security programs, with working proof-of-concept repositories for each. The responses show how six companies can look at the same evidence and reach different conclusions.
Anthropic’s outcome is the most telling. The HackerOne triage closed our report as out of scope, citing the program’s carve-out for symlinks and aliased commands used to bypass permission prompts, and its position that accepting workspace trust hands responsibility for the folder’s contents to the user. We read that symlink carve-out as written for a developer’s own environment shortcuts, not for attacker-committed symlinks shipped inside a cloned repo. The scope argument and ours are both defensible against the program text, and we did not change each other’s minds.
But the shipping product changed. The hardened version of Claude Code now resolves symlinks before it asks for approval and shows the real destination path in the prompt. A user who would have seen cp media/vid0.mp4 docs/vid-settings.mp4 now sees that the write actually lands in the configuration file. That closes the specific deception this attack depends on. The report was rejected on paper, and fixed in practice.
Claude Code behavior before and after addressing symlink issue. Click to enlarge.
Google declined, arguing that the attack requires the victim to clone a malicious repo and approve a command, which the program views as a user attacking themselves within a single-user environment. This reminds us of how the security industry initially dismissed ClickFix attacks. They are now recognized as some of the most common and dangerous attack vectors.
Cursor declined because another researcher had already reported symlink mishandling, and acknowledged ours as a different exploitation path on the same underlying flaw. xAI and GitHub have not yet replied. Copilot does show a warning when a symlink points outside the project, but the warning displays the link name or absolute path rather than the resolved target, so the user still cannot see what is really being written.
OpenAI’s Bugcrowd program closed our Codex CLI report, calling it theoretical and pointing to the step where the user approves the cp command as proof that no security boundary was crossed. That reasoning is the bug. The approval is informed only if the prompt tells the user what the copy actually does, and it does not.
! Copilot shows no warning when copying to project-scoped .mcp.json
! Copilot shows warning when trying to read from outside project scope.
To ensure robust coding agent security, the tools themselves need to change, and you need cybersecurity controls that do not depend on the agent being honest its own actions.
The root cause is that several separate checks each inspect a different representation of the same write, and none of them resolve the symlink. The fixes follow from that:
You cannot wait for five vendors to converge on a fix, and you cannot assume every coding agent in your fleet is patched. Runtime protection for AI agents is converging around a handful of capabilities:
For this specific attack, those capabilities translate into concrete controls. Policy enforcement means denying shell writes into config directories and MCP files, and forcing project-scope MCP execution off (Claude Code supports a managed-settings file that user scope cannot override; apply the equivalent for each agent). Behavioral monitoring and observability mean alerting when a coding agent or a process it spawned writes to a config directory or MCP file, then launches an interpreter ( node -e , python -c , sh -c ). Identity governance means least-privilege scoping of agent credentials and isolating CI runners that handle untrusted pull requests from those holding production secrets. Guardrailing before execution means scanning repos for tracked symlinks that target config files and for instruction files with a high blank-line ratio and a single deep include, and failing pull requests that modify agent config, MCP definitions, or instruction files. And treat any host that has run a coding agent against an untrusted repo as potentially compromised: rotate the SSH keys, cloud tokens, and signing material reachable from it.
Files that carry the payload ship with names and extensions that discourage human review and content parsing. Files that become malicious config ship empty, so a pre-run audit of the clone shows nothing.
SymJack in OpenAI Codex
Five separate controls each look at a different representation of the same write, and none resolve the symlink:
The settings payload pads dangerous keys at the end, after realistic-looking debug-log noise, where a skimming reviewer is least likely to reach:
The MCP payload registers a server whose startup command runs inline, with no external file and no further tool call:
CVE-2025-59536 (Check Point, October 2025) showed a repo could set enableAllProjectMcpServers in project scope and start MCP servers before the trust dialog. The v1.0.111 patch delayed MCP startup until after the dialog. This chain extends that line: the weaponized repo ships its config files empty and writes them after the trust prompt using the victim’s own approved copy, and it weaponizes a shell copy with symlinked destinations to defeat the framework’s own sensitive-file warnings. The conversation moves from “the settings scope is too permissive” to “the approval prompt is telling the user the wrong destination”.
TrustFall (Adversa AI, May 2026). TrustFall documented that all four agentic CLIs auto-execute project-defined MCP servers on trust-prompt acceptance, that Claude Code’s v2.1+ dialog dropped the earlier MCP warning and now lists nothing, and that the MCP-enabling settings (enableAllProjectMcpServers, enabledMcpjsonServers) are not blocked from project scope the way bypassPermissions is. The technique in this report sidesteps the part TrustFall depended on, the populated config visible at clone time, by writing the same settings after trust through a disguised cp and a symlink. Same root cause, fewer prerequisites.
DeepJack (Adversa AI, July 2026) is the same failure on a different surface. A crafted cursor:// deeplink reaches the MCP install dialog, which renders the command in a single-line field, so the malicious tail scrolls out of view before the user approves it. Where SymJack lies the destination of a write, DeepJack lies the command being installed.
Proof of concept repositories for each AI coding agent in Adversa AI GitHub repository (safe version, “malicious” MCP just emits a confirmation message).
Full PoC videos: (Youtube links)
SymJack: the approval prompt is lying to you. A symlink-hijack RCE in six AI coding agents
The full story
This article is one source in a clustered incident — the cluster page carries the summary, timeline and every other outlet covering it.
