2026-06-29
When your coding agent installs the malware
A real incident: a coding agent running in bypass mode ran an obfuscated curl … | bash from a phishing site and let in an AMOS Stealer variant. Here's the attack chain, where OpenGuardrails would have stopped it — and, honestly, where it wouldn't.
This one is from the field, not a lab. A developer ran their coding agent in bypass mode — every command auto-approved, no prompts. While installing or updating some tool, the agent went looking for the download online, landed on a phishing site ranked #1 in the search results (a fake "official" page), and ran a one-line curl that fetched and executed an obfuscated payload from a remote IP.
That payload was a macOS variant of AMOS Stealer. It sat for about a month before discovery. By the time it was found it had added a login item for persistence, dropped a root daemon that polled once a second for a user login, used AppleScript to switch into the user's session, and launched a helper — disguised as com.apple.accountsd.helper — that pulled remote instructions and opened an interactive PTY shell for hands-on control. It wiped its logs as it went. What it took on the way out: browser-extension crypto wallets, session cookies (which led to an X account being hijacked via an added passkey), Keychain credentials, .env files, and assorted tokens.
The developer's own takeaway was exactly right: turn on 2FA everywhere, and watch what the AI executes — especially during installs and updates. This post is about making that second lesson enforceable, because "watch what the AI executes" does not scale when the whole point of an agent is that you are not watching.
The attack chain, and who can still say no
OpenGuardrails (OGR) is a neutral enforcement layer: it turns each agent action into a GuardEvent, runs it past detectors you choose, and returns a Verdict — allow, block, or require approval — before the action runs. So the useful question is not "is OGR antivirus?" (it isn't), but "at which step in this chain can something still say no, and does OGR sit there?"
| # | What happened | In scope for OGR? |
|---|---|---|
| 1 | Agent finds an "official" download — a phishing site, #1 in search | ⚠️ indirectly — this is untrusted input |
| 2 | curl <obfuscated> downloads + executes a payload from a remote IP | ✅ OGR's core interception point |
| 3 | Malware persists: login item + root daemon | ❌ now running at the OS level |
| 4 | AppleScript switches user, helper opens a remote PTY shell | ❌ outside the agent boundary |
| 5 | Steals wallets / cookies / Keychain / .env, exfiltrates | ✅ if exec went through an OGR sandbox |
Everything downstream — the persistence, the root daemon, the remote shell, the theft — only happened because step 2 ran. Stop step 2 and there is no incident. That is precisely where OGR lives.
Where OGR stops it
Step 2 is the textbook case. An obfuscated download-and-execute is the canonical thing the OGR agent-hook gate is built to catch. Three things matter here:
- It fires even in bypass mode. This is the part people miss. "Bypass / auto-approve" disables the agent's own prompts. The OGR gate sits outside that approval flow — it is a separate enforcement layer, not a setting the agent can wave through. A
curl … | sh, a piped remote script, an obfuscated one-liner →deny-wins→ block (orrequire_approval), regardless of how permissive the agent's mode is. - Provenance, not the string. The download URL originated from a web search result — untrusted input — and then drove a privileged action: execute downloaded code. "Untrusted input → privileged action" is the combination OGR keys on. It is what separates this from a normal, user-typed install of the same bytes.
- The network never opens. With an OGR sandbox (srt on a laptop, a container gateway for multi-tenant), egress is deny-by-default. The fetch to an unknown remote IP is blocked at step 2; the exfiltration in step 5 is blocked again. Both legs of the attack need the network, and the network is closed unless you allowlisted the host.
And the loot itself is behind the sandbox's deny_read: browser profiles, the Keychain, ~/.ssh, ~/.aws, .env, tokens. Even if something runs inside the agent's context, those paths are not readable.
A policy that would have stopped this is small and declarative:
{
"sandbox": {
"egress_allowlist": ["api.github.com", "*.github.com", "pypi.org", "registry.npmjs.org"],
"deny_read": ["~/.ssh", "~/.aws", "~/.netrc", "~/Library/Keychains",
"~/Library/Application Support/*/Local Storage", ".env"]
},
"config_rules": {
"command_rules": [
{ "id": "pipe-to-shell",
"regex": "(curl|wget)\\b.*\\|\\s*(ba)?sh",
"category": "security.malicious_command", "decision": "block",
"why": "remote script fetched and piped directly into a shell" },
{ "id": "obfuscated-exec",
"regex": "(base64\\s+-d|eval\\s+\"?\\$\\(|\\bxxd\\b).*\\|\\s*(ba)?sh",
"category": "security.malicious_command", "decision": "block",
"why": "decoded/obfuscated payload piped into a shell" }
]
}
}
The deterministic rules catch the obvious shapes; the LLM judge (your own model, run as a guardrail) catches the rephrasings that dodge a regex; egress_allowlist is the backstop that does not care how clever the command was, because the host was never on the list.
Where OGR does not help — honestly
OGR guards the agent. That is its scope, and it is worth being precise about the edge:
- It is not antivirus / EDR. Once code executes and escapes to OS-level root persistence (steps 3–4), it is no longer an agent action — it is a process OGR never sees. Root can disable anything. OGR's value is killing step 2 so steps 3–5 never happen; it is prevention at the agent boundary, not post-infection cleanup.
- The gate needs a real sandbox underneath to be robust. The block decision alone would have stopped this incident. But to defend the "what if something runs anyway" case, the agent has to actually run inside srt or a container, where exec, network, and filesystem are confined by the OS. A coding agent in bypass mode today typically runs bare on the host — which is exactly why one
curlwas enough. - Account 2FA is out of scope. OGR can't add a passkey for you. But by stopping the cookie theft at step 5, it removes the root cause of the account takeover — the stolen session — rather than relying on 2FA to clean up afterward.
The lesson, made enforceable
"Confirm before the AI runs installs and updates" is good advice that fails the moment you stop paying attention — and agents exist so you can stop paying attention. The fix is not more discipline; it is a layer that says no without a human in the loop, and that keeps saying no even when the agent is in bypass mode.
That is the whole idea behind the command-approval gate going into agent runtimes (opencode, Kilo CLI) on top of OGR: re-insert one enforced decision point on the would-auto-approve path, key it on provenance, and back it with a deny-by-default network. The threats in this incident map cleanly onto the four categories OGR's benchmark measures — prompt injection, malicious command, exfiltration, secret-leak — which is the point: these are not hypotheticals.
The attacker's edge here was that fake official sites rank first and look right, and an agent in a hurry clicks through faster than a human would. You will not out-vigilance that. You enforce against it.
OpenGuardrails is an open standard for AI agent safety & security — a vendor-neutral protocol (GuardEvent → Verdict) plus a neutral benchmark. Read the spec · agent guide · run the example.