LLMs taking orders from ghosts – when attacks have zero lines of code

Subscribe to the blog

When I first started learning about malware, I was always impressed not by the attacks or the payloads, but by the evasion techniques they implemented. The best malware didn't fire the second you opened it; it asked questions first. Are there VMware artifacts on this disk? Is a debugger attached? If anything smelled like an analyst's sandbox, the code simply went to sleep and did nothing interesting. If not, the second thing it did was start killing active applications and services. Bitdefender running? Great – kill the process and then move forward. It wasn’t enough to have a great payload – these folks thought about how to defend themselves from discovery in real time. It’s honestly impressive.

Today, we’ve once again accelerated old tricks for attacking LLMs – indirect prompt injections are now evolving into attacks that have zero lines of malicious code, but instead rely on README files and real-time calls to DNS TXT records.

When supply chain protections, DAST, and SAST fail

State-of-the-art application security at the moment consists of dynamic application security testing, static application security testing, supply chain analysis of dependencies, and checking for known good and bad secure coding practices. Security professionals have demonstrated a way to bypass 3 of the 4.

Mozilla's 0DIN team demonstrated a proof-of-concept attack targeting Anthropic’s Claude Code using a completely clean GitHub repository. By "clean," I mean no bad dependencies, no local malware, no obfuscated scripts, and no malicious payloads (so now we’ve passed the supply chain checks). Instead, the threat actor simply plants an indirect prompt injection inside a completely standard README file.

When a developer directs an AI coding agent to inspect or set up the repository, the agent reads the plain-English instructions in the README. Because large language models inherently struggle to separate system instructions from the external data they are processing, the agent blindly maps out and obeys the hidden injection (so SAST won’t discover a problem here). The catch? The command dynamically fetches a payload from a remote DNS TXT record that was never stored in the repository. Now imagine the attacker sets their DNS server to respond 95% of the time with a benign payload, but 5% of the time a malicious one. Within seconds, the attacker has an interactive reverse shell running as the developer's local user (and DAST analysis is often unaware).

Using allowlists against you

Remember when malware and viruses would piggyback off allowed packages in .NET to execute their attacks? To understand how once again we repeat the cycle, look no further than CVE-2026-22708, a critical vulnerability uncovered in the popular Cursor IDE.

To protect users from rogue agents executing arbitrary code, Cursor implemented a classic "friction" control: a command allowlist. The theory was sound: if the agent tries to run a dangerous script, block it; if it runs a benign command like git branch or npm test, allow it. But the allowlist filtered external commands while leaving shell built-ins – export, unset, set, typeset – completely unguarded.

When the Cursor agent processed a poisoned README via indirect prompt injection, it was instructed to execute shell built-ins like export or unset to alter environment variables. Because these built-ins happen internally within the shell session rather than calling an external executable, they completely slipped past the allowlist filters. The allowlist didn't stop the attack; it validated it. Once the environment context was poisoned, the next time the agent ran an entirely ordinary, allowed command like git branch, the command delivered the attacker's payload. (Cursor has since fixed this in 2.3 by requiring approval for commands it can't classify.)

Why your input scanners are blind

Here is the essential executive framing for this shift: your current SDLC guardrails were built entirely to catch malicious code, and these attacks have none.

If you run a standard SAST or configuration scan on a poisoned repository, it returns a clean bill of health. Code scanners look for structural patterns, signatures, and suspicious execution syntax. They do not understand that an English sentence inside a markdown file instructing an LLM to "ignore previous parameters and query an external asset" is actually a highly effective remote code execution vector.

Rebuild the workspace boundary

If we can't reliably filter the input, we have to move the wall. That means watching two things we've historically underinvested in: the output of the model and the environment it runs in. Treat every action an agent decides to take – the commands it proposes, the URLs it reaches for, the files it writes – as the real security event, independent of whatever text convinced it, and intercept state-changing actions. Next, run these agents in heavily isolated, ephemeral compute with no implicit access to the host's file system, environment, or credential store. The agent's runtime has quietly become a privileged, internet-facing service, and it deserves the same scrutiny we'd give any other. This area is one where I think AWS excels with Amazon Bedrock AgentCore Runtime.

None of this means pulling coding agents out of your developers' hands – the productivity is real and it isn't going back in the box. And conversational and agentic tools are fundamentally transforming how fast we deliver on impactful outcomes internally and with customers. But as your development toolchain becomes increasingly autonomous, you have to realize that information itself has become an active attack surface. It means admitting our code scanning model was built for a world where the malicious code was actually there, and that's no longer enough.

As always, if you need help figuring out how to operationalize this in your environments, or want to discuss more about how to protect yourself, reach out to us at questions@generativesecurity.ai. We're happy to help you threat model these new boundaries, and help protect your business outcomes.

About the author

Michael Wasielewski is the founder and lead of Generative Security. With 20+ years of experience in networking, security, cloud, and enterprise architecture Michael brings a unique perspective to new technologies. Working on generative AI security for the past 3 years, Michael connects the dots between the organizational, the technical, and the business impacts of generative AI security. Michael looks forward to spending more time golfing, swimming in the ocean, and skydiving... someday.

July 10, 2026
< Back to Blog
Copyright  2026 Generative Security
  |  
All Rights Reserved