An AI Agent Hacked Snowflake in Five Days. Copilot Reviewed the Vulnerability and Called It Fine.
Wiz’s autonomous Red Agent found, exploited, and debugged its own attack on a 5-day-old Snowflake vulnerability. The PR that introduced it was co-authored by Copilot Autofix — and AI security review passed it.
Five days. That's how long a critical vulnerability in Snowflake's GitHub infrastructure survived before an autonomous AI agent found it, weaponized it, and walked into Snowflake's internal Jira.
Five days is also roughly how long it took you to get around to that PR review sitting in your queue.
Yesterday, Wiz Research published the full story of how their autonomous security agent — a tool called Red Agent — discovered and exploited a script injection bug in one of Snowflake's public repositories. The bug let any GitHub user run arbitrary code inside Snowflake's CI just by opening an issue with a creative title. And the commit that introduced the bug? Its squash commit credits "Copilot Autofix powered by AI" as co-author, and GitHub's AI-assisted security review looked at the change and called it all-clear.
An AI agent attacked. An AI agent defended. Somewhere in the middle, an AI stamped the paperwork. We have officially reached the part of the movie where the humans are mostly spectators.
What actually happened
The setting is snowflake-connector-net, one of Snowflake's official open-source repos. Like every repo on Earth in 2026, it has GitHub Actions workflows, and one of them — jira_issue.yml — does something innocent: when someone opens an issue, it pipes the issue title into a script that creates a corresponding Jira ticket.
Here's the line that mattered:
TITLE=$(echo '${{ github.event.issue.title }}' | sed 's/"/\\"/g' | sed "s/'/\\\'/g")
If you don't read YAML and shell for a living, here's the problem in one sentence: GitHub expands ${{ ... }} expressions before the shell ever sees the script. The sed escaping happens after — which means it's decorative. Anybody who opens an issue with a title containing a single quote breaks out of the echo '...' string and is now typing directly into a shell that runs inside Snowflake's CI runner, holding real credentials.
So: open an issue, put a payload in the title, receive command execution. No login, no exploit chain, no zero-day. Quote injection — a vulnerability class older than most of the people writing YAML today — still happily employed in 2026.
And here's the detail that should genuinely bother you. That injectable line was new. The repo previously had a safe pattern: the issue title went into an env: variable and got built into the Jira payload with jq --arg, which treats it as data instead of code. On June 18, a PR merged that replaced the safe pattern with the direct interpolation. Classic cleanup. Modernizing workflows, replacing deprecated Atlassian actions with direct API calls — the kind of refactor that looks like progress on the diff.
The commit that introduced the vulnerability lists "Copilot Autofix powered by AI" as co-author. GitHub's AI-assisted security review examined the change and found nothing. It was green-lit, merged, and live.
Now, an important fairness note: Wiz later updated their post to clarify that it's unclear whether the bad line itself was AI-written — Copilot co-authored the merged commit and reviewed it as all-clear, but the exact provenance of the change is murky. So don't walk away saying "Copilot wrote a backdoor." Walk away saying something almost as bad: an AI-assisted pipeline produced the change, an AI reviewer passed it, and a human presumably clicked merge on a workflow diff they didn't fully read. The provenance doesn't change the ending.
The guard that guarded nothing
My favorite part of the whole disclosure is this. The workflow had an if: condition that looked protective:
if: (github.event_name == 'issues' && github.event.pull_request.user.login != 'whitesource-for-github-com[bot]')
Looks like it's filtering out bots. Except on issues events, github.event.pull_request is always null. So the condition evaluates to "null != some-bot-account" — which is always true. Every single GitHub user passed the gate. It's a security checkpoint staffed by a mannequin.
This is the kind of bug that's been shipping in CI configs for years. What's changed is how fast it gets found.
The part where the attacker debugs itself
Wiz's Red Agent is an autonomous security researcher — it scans organizations' public attack surface, hypothesizes, tests, and exploits, without a human in the loop. While scanning Snowflake's GitHub org, it flagged the workflow, and here's where the story gets cinematic.
Red Agent's first exploitation attempt failed. It tried to comment out the rest of the shell line with a # character — standard payload hygiene — but the comment swallowed the closing parenthesis of TITLE=$(...), and bash threw a syntax error.
A dumber tool would have retried the same thing louder. Red Agent read the error, understood the syntax it was fighting, rewrote its payload to use ; echo ' to cleanly close the shell block instead, and fired again. Within seconds, Wiz's listener caught an out-of-band callback from a GitHub Actions runner — an Azure IP — carrying base64-encoded Jira credentials out of Snowflake's CI.
The token authenticated as qa@snowflake.net and had read access across Snowflake's engineering, security compliance, and bug bounty tracking projects in Jira. Internal bug reports, security workflows, the works.
Read that sequence again. An AI agent autonomously: found the bug in a public repo, understood template-expansion ordering in GitHub Actions, hit a syntax error mid-exploitation, diagnosed it, fixed its own exploit, and succeeded. No human touch. To be clear — this was authorized research through Snowflake's HackerOne program, disclosed responsibly, and Snowflake patched it the same day it was reported, rotated the token, and confirmed via audit logs that Wiz was the only actor during the exposure window. Nobody got breached. This time.
The uncomfortable math
Let's update our priors with what this incident actually demonstrated.
Discovery windows are collapsing. This bug was live for five days. It was found not by a dedicated pentest or a bounty hunter grinding through workflows, but by an agent scanning an org's attack surface semi-continuously. When discovery is constant and automated, your exposure window is however long it takes an agent to get to your repo on its to-do list. The old model — months or years before someone notices a sloppy workflow — is dead.
AI review is not a security control. GitHub's AI-assisted review examined a change that replaced an injection-safe pattern with a direct injection and rated it fine. This isn't a knock on that specific product — it's a structural truth. AI reviewers (and human reviewers, honestly) evaluate whether code looks right. Security regressions usually look cleaner than the code they replace. The safe version — piping through env: and jq --arg — looks like ceremony. The unsafe version looks like simplification. Review is optimized for clean.
Context loss is the vulnerability. This is the deepest lesson in the whole story, and almost everyone is going to miss it. That env: + jq pattern existed for a reason. Somebody, at some point, either read the GitHub Actions security docs or got burned, and wrote the safe version. Then a modernization PR came through — automate away those deprecated actions, simplify, tidy — and the safe pattern got replaced, because to the author of that PR, human or AI or both, it looked like pointless indirection.
The code said what. Nothing in the repo said why. And when you rewrite code without knowing why it's shaped like that, you reintroduce vulnerabilities that were solved before you were born. This has always been true of junior engineers. It's now true at machine speed, and the machines are doing the rewriting more often than the juniors are.
What you should actually do about it
If you run a repo, or you let agents touch yours (hi), a short, unglamorous list:
- Never interpolate untrusted input into
run:blocks. Issue titles, PR bodies, branch names, comments — all of it is attacker-controlled. Useenv:variables and pass data as arguments. This is in GitHub's own docs, which apparently everyone modernizing workflows skips. - Lint your workflows in CI.
actionlintcatches script injection patterns like this one. A static linter caught in five seconds what an AI reviewer blessed. Think about that ordering. - Treat AI-reviewed code as unreviewed. Copilot Autofix, AI PR summaries, agent-authored commits — all fine, all useful, none of it a substitute for a human or a scanner that understands injection. AI review is a freshness check, not a security gate.
- Make credentials short-lived and scoped. The blast radius here was limited because it was a QA token with read access. Imagine the same workflow with a deploy key or an org-wide admin token. Assume any CI credential will eventually sit in a runner next to attacker-controlled shell.
- Write down why. Commit messages, comments, ADRs — anything that explains why the weird-looking pattern is weird-looking. The next thing to rewrite your repo may not read your mind. It will, however, read your comments. Probably.
The era of agent versus agent
Zoom out and the shape of this story is the shape of the next few years. An AI-assisted pipeline shipped a bug. An AI agent found it, weaponized it, and debugged its own exploit on the fly. A human company scrambled to patch within hours of disclosure because the old "nobody will notice" assumption is gone.
This is the real arrival of the agentic era — not the demos, not the "your AI intern" tweets. Agents that act autonomously in real infrastructure, on both sides, today. Wiz built theirs for defense and authorized testing. The same capability is being built elsewhere for other purposes, and the good ones won't publish blog posts about it.
If you're building with AI agents — and if you're reading this, you probably are — the takeaway isn't fear. It's that the margin for sloppy defaults is gone. Guardrails on what agents can change, linters that don't get tired, credentials that die young, and context written down where machines can find it.
We think about this a lot at CopperRiver, because our product is literally an AI agent with real access — browser, terminal, files. The design answer is the boring stuff above: scoped permissions, read-only mounts for things that shouldn't change, and a human who can see everything the agent did. Not because agents are untrustworthy, but because the Snowflake story is what happens when everyone assumes someone else — or some other AI — checked the diff.
The Snowflake vulnerability lived for five days before an agent found it. The next one might not last the weekend.