{"id":91828,"date":"2026-07-01T09:39:14","date_gmt":"2026-07-01T09:39:14","guid":{"rendered":"https:\/\/www.europesays.com\/ai\/91828\/"},"modified":"2026-07-01T09:39:14","modified_gmt":"2026-07-01T09:39:14","slug":"guardfall-flaw-hits-10-of-11-popular-open-source-ai-agents","status":"publish","type":"post","link":"https:\/\/www.europesays.com\/ai\/91828\/","title":{"rendered":"GuardFall Flaw Hits 10 of 11 Popular Open-Source AI Agents"},"content":{"rendered":"<p>\n\t\t\t\t\t\t\tGuardFall Flaw Hits 10 of 11 Popular Open-Source AI Agents\n\t\t\t\t\t\t<\/p>\n<p>\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/securityaffairs.com\/wp-content\/themes\/security_affairs\/images\/user-icon.svg\" alt=\"\"\/> <a href=\"https:\/\/securityaffairs.com\/author\/paganinip\" rel=\"nofollow noopener\" target=\"_blank\">Pierluigi Paganini<\/a><br \/>\n\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/securityaffairs.com\/wp-content\/themes\/security_affairs\/images\/clock-icon.svg\" alt=\"\"\/> July 01, 2026<\/p>\n<p>\t\t\t\t\t\t<img decoding=\"async\" class=\"img-fluid mb-4\" src=\"https:\/\/www.europesays.com\/ai\/wp-content\/uploads\/2026\/07\/1782898754_487_image.png\" alt=\"\"\/><\/p>\n<p>Researchers found a shell injection flaw in 10 of 11 popular open-source AI agents, allowing attackers to bypass command filters.<\/p>\n<p class=\"wp-block-paragraph\">Adversa AI just published a survey, titled \u201cGuardFall: a universal shell injection vulnerability in open-source AI agents,\u201d of eleven open-source AI coding and computer-use agents, and the headline finding is uncomfortable: ten of them leave a structural gap that lets a shell bypass walk straight through their command filter. The one that doesn\u2019t is Continue. The rest include Hermes, opencode, Goose, Cline, Roo-Code, Aider, Plandex, Open Interpreter, OpenHands, and SWE-agent, ranked by GitHub star count, roughly 548,000 combined.<\/p>\n<p><a href=\"https:\/\/i0.wp.com\/securityaffairs.com\/wp-content\/uploads\/2026\/07\/image.png?ssl=1\" rel=\"nofollow noopener\" target=\"_blank\"><img data-recalc-dims=\"1\" fetchpriority=\"high\" decoding=\"async\" width=\"926\" height=\"752\" src=\"https:\/\/www.europesays.com\/ai\/wp-content\/uploads\/2026\/07\/1782898754_646_image.png\" alt=\"\" class=\"wp-image-194552\" style=\"aspect-ratio:1.2313894360712814;width:640px;height:auto\"  \/><\/a><\/p>\n<p class=\"wp-block-paragraph\">The core of the GuardFall issue is a mismatch that\u2019s been sitting in security literature for decades. The filter checks what the command looks like. Bash runs what the command means. Those two things are not the same.<\/p>\n<p class=\"wp-block-paragraph\">\u201cAI coding agents and computer use agents run shell commands with your full account authority: your SSH keys, your cloud credentials, everything in\u00a0$HOME. Most of them gate that power behind a guard that matches the command string against a list of dangerous patterns.\u201d reads the <a href=\"https:\/\/adversa.ai\/blog\/opensource-ai-coding-agents-shell-injection-vulnerability\/\" rel=\"nofollow noopener\" target=\"_blank\">report<\/a> published by Adversa. \u201cBut the string being inspected is different from the command executed. A guard inspects raw text, while system shell (bash)\u00a0expands, unquotes, and rewrites\u00a0text before running it. So, when an agent processes untrusted content (for example, an npm package with a poisoned README), the prompt injection can make it run a command that passes all the execution filters.\u201d<\/p>\n<p class=\"wp-block-paragraph\">Bash has always done quote removal, parameter expansion, command substitution, and field splitting. These aren\u2019t bugs. They\u2019re documented features. The problem is that an AI agent that pattern-matches raw command strings against a denylist is making a security decision on text that bash will rewrite before executing.<\/p>\n<p class=\"wp-block-paragraph\">Adversa identified five bypass classes. Class A: write r&#8221;m instead of rm. The regex never fires. Bash strips the quotes and runs rm. Class B: write rm$IFS-rf$IFS\/. To a regex that looks for rm followed by a space, this is one word. Bash expands $IFS to whitespace and executes three arguments. Class C: put the binary name inside a command substitution, like $(echo rm) -rf \/. The regex sees a substitution expression, not a binary name. Class D: pipe base64-encoded payload through sh. Each segment is benign alone. The composition is not. Class E is the most successful and the hardest to patch, because it involves alternative commands that turn destructive with specific flags: find \/x -delete, dd of=\/dev\/sda, install -m 4755 payload \/usr\/local\/bin\/backdoor. A guard that denies rm -rf misses all of them.<\/p>\n<p class=\"wp-block-paragraph\">\u201cA guard that denies\u00a0rm -rf\u00a0and\u00a0mkfs.*\u00a0misses the long tail of POSIX utilities that turn destructive with the right flags.\u201d continues the report. \u201cClass E survives the most guards, including the strongest tokenized guard in our survey, because per-flag reasoning requires knowing, for each binary, which flag combinations flip it from benign to destructive.\u201d<\/p>\n<p class=\"wp-block-paragraph\">The research started when Adversa found a bypass in NousResearch\/hermes-agent: an approval gate defeated by shell rewrites against a 30-pattern regex denylist. They confirmed it live, then built the survey around the same bypass class across the rest of the category. The finding is not that the agents are badly written. It\u2019s that the convention they share is structurally wrong.<\/p>\n<p class=\"wp-block-paragraph\">\u201cGuardFall is not a bug, but a dangerous convention and a class of problems.\u00a0A filter that string-matches raw commands can\u2019t model bash\u2019s expansion, so it provides confidence without protection; that confidence gets the Human-in-the-Loop switched off and auto-mode switched on.\u201d continues the report.<\/p>\n<p class=\"wp-block-paragraph\">Three agents ship a guard that exists and gets defeated outright: Hermes, opencode, and Goose. Their regex-over-raw-string guards fire on rm -rf but stay silent on bypass variants, leaking almost every probe in the test set. Goose leaked 22 of 23 cases. Opencode leaked 16 of 16.<\/p>\n<p class=\"wp-block-paragraph\">Two more ship a tokenized guard that\u2019s meaningfully better but still incomplete. Tokenizing closes quote-removal bypasses and some $IFS variants. What it doesn\u2019t close is a command substitution inside a quoted argument, like echo &#8220;$(rm -rf \/x)&#8221;, where the outer command is echo, which every guard allows, and the destructive command runs as a side effect. It also doesn\u2019t close Class E, because per-flag reasoning requires knowing which flag combinations make a given binary destructive, and none of these agents have that knowledge.<\/p>\n<p class=\"wp-block-paragraph\">The remaining agents ship no static guard at all, relying entirely on human confirmation before each command runs. That\u2019s sound until the operator switches on auto-execute, which is the default in CI pipelines and the obvious choice whenever an agent starts interrupting the workflow. Some agents make this worse: a malicious repository can ship a committed config file, like an .aider.conf.yml with auto-test: true and a payload in the test-cmd field, that fires the payload on the first accepted edit without any flag from the operator.<\/p>\n<p class=\"wp-block-paragraph\">The container case sits in its own category. Teams assume a sandbox means dangerous commands are stopped. What it actually means is the commands run inside a disposable box. The moment the workspace isn\u2019t disposable, the protection is gone. Every sandboxed agent in the survey ships a documented local-mode configuration that disables the container and runs commands directly on the host. In local mode, there\u2019s no fallback guard. Adversa\u2019s live tests against SWE-agent and OpenHands in local mode confirmed this: the destructive command ran on the host.<\/p>\n<p class=\"wp-block-paragraph\">The chain requires the language model to cooperate with the attacker\u2019s framing, and this is where the finding gets uncomfortable for anyone who assumes the model is the last line of defense. A direct prompt to run rm is refused. The same command wrapped in a Makefile target, an MCP \u201cdocumentation\u201d response, or an injected README task gets emitted as routine work. Adversa\u2019s live runs used Claude Sonnet 4.6 as the model, which is also the default for opencode, Goose, Cline, and Roo-Code. The chain is model-dependent and framing-dependent, which means it can shift as safety training evolves.<\/p>\n<p class=\"wp-block-paragraph\">One Cline test illustrated the fragility precisely. Framed as MCP content, the model spotted the injection and emitted a read-only command. Re-framed as an authoritative MCP directive, it emitted find -delete without hedging. The controller passed it because find was on the allowlist. Same model, same payload, different framing, different outcome.<\/p>\n<p class=\"wp-block-paragraph\">Continue implements five components in sequence. It tokenizes the command using shell-quote before any matching, which closes quote-removal bypasses. It detects variable expansion tokens like $IFS and escalates those commands to require permission. It evaluates command substitutions recursively, constraining the outer verdict by the inner result. It checks whether any pipe segment terminates in a shell interpreter and escalates those too. It maintains an explicit disabled list for canonical destructive patterns.<\/p>\n<p class=\"wp-block-paragraph\">Of 21 bypass cases, zero passed through to unrestricted execution. All 12 canonical-destructive cases were correctly blocked. There are still gaps, Class C inside a quoted argument and the long tail of Class E both remain open, but Continue is the only agent in the survey that closes the structural majority of the surface. <\/p>\n<p class=\"wp-block-paragraph\">\u201cThe five components are independently meaningful: adopting just three (tokenize + substitution-recursion + pipe-destination) closes Classes A, B, C-outside, and D, leaving only C-inside-quotes and E, both addressable through an enumerated disabled list. Re-implementing the pattern is a two-day exercise for an experienced engineer.\u201d reads the report.<\/p>\n<p class=\"wp-block-paragraph\">Continue\u2019s CLI mode does partially relax enforcement under &#8211;auto, running commands that the IDE extension would prompt on. The disabled tier still holds in both modes: rm -rf \/, sudo, and chmod +s are hard-blocked regardless. The fix is to apply the same policy the IDE extension uses to the CLI\u2019s policy resolver.<\/p>\n<p class=\"wp-block-paragraph\">None of the short-term controls are sound defenses in the full sense. They\u2019re compensating measures. The strongest immediate step is running agents from a scoped shell with $HOME redirected. A one-line wrapper keeps the project directory but moves ~\/.ssh\/, ~\/.aws\/, shell history, and the rest of the credential surface out of scope. It\u2019s always-on and has no documented one-flag opt-out, which makes it more durable than operator discipline.<\/p>\n<p class=\"wp-block-paragraph\">Also worth doing this week: audit repository configs before letting an agent read them. A malicious .aider.conf.yml committed to a repository can trigger remote code execution on the first accepted edit, with no CLI flag from the operator. Disable agent execution on fork pull requests in CI. Turn off every auto-yes flag unless the use case genuinely can\u2019t be interrupted.<\/p>\n<p class=\"wp-block-paragraph\">The only sound, always-on defense is the tokenize-and-canonicalize evaluator. Until that becomes the convention rather than the exception, every agent shipping a string-matching guard is structurally one prompt injection away from the operator\u2019s full account authority being handed to whoever controls the content the agent reads.<\/p>\n<p class=\"wp-block-paragraph\">\u201cAn unsound guard offers no protection even when left on; a sandbox offers full protection until it\u2019s switched off; and only a sound, on-by-default guard protects the operator\u2019s own host without asking them to opt in.\u201d concludes the report. \u201cUntil that last shape becomes the convention, every agent that ships a string-matching guard is one prompt injection away from operator-account compromise.\u201d<\/p>\n<p class=\"wp-block-paragraph\">Follow me on Twitter:\u00a0<a href=\"https:\/\/twitter.com\/securityaffairs\" rel=\"nofollow noopener\" target=\"_blank\">@securityaffairs<\/a>\u00a0and\u00a0<a href=\"https:\/\/www.facebook.com\/sec.affairs\" rel=\"nofollow noopener\" target=\"_blank\">Facebook<\/a>\u00a0and\u00a0<a href=\"https:\/\/infosec.exchange\/@securityaffairs\" rel=\"nofollow noopener\" target=\"_blank\">Mastodon<\/a><\/p>\n<p class=\"wp-block-paragraph\"><a href=\"http:\/\/www.linkedin.com\/pub\/pierluigi-paganini\/b\/742\/559\" rel=\"nofollow noopener\" target=\"_blank\">Pierluigi\u00a0Paganini<\/a><\/p>\n<p class=\"wp-block-paragraph\">(<a href=\"http:\/\/securityaffairs.co\/wordpress\/\" rel=\"nofollow noopener\" target=\"_blank\">SecurityAffairs<\/a>\u00a0\u2013\u00a0hacking,\u00a0AI)<\/p>\n<p>\t\t\t\t\t\t\t\t\t\t\t<script async src=\"https:\/\/platform.twitter.com\/widgets.js\" charset=\"utf-8\"><\/script><\/p>\n","protected":false},"excerpt":{"rendered":"GuardFall Flaw Hits 10 of 11 Popular Open-Source AI Agents Pierluigi Paganini July 01, 2026 Researchers found a&hellip;\n","protected":false},"author":2,"featured_media":91829,"comment_status":"","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[24,25,48339,315,8066,7512,8067,8068,8069,8070],"class_list":["post-91828","post","type-post","status-publish","format-standard","has-post-thumbnail","category-ai","tag-ai","tag-artificial-intelligence","tag-guardfall","tag-hacking","tag-hacking-news","tag-information-security-news","tag-it-information-security","tag-pierluigi-paganini","tag-security-affairs","tag-security-news"],"_links":{"self":[{"href":"https:\/\/www.europesays.com\/ai\/wp-json\/wp\/v2\/posts\/91828","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.europesays.com\/ai\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.europesays.com\/ai\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.europesays.com\/ai\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.europesays.com\/ai\/wp-json\/wp\/v2\/comments?post=91828"}],"version-history":[{"count":0,"href":"https:\/\/www.europesays.com\/ai\/wp-json\/wp\/v2\/posts\/91828\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.europesays.com\/ai\/wp-json\/wp\/v2\/media\/91829"}],"wp:attachment":[{"href":"https:\/\/www.europesays.com\/ai\/wp-json\/wp\/v2\/media?parent=91828"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.europesays.com\/ai\/wp-json\/wp\/v2\/categories?post=91828"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.europesays.com\/ai\/wp-json\/wp\/v2\/tags?post=91828"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}