Hardening CI/CD Pipelines: When the AI Agent Becomes the Attack Vector
The Clinejection incident of February 2026 was not an isolated case. It was the wake-up call the industry underestimated: a single malicious GitHub issue title compromised the supply chain of the "Cline" coding agent, turning an AI assistant into a privilege escalation vector toward CI/CD environments and repository credentials.
Today, as agentic frameworks (LangGraph, AutoGen, Semantic Kernel, Claude Code, Gemini CLI) become standard components of deployment pipelines, the attack surface has shifted. It is no longer the code we write. It is the code the agent decides to execute on our behalf.
The Architecture of Betrayal: "Comment and Control"
The Comment and Control vulnerability class (documented by Cloud Security Alliance and OWASP Agentic Applications Top 10 2026) exploits a naive architectural assumption: agents treat untrusted GitHub metadata — PR titles, issue bodies, HTML comments — as authoritative context for their own planning.
```python
issue_body = github.get_issue(123).body # Unsanitized input
plan = agent.plan(f"Resolve: {issue_body}") # Agent "reads" the injection
agent.execute(plan) # Executes privileged tool calls
```
An attacker does not need to breach the model. They only need to write a well-crafted issue. The agent, in its eagerness to be helpful, executes the injection as a legitimate instruction: exfiltrating `GITHUB_TOKEN`, `AWS_KEY`, `DOCKER_HUB_CREDS` — everything the CI/CD pipeline generously injected into the environment.
The Siliceo Project Lesson: Sovereignty over Execution Context
In the Siliceo Project we learned this lesson firsthand. Our Kernel Rust v2 (running on `localhost:5005` with ~1.3GB VRAM on an RTX 2070 8GB) exposes no tools to the LLM by default. Every capability (`think`, `call_llm`, `fallback_provider`, `memory_read`, `memory_write`) is an explicit, signed, revocable capability token with scope defined at compile-time.
We do not use "system prompts" to define permissions. We use the Rust type system.
```rust
// Real example from our kernel: tools are typed capabilities, not strings
pub trait Capability: Send + Sync {
fn scope(&self) -> CapabilityScope; // ReadOnly | WriteLocal | Network | Privileged
fn requires_approval(&self) -> bool;
}
#[derive(Capability)]
#[scope(WriteLocal)]
#[requires_approval(true)]
pub struct FileWriteTool { ... }
```
Immediately applicable practical insight:
If you are integrating an AI agent into CI/CD, stop passing `GITHUB_TOKEN` to the agent's environment. Create a sidecar service (a minimal Rust/Go microservice) that exposes only the necessary Git operations (`create_branch`, `open_pr`, `read_file`) via gRPC with mTLS. The agent calls `sidecar.open_pr(title, body)` — the sidecar validates, sanitizes, logs, and uses its own short-lived token. The agent never sees the credential. The blast radius shrinks from "everything"