mech.app

The mech.app newsletter

Agentic AI, minus the noise.

Get practical field notes on AI agents, automation, developer tools and security delivered to your inbox.

No spam. Unsubscribe anytime.

Dev Tools

0-Click RCE in AI Coding Agents: What Prompt Injection Teaches About Tool Execution Boundaries

How Plugin4Shell exploits the gap between LLM reasoning and shell execution, exposing privilege boundaries in Claude Code, Copilot, and Gemini CLI.

Source: theregister.com
0-Click RCE in AI Coding Agents: What Prompt Injection Teaches About Tool Execution Boundaries

The Plugin4Shell vulnerability exposes a fundamental design problem in AI coding agents: the boundary between what an LLM decides to do and what it has permission to execute is often nonexistent. Security researchers at Air disclosed a zero-click remote code execution flaw affecting Claude Code, GitHub Copilot, OpenAI Codex, Google Gemini CLI, and Microsoft Copilot. The attack vector is simple. Poison a plugin in a trusted marketplace, wait for an agent to install it, and you inherit every privilege the agent holds.

This is not a model jailbreak. This is a supply chain attack that exploits the trust relationship between agents and their tool ecosystems. The agent reasoning layer has no way to distinguish between legitimate plugin instructions and malicious commands embedded in plugin metadata or documentation.

How the Attack Works

Plugin4Shell targets the plugin installation flow. Most coding agents support extensions or plugins that add new capabilities (linters, formatters, API clients, deployment scripts). These plugins are distributed through marketplaces or package registries. The agent fetches plugin metadata, reads installation instructions, and executes setup commands.

The attack embeds malicious instructions in plugin metadata fields that the agent processes as part of its reasoning context. When the agent decides to install or configure the plugin, it executes those instructions with the same privileges it uses for legitimate coding tasks. No user confirmation is required because the agent interprets the plugin installation as a routine operation.

Attack chain:

  1. Attacker publishes or compromises a plugin in a trusted marketplace
  2. Malicious payload is embedded in plugin description, setup script, or configuration template
  3. User asks agent to install the plugin or agent auto-installs based on project dependencies
  4. Agent’s LLM processes plugin metadata as part of its reasoning context
  5. Agent executes embedded commands with full shell access
  6. Attacker gains RCE with agent’s privilege level

The zero-click aspect comes from agents that auto-install dependencies or plugins based on project context. If your codebase references a library, some agents will proactively fetch and configure tooling without explicit user approval.

The Privilege Boundary Problem

Most coding agents run with the same privileges as the developer’s shell session. They can read secrets from environment variables, access SSH keys, write to the filesystem, and make network requests. The agent’s execution environment is not sandboxed or isolated from the developer’s workspace.

This creates a privilege escalation surface. The LLM’s reasoning layer operates on untrusted input (user prompts, external documentation, plugin metadata), but its tool execution layer has full system access. There is no privilege separation between “thinking about what to do” and “doing it.”

Current agent architectures assume:

  • Plugin marketplaces are trusted
  • Plugin metadata is safe to process as reasoning context
  • Execution decisions made by the LLM are inherently safe
  • User approval is sufficient guardrail for dangerous operations

Plugin4Shell breaks all four assumptions. Marketplaces can be compromised. Metadata can contain prompt injection payloads. LLM reasoning can be manipulated. User approval is bypassed when agents auto-install dependencies.

Where Input Validation Fails

The vulnerability exists because there is no input validation layer between the LLM’s decision to execute a command and the actual execution. The agent architecture looks like this:

User Prompt → LLM Reasoning → Tool Selection → Command Execution

            External Data (plugins, docs, dependencies)

External data flows directly into the reasoning context. The LLM has no mechanism to distinguish between:

  • Instructions from the user
  • Instructions from plugin documentation
  • Instructions embedded by an attacker

The LLM treats all text in its context window as equally authoritative. If plugin metadata says “run this setup script,” the agent interprets that as a legitimate installation step.

Missing validation layers:

  • No schema enforcement on plugin metadata fields
  • No static analysis of setup scripts before execution
  • No privilege checks before shell command invocation
  • No sandboxing of plugin installation environments

Some agents implement approval prompts for “dangerous” commands (file deletion, network requests), but these are bypassable. The LLM decides what is dangerous based on its training, not a hardcoded policy. Prompt injection can convince the model that a malicious command is safe.

Comparing Agent Execution Models

Different coding agents handle tool execution with varying levels of isolation. None of them solve the fundamental problem, but the failure modes differ.

AgentExecution ModelApproval FlowSandboxPlugin Source
Claude CodeDirect shell accessPrompt for “risky” commandsNoneAnthropic marketplace
GitHub CopilotVSCode extension API + shellUser confirms actionsVSCode process boundaryGitHub marketplace
OpenAI CodexAPI-based tool callsDeveloper implements approvalDepends on integrationNo official marketplace
Gemini CLIDirect shell accessConfigurable approval thresholdNoneGoogle plugin registry
Microsoft CopilotWindows shell + PowerShellPrompt for system changesNoneMicrosoft store

The VSCode extension API provides some isolation for GitHub Copilot, but it still has access to workspace files and can invoke shell commands through the integrated terminal. The “sandbox” is the VSCode process, which runs with full user privileges.

Codex is the most flexible because it does not prescribe an execution model. Developers integrate it into their own tooling and are responsible for implementing privilege boundaries. This shifts the security burden but also allows for proper sandboxing if the developer builds it.

Building Safer Tool Execution Boundaries

Fixing this requires rethinking the agent execution model. The LLM reasoning layer and the tool execution layer need to be separated by a privilege boundary with explicit policy enforcement.

Architectural changes needed:

  • Separate reasoning and execution contexts. The LLM should not have direct shell access. It should emit structured tool calls that are validated and executed by a separate runtime with limited privileges.

  • Schema-based tool validation. Every tool call should conform to a predefined schema. The execution runtime rejects calls that do not match the schema or contain unexpected fields.

  • Capability-based permissions. Tools should declare required capabilities (filesystem access, network access, environment variables). The runtime enforces these capabilities and denies access to undeclared resources.

  • Plugin sandboxing. Plugin installation and execution should happen in isolated environments (containers, VMs, or WASM runtimes) with no access to the developer’s workspace or credentials.

  • Static analysis of plugin code. Before installation, analyze plugin scripts for dangerous patterns (command injection, credential exfiltration, network callbacks). Reject plugins that fail analysis.

Here is a sketch of a safer execution model:

class ToolExecutor:
    def __init__(self, allowed_capabilities):
        self.capabilities = allowed_capabilities
        self.sandbox = Sandbox(capabilities)
    
    def execute(self, tool_call):
        # Validate against schema
        if not self.validate_schema(tool_call):
            raise ValidationError("Tool call does not match schema")
        
        # Check capability requirements
        required_caps = tool_call.get("required_capabilities", [])
        if not all(cap in self.capabilities for cap in required_caps):
            raise PermissionError("Tool requires unavailable capability")
        
        # Execute in sandbox
        result = self.sandbox.run(
            command=tool_call["command"],
            args=tool_call["args"],
            timeout=tool_call.get("timeout", 30)
        )
        
        return result
    
    def validate_schema(self, tool_call):
        schema = self.get_tool_schema(tool_call["tool_name"])
        return jsonschema.validate(tool_call, schema)

This separates the decision to invoke a tool (made by the LLM) from the execution of the tool (handled by a sandboxed runtime). The LLM emits structured tool calls. The executor validates them and enforces capability constraints.

Observability and Audit Trails

Even with better isolation, you need visibility into what agents are doing. Most coding agents provide minimal logging of tool invocations. You cannot easily answer questions like:

  • What commands did the agent execute in the last hour?
  • Which tools accessed environment variables or secrets?
  • Did any plugin make unexpected network requests?
  • What was the reasoning chain that led to a specific command execution?

Observability requirements:

  • Structured logging of all tool calls. Log the tool name, arguments, timestamp, and execution result. Include the LLM’s reasoning trace if available.

  • Audit trail for privilege escalations. Log when a tool requests a capability it was not initially granted. Track approval decisions.

  • Anomaly detection. Flag unusual patterns like plugins making network requests to unknown domains or accessing files outside the project directory.

  • Replay and debugging. Store enough context to replay an agent session and understand why it made specific decisions.

OpenTelemetry can handle most of this if you instrument the agent runtime. Emit spans for each tool call, include relevant attributes (tool name, capabilities, approval status), and send traces to a collector.

from opentelemetry import trace

tracer = trace.get_tracer(__name__)

def execute_tool(tool_call):
    with tracer.start_as_current_span("tool_execution") as span:
        span.set_attribute("tool.name", tool_call["tool_name"])
        span.set_attribute("tool.capabilities", tool_call["required_capabilities"])
        span.set_attribute("tool.approved", tool_call.get("approved", False))
        
        result = executor.execute(tool_call)
        
        span.set_attribute("tool.exit_code", result.exit_code)
        span.set_attribute("tool.output_size", len(result.stdout))
        
        return result

This gives you a queryable audit trail. You can search for all tool executions that accessed secrets, made network requests, or failed validation.

Deployment Considerations

If you are running coding agents in production (CI/CD pipelines, automated code review, infrastructure provisioning), the risk surface is larger. The agent has access to production credentials, deployment keys, and infrastructure APIs.

Deployment hardening:

  • Run agents in ephemeral environments. Spin up a fresh container or VM for each agent session. Destroy it when the session ends. This limits the blast radius if the agent is compromised.

  • Use short-lived credentials. Do not give agents long-lived API keys or SSH keys. Use token vending machines or IAM roles with expiration.

  • Network segmentation. Agents should not have direct access to production networks. Route outbound traffic through a proxy that enforces egress filtering.

  • Least privilege IAM policies. Grant agents only the permissions they need for specific tasks. Use separate IAM roles for different agent workflows.

  • Immutable plugin registries. Do not allow agents to install arbitrary plugins from public marketplaces. Maintain an internal registry of vetted plugins and lock down the agent’s plugin sources.

For CI/CD integration, consider running the agent in a separate build stage with no access to deployment credentials. The agent generates code or configuration, a human reviews it, and a separate deployment pipeline applies the changes.

Technical Verdict

Use coding agents with tool execution capabilities when:

  • You run them in isolated, ephemeral environments with no access to production systems
  • You implement schema validation and capability enforcement for all tool calls
  • You maintain an audit trail of all agent actions and have alerting for anomalies
  • You control the plugin ecosystem and vet all extensions before allowing installation

Avoid coding agents with direct shell access when:

  • They run in your primary development environment with access to SSH keys and cloud credentials
  • They auto-install dependencies or plugins without explicit approval
  • You rely on the LLM’s reasoning to determine what is safe to execute
  • You cannot sandbox plugin installation or tool execution

The Plugin4Shell vulnerability is not a one-off exploit. It is a symptom of a deeper architectural problem. Coding agents blur the line between reasoning and execution, and most implementations do not enforce a privilege boundary between the two. Until agent runtimes adopt capability-based security models and sandboxed execution environments, treat any agent with shell access as a potential RCE vector.

If you are building agentic systems, separate the reasoning layer from the execution layer. Use structured tool calls, enforce schemas, and run tools in isolated environments. Log everything. Assume that any external data (plugins, documentation, API responses) can contain prompt injection payloads. Design your system so that even if the LLM is compromised, the attacker cannot escalate privileges or exfiltrate credentials.