Plugin4Shell: a zero-click RCE in AI coding agents — and how to keep your agent's model calls safe
This week security researchers disclosed Plugin4Shell, a zero-click remote-code-execution flaw in the plugin systems of Claude Code, OpenAI Codex, GitHub Copilot and Google's Gemini CLI. The attack does not touch the model — it poisons the marketplace your agent trusts. The fix is architectural: stop pulling untrusted third-party code into your agent, and route every model call through one vetted OpenAI-compatible endpoint instead.
What Plugin4Shell actually is
AI coding agents lean on SHA-pinning to lock a plugin (or "skill") to a specific, immutable commit hash, so a compromised repo cannot silently swap in malicious code. Researchers at the security firm Air found the gap: the agent checks out the pinned commit but never verifies it actually landed there. Whoever controls the plugin's repo can make that checkout resolve to malicious code while the pin still looks honored — and because Claude Code and Codex auto-update installed plugins by default, the result is zero-click RCE. The researchers call it a "first-of-its-kind AI supply-chain attack." Details in plainenglish.io's write-up (Sep 18, 2026) and zeroday.news.
Why a poisoned plugin beats a bad prompt
Prompt injection is contained to the conversation. A poisoned plugin is code running in your process with the agent's permissions — and agents are deliberately given broad filesystem and network access so they are useful. One malicious "skill" can read your .env, exfiltrate keys, or reach anything the agent can reach. The researchers' earlier SkillJacking and RepoJacking proofs showed this at scale: in one test a benign-looking plugin infected 134,000 agents across 925 hijacked repositories. The blast radius is your whole machine, not one chat.
The concern is not isolated to one vendor. A wave of reporting this week (plainenglish.io, The Hacker News) framed AI-agent plugins as a mainstream supply-chain attack surface: an independent report tallied roughly 17,800 public AI add-ons across about 6.7 million installations that pull instructions from unverified external sources and impersonate legitimate Anthropic and OpenAI skills to run arbitrary code. No single marketplace can fully secure it.
The reflex that makes it worse
The convenience pattern — "add this MCP server / skill from the marketplace, turn on auto-update" — is exactly the delivery mechanism. SHA-pinning was supposed to stop it; Plugin4Shell defeats the verification. Vendor patches are uneven: Anthropic fixed Claude Code in 2.1.179 and OpenAI fixed Codex in 0.146.0, but Google deprecated Gemini CLI entirely and Microsoft's Copilot remained unpatched at disclosure. Patching the agent helps, but it does not change the underlying habit of trusting third-party code.
The architectural fix: don't run code you didn't write
You do not need a marketplace to give your agent capabilities. Define the tools in your own codebase, under your own review, and let the agent call them. The only external surface your agent touches is a single, narrow, auditable HTTP API for model inference. No third-party package executes in your environment, so there is nothing for a poisoned "skill" to replace.
One vetted endpoint, your own keys
TideLink aggregates 30+ models — China flagships like GLM, Qwen, DeepSeek and Hunyuan, plus the Western models you bring through BYOK — behind one OpenAI-compatible endpoint at https://tidelink.xyz/v1. You call /v1/chat/completions with one API key. Your provider keys stay yours (BYOK means the gateway routes, it never stores your upstream credentials in your app); the gateway is a stateless router, not a code executor. GET /v1/models returns the live catalog.
Drop-in: an agent loop with no third-party plugins
The tool is defined in your code. The only network call leaves for one endpoint:
import json
from openai import OpenAI
client = OpenAI(
base_url="https://tidelink.xyz/v1",
api_key="YOUR_TIDELINK_KEY",
)
# Tools live in YOUR code — never pulled from a marketplace.
def get_weather(city: str) -> str:
return json.dumps({"city": city, "temp_c": 21})
TOOLS = [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Current weather for a city",
"parameters": {"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"]},
},
}]
messages = [{"role": "user", "content": "Weather in Berlin?"}]
while True:
r = client.chat.completions.create(
model="glm-5.3-flash", messages=messages, tools=TOOLS)
msg = r.choices[0].message
if not msg.tool_calls:
print(msg.content)
break
for call in msg.tool_calls: # runs YOUR function, locally
result = get_weather(**json.loads(call.function.arguments))
messages += [msg, {"role": "tool",
"name": call.function.name, "content": result}]
# Same client, Western model via BYOK — one line to switch:
# model="gpt-6-astra" # your OpenAI key, brought through BYOK
Hardening checklist
| Risk | Control |
|---|---|
| Untrusted plugin code in your process | Define tools in your code; route model calls through one endpoint. No marketplace packages. |
| Stolen provider keys | Bring your own keys (BYOK); the gateway routes, your app never holds upstream secrets. |
| One dead upstream = 5xx | Gateway failover routes to the next healthy model, same client shape. |
| Over-broad agent permissions | Run the agent in a sandbox; least-privilege on credentials; rotate keys; log every call. |
Even with a gateway, treat the agent like a production service account: sandbox it, scope its filesystem and network, and rotate keys. The endpoint narrows the attack surface; it does not remove the need for least privilege.
Failover without the supply chain
When one upstream degrades, the gateway routes the same request to the next healthy model — Qwen, DeepSeek, Hunyuan — with the same client and response shape. Your users see a slower answer, not a 5xx, and you never had to install a plugin to get there.
TideLink · TideLink is operated by Yuncheng Yanhu Beicheng Chaoxi Network Technology Studio, a sole proprietorship registered in Yuncheng, China (Unified Social Credit Code 92140802MAKM59LT6K), providing software development and IT integration services. Not a resale of third-party credentials.
All guides
Get a free TideLink API key — call GLM, Qwen, DeepSeek and more through one OpenAI-compatible endpoint: https://tidelink.xyz/dashboard.html?cid=devto
Top comments (0)