Logan Kelly

A Snowflake CI/CD Flaw Was Live for Five Days — Then an Autonomous Agent Found It

A Snowflake CI/CD Flaw Was Live for Five Days — Then an Autonomous Agent Found It

A Snowflake CI/CD flaw leaked a Jira token to an autonomous agent in 5 days. How to gate the write-path tool calls AI agents make.

Waxell blog cover: an autonomous agent exploited a CI/CD flaw live for five days

On August 17, 2026, Wiz Research disclosed that its autonomous security tool, "Red Agent," found and exploited a script-injection vulnerability in one of Snowflake's public repositories — snowflakedb/snowflake-connector-net, the .NET data connector — and used it to exfiltrate a live Jira API token from a GitHub Actions runner. The vulnerability became live on June 18, 2026, when a pull request was merged, and Red Agent discovered it five days later. That five-day gap is the whole story.

Script injection in CI/CD is what happens when a workflow drops attacker-controllable text — here, the title of a GitHub issue — directly into a shell command. Because the workflow triggered on issues: opened, any account on the internet could fire it, unauthenticated, just by opening an issue with a crafted title.

The affected workflow, jira_issue.yml, interpolated ${{ github.event.issue.title }} straight into a run: block. A guard condition looked protective but compared a pull-request field that is null on issue events, so it always evaluated true and every user passed it. Red Agent's first exfiltration payload threw a bash syntax error; the agent read the error output, rewrote the payload to close the shell block cleanly, and succeeded on the retry. Within seconds, a callback arrived from an Azure-hosted runner carrying a base64-encoded token that authenticated as qa@snowflake.net with read access across Snowflake's engineering, security-compliance and bug-bounty Jira projects. After Wiz reported the flaw on June 23 through Snowflake's HackerOne program, Snowflake patched it the same day and rotated the token the next; its audit logs showed Wiz was the only actor during the window. No harm resulted.

One widely repeated claim did not survive the day. Wiz initially framed the vulnerable code as written by GitHub's Copilot Autofix. GitHub ran an internal review and rejected that framing: it says a human wrote the contributions that led to the vulnerability, and that Copilot Autofix neither reviewed nor contributed to them. Wiz's updated post places Copilot Autofix's documented contribution in a different file in the same pull request, and still says Copilot checked the merged change and called it clear — which is the half GitHub disputes. Wiz updated its post the same evening to say it is "unclear whether the code-change was AI-assisted," and The Register corrected its headline. The AI-authorship angle came apart; the autonomous-exploitation half held up.

Why does script injection keep reaching production?

The mechanism is old and the fix is documented, which makes its recurrence the interesting part. GitHub's own Actions security guidance names the exact remedy: pass untrusted input through an intermediate env: variable rather than interpolating it into the shell, so the template engine never gets to build a command out of it. Wiz publishes the diff: the safe pattern — env: plus jq --arg — was present in this workflow before the merge and gone after it. Security intent was there, then a refactor removed it, and, on Wiz's account, GitHub Advanced Security analysed the final revision including the vulnerable workflow and did not flag the injection.

That is the structural gap, and it is framework-agnostic: defensive patterns encode why, and edits routinely preserve what the code does while dropping the why. Whoever or whatever authored the change, the review step is where a removed sanitizer is supposed to be caught, and it was not. The pull request merged with a green check.

The second structural shift is on the attacker's side, and it is what makes the first one urgent. Wiz's own takeaway is that discovery windows are collapsing — that security operations now have to plan for automated discovery in hours rather than weeks. Five days, here, with no human at the keyboard on the offensive side — the agent scanned, built an exploit, hit an error, diagnosed it against live output, and self-corrected. A defensive assumption that a freshly introduced CI flaw has weeks of obscurity before anyone probes it is no longer safe. Here, discovery was automated and review was not.

What should teams check now?

First, close the specific hole. Route every use of untrusted input — issue titles, PR titles, branch names, commit messages — through an intermediate environment variable, never a direct ${{ }} interpolation inside a run: block. This is GitHub's documented recommendation, and it is a mechanical change.

Second, shorten credential lifetimes to match automated discovery speeds. A token that lives for months is a token an agent has time to find and use; short-lived, least-privilege credentials shrink the blast radius of any single leaked workflow.

Third, treat AI-authored and AI-assisted changes to CI as changes that need the same scrutiny as any other — because the review step, not the suggestion, is where this class of regression gets through. Put workflow files behind CODEOWNERS so a designated reviewer signs off on changes to .github/workflows, and enable code scanning that specifically covers Actions.

Fourth, ask a harder question about your agents: when an agent takes a write-path action — merging a PR, calling an internal API, touching a ticketing system — is that action gated and recorded, or does it just happen? The exploited path here was a CI runner, not an agent tool call. But the direction of travel is agents performing exactly these actions through tools, and the governance question is the same either way.

How Waxell handles the adjacent problem

Be precise about what Waxell would and would not have done here. The exploited path was a GitHub Actions runner executing a shell command — not an MCP tool call — so nothing in Waxell's product line sits on that path, and it would not have blocked this injection or this exfiltration. Repo-side controls — the env: pattern, branch protection, CODEOWNERS, short-lived tokens — are what close this specific incident.

What Waxell does govern is the adjacent and growing surface: the tool calls that AI agents make. When a coding or assistant agent performs a write-path action through an MCP tool — merging a pull request, posting to a ticketing system, calling an internal API — the Waxell MCP Gateway evaluates that call against your tenant's policy rules before the upstream ever sees it, and again on the result. A call that requires approval is parked rather than dropped: the gateway holds the connection open so the agent does not time out, a reviewer approves and the call resumes, or denies and the agent receives a structured error it can recover from — the same human-in-the-loop pattern that has to survive approval fatigue to be real. Every brokered call is resolved to a real user identity, and the audit log records the call, the decision, and the rules that fired — payload-free, durable for years, exportable to CSV. Policy rule changes propagate within 30 seconds.

Two scope limits the incident makes worth stating plainly. The gateway governs calls that traverse it; an agent holding a direct upstream credential, or a process running inside a CI runner, is outside that path. And the gateway does not judge whether an action is safe — it enforces that a call requiring approval waits for a recorded human decision, and leaves an attributed record that it did. For agents you build in Python, Waxell Observe applies related policy logic inside the run, so a low-confidence or out-of-policy step can be escalated before the next one executes rather than examined afterward.

The value is not detection of this bug. It is that when the write-path action runs through a governed tool call, "which agent did this, under what policy, and who approved it" has an answer — the same kind of answer Snowflake's audit logs gave it here, scoped to the calls that agents make.

FAQ

What was the Snowflake CI/CD vulnerability?

A GitHub Actions workflow, jira_issue.yml, in the public snowflakedb/snowflake-connector-net repository interpolated the title of a GitHub issue directly into a shell command. Because the workflow triggered whenever anyone opened an issue, any unauthenticated user could execute arbitrary commands on the runner with a crafted title. Wiz's autonomous Red Agent used it to exfiltrate a Jira API token.

Did GitHub Copilot write the vulnerable code?

That claim was walked back. Wiz initially attributed the vulnerable change to Copilot Autofix, but GitHub ran an internal review and says a human wrote the contributions that led to the vulnerability and that Copilot Autofix neither reviewed nor contributed to them. Wiz's updated post places Copilot Autofix's documented contribution in a different file in the same pull request. Wiz updated its post to say it is unclear whether the change was AI-assisted. What is not disputed is that an autonomous AI agent found and exploited the flaw.

How long was the vulnerability exposed?

Five days. The injectable pattern went live when the pull request merged on June 18, 2026, and Wiz's Red Agent discovered and reported it on June 23. Snowflake patched it the same day it was reported and rotated the affected token the following day.

What is the recommended fix for script injection in GitHub Actions?

GitHub's own guidance is to pass untrusted input through an intermediate env: variable instead of interpolating it directly into a run: block, so the value is handled as data rather than used to build a shell command. Pairing that with least-privilege, short-lived tokens and CODEOWNERS review on workflow files closes the common paths.

Would Waxell have prevented this incident?

No. The exploited path was a CI runner executing a shell command, which is not an MCP tool call and does not traverse Waxell's gateway; repo-side controls are what close this incident. Waxell governs a different surface — the tool calls agents make — where the MCP Gateway can gate a write-path call behind an approval policy and keep an attributed audit record of it.

Sources

The five-day window is an argument for governing what agents do, not just what they suggest. Start free with the Waxell MCP Gateway — one governed endpoint, with approval policies and an attributed audit log on the tool calls your agents already make.

Waxell

Waxell provides observability and governance for AI agents in production. Bring your own framework.

Compliance — NIST AI RMF · EU AI Act · SOC 2 Type II (in progress) · HIPAA (in progress)

Governed continuously in Vanta.

© 2026 Waxell. All rights reserved.

Patent Pending.

Waxell

Waxell provides observability and governance for AI agents in production. Bring your own framework.

Compliance — NIST AI RMF · EU AI Act · SOC 2 Type II (in progress) · HIPAA (in progress)

Governed continuously in Vanta.

© 2026 Waxell. All rights reserved.

Patent Pending.

Waxell

Waxell provides observability and governance for AI agents in production. Bring your own framework.

Compliance — NIST AI RMF · EU AI Act · SOC 2 Type II (in progress) · HIPAA (in progress)

Governed continuously in Vanta.

© 2026 Waxell. All rights reserved.

Patent Pending.