On June 18, a pull request landed on the default branch of snowflakedb/snowflake-connector-net. It touched a small housekeeping workflow — the one that opens a Jira ticket whenever somebody files a GitHub issue. Five days later, an autonomous security agent had found the bug that PR introduced, written a working exploit for it, stolen the credential the workflow was carrying, and used that credential to read Snowflake's internal Jira.
No human was in the loop for any of that until the disclosure email.
The details are now public in Wiz's write-up, and they are worth reading closely, because almost every part of this incident is a preview of how software defects will be found from here on. But the lesson people are taking from it — review your AI-generated code more carefully — is the smallest one available. The bug was ordinary. What made it interesting was the credential sitting next to it, and how little time anyone had to notice.
The workflow interpolated an untrusted GitHub issue title straight into a shell command:
run: TITLE=$(echo '${{ github.event.issue.title }}' | sed ...)
That is the canonical GitHub Actions script injection. A single quote in an issue title closes the echo, and everything after it runs on the runner. Anyone with a GitHub account could file an issue; no fork, no PR, no approval step.
There was a guard on the job. It checked github.event.pull_request.user.login — a field that does not exist on an issue event. It evaluated to empty, and the gate stood open on every single issue. This is the failure mode that makes CI conditionals so treacherous: a security check written against the wrong event type does not error, it just silently passes forever. The workflow had previously used the safe pattern — environment variables and jq --arg — and the change regressed away from it.
Two automated reviewers looked at that code and cleared it. GitHub Advanced Security did not flag the injection. Copilot, listed as a co-author on the squash merge, marked the change all-clear. GitHub has since disputed the attribution — its position is that the vulnerable lines were written by a human contributor and folded into a squash commit that named Copilot as co-author, not generated by Copilot. That correction matters for the headline and changes nothing about the outcome: the code shipped, and the automated review layer that was supposed to be the backstop passed it.
Wiz's Red Agent found the flaw on June 23 — five days after it reached the default branch. It did not just spot it. It built the payload, hit a bash EOF error when its first # comment terminator broke the syntax, adapted to ; echo ' to close the quoting cleanly, exfiltrated the token over an out-of-band DNS callback, then authenticated to snowflakecomputing.atlassian.net as [email protected] and confirmed read access across engineering, security compliance and bug bounty projects. That is a full chain: discovery, exploit development, failure, adaptation, credential theft, lateral validation, blast-radius assessment.
Snowflake's response was the good half of the story. Reported June 23 through HackerOne, fixed the same day, token rotated June 24. And then the part that most organisations could not have done: Snowflake went to its audit logs and verified that Wiz was the only actor during the five-day window.
Hold that against yesterday's Clop story, where 43 organisations are currently unable to confirm or deny what an extortion crew claims to have taken from them. Same underlying question — what actually happened in our environment during a window we did not know was open? — and two completely different outcomes, decided entirely by whether the logs existed before anyone needed them.
We wrote last week that the exploit window has collapsed to days for internet-facing infrastructure. This is the same collapse arriving somewhere less defended: not a KEV-listed CVE with a vendor advisory and a patch cycle, but a five-day-old commit in a public repo that nobody had scored, ticketed, or announced. There is no advisory to subscribe to for your own merge commits.
This is the part that should stop people scrolling. According to Datadog's 2026 State of DevSecOps, 38% of organisations have at least one GitHub Actions workflow vulnerable to script injection or a dangerous trigger, two in three carry at least one critical flaw in their actions or workflows, and 71% never pin an action to a SHA. GitHub Actions runs more than five million workflows a day.
So the population is: a third of all organisations, holding live credentials, in files that are typically reviewed with less rigour than application code because they are "just CI". Snowflake's distinction is not that it had the bug. It is that the finder filed a HackerOne report instead of selling the access.
And the CI runner is only one instance of the broader pattern. Machine identities now outnumber human ones 109 to 1 in the average enterprise, up from 82:1 a year earlier, per Palo Alto Networks' 2026 Identity Security Landscape — and roughly 79 of every 109 are AI agents. Every one of those is a workload holding a credential, taking actions, and in most organisations answering to no owner, no policy, and no inventory.
Reorder the defences by how much they actually changed the outcome here, and the ranking is uncomfortable:
Code review — did not work. Two automated reviewers cleared it. A human reviewer would probably have cleared it too; the diff looks like a refactor.
Detection — too slow to matter. The window was five days, in a public repo, on a workflow nobody monitors. Even a perfect alerting pipeline gives you a finding after the runner has already executed the attacker's command.
Blast radius — this is the one. The injection was a foothold. What turned it into an incident was that the runner held a Jira token authenticated as a service account with read access across engineering, compliance and bug bounty projects. A credential scoped to create one ticket in one project would have made the same exploit a footnote.
Evidence — this is what closed it. Snowflake could state, factually, that nothing else touched that token. That statement is the difference between a resolved report and an open-ended investigation.
Two of those four are properties of the credential and its record, not of the code. That is the shift worth internalising: when discovery is automated and the window is measured in days, you stop winning by finding bugs faster than the other side and start winning by making sure the thing an attacker reaches at the end of the chain cannot do very much, and leaves a trail when it tries.
An agent with tool access is a new kind of insider. It authenticates as a service account, acts continuously, and — unlike a human insider — nobody offboards it. Obiguard Governance AI is built to give that population the three things it is usually missing.
An inventory with an owner. Every AI agent and tool-call is registered in a living inventory with a named owner, a business function, and an assigned Policy Set. The reason the Snowflake token was interesting was that it belonged to [email protected] — a QA service identity with reach into security compliance and bug bounty projects. That kind of scope creep is invisible without a register; it is obvious in a review with a name attached to it. Agent governance is the specific use case here.
Scope bound at the credential, not the code. Allow-lists bind each credential to specific model IDs, tools, external domains and invoking identities. The two moves that would have contained this exploit are both allow-list decisions: constrain what the identity can reach, and constrain where it can talk to — an out-of-band DNS callback to an unrecognised listener is not a subtle signal if egress is enumerated rather than open.
Policy that changes without a redeploy, and off-scope behaviour that gets seen. Change a Policy Set once and every instance of that agent updates immediately — which matters when your response window is hours, and shipping a fix means a release train. Tool calls or outputs outside an agent's intended scope route to a Review Queue for human judgment before they cause damage, and the audit ledger keeps an immutable per-call record of the prompt, the response, every tool call, the model, the agent ID and the initiating identity. That ledger is the artefact that let Snowflake say "it was only Wiz" — reconstructed for agents rather than for CI runners.
For the repository half of this — the workflow file that carried the bug for five days — Obiguard SOC scans every connected repo on each push and once daily, and cross-checks findings against CISA KEV and FIRST.org EPSS so exposure surfaces against your estate rather than in a newsletter.
The uncomfortable thing about this incident is that Snowflake did nearly everything right after the fact and still lost five days to an adversary that never slept, never got bored, and adapted its payload when the first one failed. That adversary happened to be a research bot with a disclosure policy. The next one will not be. Bound the credential, register the agent, keep the record. Explore Governance AI or talk to us about what your CI and agent identities are currently allowed to reach.
Obiguard sits in front of every AI request your organization makes — screening prompts and outputs against the guardrails, compliance frameworks, and audit trails that stories like this one make necessary.
See how it works →