Agents are moving into CI/CD quickly: reviewing pull requests, generating tests, triaging failures, updating dependencies, writing release notes, and increasingly proposing and applying fixes. The productivity case is strong.
The security case is uncomfortable, because a pipeline agent sits at the intersection of two things that should never meet: credentials that can modify production, and input that any outsider can submit. A pull request from a fork is attacker-controlled content. If an agent reads it and holds deploy authority, the distance between "someone opened a PR" and "someone deployed code" is one successful injection.
Why the Pull Request Trigger Is the Sharp Edge
Consider a workflow that runs on every pull request, uses an agent to review the diff, and posts a comment. Benign-looking. Now consider what the agent reads: the diff, commit messages, PR title and body, changed file contents, and often the results of running tests. All of it is authored by whoever opened the PR.
If the agent's job also includes anything privileged — pushing a fix commit, updating a status check, calling an internal API, reading a secret to run integration tests — then injected instructions in the PR content have that authority available. And the agent has every reason to read the injected text carefully, because reading the diff is the task.
This is the same structural problem that made pull_request_target-style triggers a known hazard in conventional CI: a workflow that runs with repository secrets in the context of untrusted code. Agents make it worse because the untrusted content is not merely executed — it is interpreted by a system that follows instructions.
The Split-Pipeline Pattern
The controlling principle: untrusted input and privileged credentials must not be in the same job.
Stage one, untrusted, unprivileged. The agent reads the PR content and produces an analysis. No secrets in the environment, no write tokens, no network egress beyond what analysis requires, read-only checkout. Output is a structured artifact — findings, proposed patch, verdict — not an action.
Stage two, privileged, no untrusted input. A separate job consumes the artifact, validates it against a schema, and performs the privileged operation: posting a comment, opening a PR, updating a check. Crucially, this job never reads the original PR content, so injected instructions have no path into it.
The artifact is the boundary, and it has to be a narrow one. If stage one can emit arbitrary text that stage two posts or executes, you have reconnected the two halves. Validate the artifact strictly: enumerated verdicts, bounded field lengths, escaped content, patches applied through a diff tool rather than as shell commands. See insecure output handling.
Identity and Credentials
Give the pipeline agent its own identity. Not the shared CI service account, which typically holds far more authority than any single job needs and makes attribution impossible. A distinct identity per agent purpose, with enumerated permissions.
Short-lived, job-scoped credentials. Minted at job start, expiring at job end, audience-restricted to the specific services the job touches. Workload identity federation is the right mechanism where the CI platform supports it, since it removes stored secrets entirely. See mTLS, SPIFFE, and workload identity for agents.
No secrets available to untrusted jobs, at all. This includes provider API keys. An agent reviewing a PR needs model access, and the way to provide it without exposing a key is to route model calls through an internal gateway that authenticates the job identity and holds the provider key itself. See securing LLM provider API keys.
Separate write authority by target. The agent that comments on PRs should not be able to push to protected branches. The agent that updates dependencies should be able to open a PR and nothing else. Merge authority should not be delegated to an agent at all.
Treat Agent Output as Untrusted Code
An agent that writes code is a code author whose work needs the same controls as any other author's — arguably more, because the volume is higher and the review attention per line is lower.
Human review is required for anything that reaches a protected branch. Agent-authored PRs must not bypass required reviews, and the agent must not be able to approve its own work or another agent's. This is a straightforward separation-of-duty requirement and it is frequently broken by giving the bot account approval rights for convenience.
Provenance on every commit. Agent-authored commits should be identifiable as such — a distinct committer identity, signed with a key belonging to the agent, with the initiating human principal recorded. Without this you cannot answer "how much of this codebase was agent-authored," which is a question you will eventually be asked, by an auditor or after an incident. See post-incident forensics for AI agents.
Dependency changes need extra scrutiny. An agent updating dependencies is making supply-chain decisions. Pin versions, verify signatures and provenance attestations, and diff the lockfile rather than trusting the summary. An injected instruction that adds a malicious package to a dependency file is a high-value attack with a low detection rate, because dependency bumps are reviewed loosely. See securing the agent supply chain.
No agent-initiated changes to the pipeline itself. Workflow definitions, deployment configuration, and branch protection rules are the controls; an agent that can edit them can remove them. This belongs on the prohibited list rather than behind a gate. See excessive agency.
Execution Environment
Pipeline agents typically run code — tests, builds, linters — which means the sandbox concerns apply directly, with a CI-specific twist: build runners are often long-lived, shared between jobs, and hold cached credentials.
- Ephemeral runners. One job, one runner, destroyed after. Shared runners let one job's poisoned cache reach another's build.
- No credentials in the environment for untrusted jobs. Constructed minimal environment, no inherited variables.
- Egress allow-list. Package mirrors and your own services. Not the open internet, which is the exfiltration path for anything the job can read. See SSRF risks in agent tool calls.
- Cache poisoning awareness. Build caches keyed on content an untrusted job can influence are a persistence mechanism. Scope caches so untrusted jobs read but never write shared caches.
- Resource ceilings and timeouts. A pipeline agent in a retry loop is a cost incident with a CI-shaped invoice.
Observability
Pipeline agents produce a high volume of low-attention actions, so the records matter more than usual.
Record, per agent action: the triggering event and its author, the agent identity, the credentials used, the tool calls made, files changed, external calls, and cost. Then alert on: agent actions on workflows triggered by fork PRs (should be none with privileged credentials), writes to protected paths, dependency file modifications, credential usage outside the expected set, and unusual volume.
Rate limits matter too. A pipeline agent triggered per commit on a busy repository can generate substantial spend, and a loop — agent opens PR, PR triggers agent, agent opens PR — is a real failure mode. Cap invocations per repository per hour and exclude agent-authored events from agent triggers. See budget policies and hard spend caps.
Common questions
Can I run an agent on pull requests from forks safely at all?
Yes, with no secrets and no write authority in that job — analysis only, output as an artifact, privileged action in a separate job that does not read the PR. What you cannot do safely is give the fork-triggered job a write token or repository secrets. If your CI platform offers a trigger that provides secrets in the context of fork content, treat using it with an agent as equivalent to running untrusted code with your deploy credentials.
Should agents be allowed to merge their own PRs?
No. Auto-merge on an agent PR removes the only human checkpoint on agent-authored code reaching production. The routine argument for it is dependency bumps, which is exactly where a supply-chain attack would land. If the volume genuinely requires automation, gate on a strong signal — signed provenance, an allow-list of trusted packages, a passing security scan — and keep a human on anything outside that envelope.
How do I handle agents that need production access to debug failures?
Time-bounded, approved, read-only where possible, and heavily recorded — a break-glass path rather than standing authority in the pipeline. An agent that holds production credentials continuously so it can occasionally investigate is a persistent risk in exchange for an occasional convenience. See break-glass and emergency access.
What about coding agents running on developer machines rather than in CI?
Different exposure, similar principles. The developer's machine holds their credentials, SSH keys, and cloud sessions, and a local agent reading a repository is reading content that may have been authored by anyone who can open a PR. Scope what the local agent can reach, keep production credentials out of the local environment, and require review before anything it produces is pushed. See securing AI coding agents.
How Praesidia approaches pipeline agents
Praesidia gives each agent its own identity and enumerated connections, so a pipeline agent's authority is a set of narrow grants rather than an inherited CI service account — and the agent that comments on PRs can be structurally unable to push to a branch. Provider credentials are held at the gateway, so an untrusted job can make model calls by authenticating its own identity without any provider key existing in the runner environment.
Consequential actions can be gated for approval instead of executed inline, spend ceilings are enforced per agent before dispatch so trigger loops cannot run unbounded, and every action is recorded with both the agent and the human who initiated it. See governed agent resource connections and the Praesidia documentation.