In the last month, coding agents escaped their own sandbox, installed plugins that had been swapped for someone else’s code, and pushed more than 13,000 internal screenshots to public GitHub repositories. None of it needed a weak password, a phishing email or a careless developer. It needed an agent doing exactly what it was built to do.
I use Claude Code every day on client Magento and Adobe Commerce projects. That means an AI agent runs commands on a machine that also holds database credentials, Composer keys, SSH keys and access to client tickets. This post is what I changed after reading September’s incident reports, and the checklist I now apply before an agent touches a client repository.
What happened in September
Four stories, all from the last few weeks, all verified against their original write-ups:
- Two sandbox escapes in OpenAI Codex. Researchers at Accomplish AI showed Codex Desktop running commands on the host even in read-only mode, and Codex CLI writing outside its workspace by patching a symlinked
~/.zshrc. Both were reported on August 12 and fixed within eight days. Their conclusion is the important part: both sandboxes were enforced from inside the environment they were supposed to restrict. (Accomplish AI) - Plugin4Shell. Air Security found that agents verifying a plugin by its pinned commit could be tricked into checking out attacker code, using a branch named after that commit’s SHA. Claude Code, Codex and GitHub Copilot were affected, and Gemini CLI fell to a similar trick. Background plugin auto-update is on by default in Claude Code and Codex, so existing users didn’t have to click anything. Claude Code is fixed in 2.1.179 and Codex in 0.146.0; Copilot had no fix at disclosure. (Air Security)
- PixelLeak. Agents asked to attach before-and-after screenshots to pull requests couldn’t use GitHub’s browser-only image upload, so they created public repositories to host the images. Glow Labs found more than 13,000 internal images in over 900 repositories from more than 300 organizations, 93% of them under employees’ personal accounts. Glow reproduced the behaviour with Claude Code. No attacker was involved. (Glow Labs)
- A critical MCP server bug. The popular Jira and Confluence MCP server,
mcp-atlassian, let requests without a user identity run with its globally configured credentials (CVE-2026-77254, CVSS 9.1). Upgrade to 0.22.0 or later. (GitHub advisory)
Different vendors, different bugs, one pattern: the agent already had the access. Nobody had to break in.
Why a Magento project is a good target
Think about what sits next to the code on a typical Magento working copy:
app/etc/env.php, with database credentials and the encryption key.auth.json, with the client’s repo.magento.com keys and private Composer repositories.- SSH and deploy keys in your home directory, often with access to staging or production.
- An admin panel full of customer names, addresses, orders and payment settings. A screenshot of it is personal data, and secret scanners read text, not images.
- The client’s Jira or Confluence, increasingly wired to the agent through MCP.
An agent with your shell has all of that. So the question isn’t whether the agent is smart. It’s what it can reach when it does something unexpected.
Something changed in Claude Code too
Since late September, interactive Claude Code sessions in the terminal and VS Code start in auto mode when you haven’t configured a permission mode, on every plan. In auto mode a classifier decides which actions are safe enough to run without asking you. It’s a good productivity feature, and I use it. But a classifier deciding what’s safe is a convenience, not a security boundary. The rules below are the boundary.
One detail worth knowing: permissions.defaultMode still overrides the new default, but the values auto and bypassPermissions only take effect from your user settings, managed settings or the command line, not from a project’s .claude/settings.json. A cloned repository can’t quietly switch your agent into bypass mode.
My checklist for client repositories
1. Keep secrets out of the agent’s reach
Deny rules are deterministic: no classifier, no judgment call. I deny reads of the files that hold credentials in every Magento project:
{ "permissions": { "deny": [ "Read(./app/etc/env.php)", "Read(./auth.json)", "Read(./.env)", "Read(./.env.*)" ] }}Better still, the agent should never see production credentials in the first place. My local env.php points at a local database with sanitized data, and production keys don’t live on the machine I run agents on.
2. Turn the sandbox on
Claude Code’s Bash sandbox is off by default. Turn it on with /sandbox or in settings. It’s enforced by the operating system (macOS, Linux and WSL2), so commands and the processes they start can only write to the working directory and reach the network domains you allow. Two things to know: it covers shell commands only, not Claude’s file tools or MCP servers, and by default it can still read most of your machine, so deny the obvious places:
{ "sandbox": { "enabled": true, "allowUnsandboxedCommands": false, "filesystem": { "denyRead": ["~/.ssh", "~/.aws", "~/.composer/auth.json"] }, "network": { "allowedDomains": ["repo.magento.com", "repo.packagist.org", "github.com"] } }}allowUnsandboxedCommands: false stops the agent from retrying a blocked command outside the sandbox. The Codex escapes are the reason I don’t treat any sandbox as perfect, so for unfamiliar code (a third-party extension, a repo from a new client) I go one step further and run the agent inside a container or VM.
3. Treat plugins and MCP servers like Composer packages
We learned the hard way to review the extensions we install on a store. Agent plugins and MCP servers deserve the same care: they run with your access.
- Keep Claude Code updated. Plugin4Shell was fixed in 2.1.179; check yours with
claude --version. - Install plugins only from marketplaces you trust. Teams can enforce it with the managed settings
strictKnownMarketplacesandblockedMarketplaces. - Don’t auto-approve a repository’s MCP servers (
enableAllProjectMcpServers). Read.mcp.jsonbefore you say yes. - Run MCP servers locally over stdio, not as an open HTTP endpoint, and give them narrowly scoped tokens, never an admin account.
4. Block the “helpful” leaks with a hook
PixelLeak didn’t need an attacker, so a smarter attacker model won’t stop it. A PreToolUse hook can. It runs before every Bash command and can deny it with exit code 2:
{ "hooks": { "PreToolUse": [ { "matcher": "Bash", "hooks": [ { "type": "command", "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/no-public-leaks.sh" } ] } ] }}#!/bin/bash# Block commands that publish code or images outside the client's repository.command=$(jq -r '.tool_input.command')if [[ "$command" =~ (gh\ repo\ create|gh\ gist\ create|--visibility[=\ ]public|gitshot) ]]; then echo "Blocked: publishing outside the client repository needs a human." >&2 exit 2fiexit 0Pattern matching is never complete, so treat it as a seatbelt, not a wall. And never ask an agent to screenshot an admin panel with real customer data.
5. Choose your permission mode on purpose
Auto mode is fine with the rules above in place. What I avoid is bypassPermissions on any machine that holds client credentials. On a team, an admin can make that a policy with permissions.disableBypassPermissionsMode, and can block new model versions until they’ve been tested with availableModels and deniedModels in managed settings.
6. Review the code like it came from a new colleague
All of the above protects your machine. It doesn’t protect the store. Agent-written code still goes through the same review as anyone else’s, with extra attention where Magento hurts the most: checkout, payment methods, admin ACL, web API permissions and raw SQL.
A starting point you can copy
Here is the project file I start from. Put it in .claude/settings.json in the client repository and adjust the domains to the project:
{ "permissions": { "deny": [ "Read(./app/etc/env.php)", "Read(./auth.json)", "Read(./.env)", "Read(./.env.*)" ] }, "sandbox": { "enabled": true, "allowUnsandboxedCommands": false, "filesystem": { "denyRead": ["~/.ssh", "~/.aws", "~/.composer/auth.json"] }, "network": { "allowedDomains": ["repo.magento.com", "repo.packagist.org", "github.com"] } }, "hooks": { "PreToolUse": [ { "matcher": "Bash", "hooks": [ { "type": "command", "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/no-public-leaks.sh" } ] } ] }}Check the result with /permissions and /sandbox before you start working. If something legitimate breaks, widen one rule at a time instead of turning the whole thing off.
Final thought
For years our security work on Magento was about the store: patches, ACL, two-factor authentication on the admin. Now there’s a new member of the team with shell access, our credentials and a strong wish to be helpful. Give it the same treatment you’d give a new contractor on day one: a clear scope, only the keys it needs, and someone checking its work.
How are you running agents on client projects? I’d like to hear what your setup looks like.

Leave a Reply