On May 16, 2026, Grafana Labs disclosed that an attacker downloaded their entire private codebase using a stolen GitHub token. Here's exactly how the attack worked and how to protect your own CI/CD pipelines from the same vector.
On May 16, 2026, Grafana Labs — the company behind the widely used open-source observability and monitoring platform — disclosed a significant security incident. An attacker had obtained a privileged GitHub token that granted access to their GitHub environment and subsequently downloaded the company's entire private codebase.
The disclosure sent shockwaves through the developer community. Grafana powers dashboards for over 7,000 organizations, including 70% of the Fortune 50. While the company confirmed that no customer data or personal information was exposed, the incident raises critical questions about GitHub token security that every web developer should be asking about their own projects.
The breach was discovered when one of Grafana's thousands of deployed canary tokens — digital tripwires that look like real credentials — was triggered. That alert immediately notified their security team that someone was inside their environment. By then, the attacker had already downloaded the full codebase.
Disclosed: May 16, 2026
Attack vector: Pwn Request via misconfigured pull_request_target GitHub Action
What was taken: Entire private codebase downloaded
Ransom demanded: Yes — Grafana refused to pay
Alleged group: CoinbaseCartel
Customer data exposed: No
Status: Contained — credentials invalidated, additional security measures implemented
The attack exploited a well-known but frequently misconfigured GitHub Actions trigger called
pull_request_target. Understanding this vulnerability is critical
because it's the same class of misconfiguration that led to the npm supply chain attacks in the
Mini Shai-Hulud incident — and countless other breaches.
GitHub Actions offers two ways to run workflows on pull requests:
pull_request runs the workflow in the context of the forked repository.
It has no access to the target repository's secrets. This is the safe default — a malicious
PR author cannot steal secrets because the workflow runs in an isolated environment.
pull_request_target runs the workflow in the context of the target repository.
It has full access to the repository's secrets: GitHub tokens, cloud credentials, API keys, and
everything else in the Actions secrets store. This trigger is designed for workflows that need
to comment on PRs, label issues, or perform other actions that require write access to the
repository.
The danger arises when a pull_request_target workflow checks out the PR code and
executes scripts from it. Because the workflow runs in the target repository's context, any
malicious code in the PR has access to all secrets.
Here's the vulnerable pattern that attackers look for:
# VULNERABLE — never do this
name: PR Workflow
on:
pull_request_target:
types: [opened, synchronize]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }} # ❌ Checks out PR code
- name: Run CI
run: |
npm ci
npm test # ❌ PR author controls what runs here
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # ❌ Exposed to untrusted code
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_KEY }} # ❌ Cloud credentials exposed
The attacker submits a PR with malicious code in package.json scripts or a CI
configuration that exfiltrates environment variables. When the workflow triggers on
pull_request_target, it checks out the attacker's code, runs it, and the
attacker receives the secrets.
Based on the StepSecurity analysis of the April 2025 Grafana incident (which used a similar vector) and the May 2026 disclosure, the attack chain likely followed this pattern:
pull_request_target workflow that checked out PR code and executed scripts from it.pull_request_target workflow automatically triggered on the PR, running in the context of the target repository with access to its secrets.GITHUB_TOKEN and any other accessible secrets from the runner environment.
The pull_request_target trigger is not unsafe by itself — it becomes
dangerous only when combined with checking out and executing untrusted PR code. If your workflow
needs pull_request_target, never execute untrusted code from the
PR in the workflow body. Use separate jobs, artifact uploads from pull_request, or
require manual approval before running external code.
The extortion group claiming responsibility for the Grafana attack, CoinbaseCartel, emerged in September 2025. According to threat intelligence researchers, they appear to consist of affiliates from ShinyHunters and Lapsus$ — two well-known cybercriminal groups.
CoinbaseCartel operates a data leak site (DLS) where they list victims and threaten to publish stolen data if ransoms aren't paid. They have listed over 100 victims on their portal and are reportedly "behind on many leaks" — suggesting their breach activity exceeds what has been publicly disclosed.
The group's primary attack vectors include:
Grafana Labs publicly refused to pay the ransom, citing the FBI's official stance on ransom payments. In their statement, the company said:
"Based on our operational experience and the published stance of the FBI, which notes that paying a ransom doesn't guarantee you or your organization will get any data back and only offers an incentive for others to get involved in this type of illegal activity, we've determined the appropriate path forward is not to pay the ransom."
This is a meaningful precedent. A major open-source infrastructure company, responsible for tools used by 70% of Fortune 50 companies, chose the hard but principled path. It sends a clear signal to attackers that codebase extortion won't be rewarded.
The Grafana breach isn't an exotic zero-day — it exploited a configuration error that thousands of repositories have. Here's a practical defense strategy for every developer and team.
Run this audit on every workflow file in your repository:
# Find all pull_request_target usage
grep -rn "pull_request_target" .github/workflows/
For each result:
pull_request — it runs in the fork's context with no secret accesspull_request_target, never check out PR code:# SAFE — never checks out or executes PR code
name: PR Labeler
on:
pull_request_target:
types: [opened, labeled]
jobs:
label:
runs-on: ubuntu-latest
steps:
- uses: actions/labeler@v5
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
Note how this workflow doesn't run actions/checkout, doesn't execute scripts from
the PR, and only uses well-known GitHub Actions. This is the only safe pattern for
pull_request_target.
GitHub deprecated classic tokens with full repo scope in 2025. If you're still
using them, switch to fine-grained tokens (FGPATs) immediately:
Every workflow job should request the minimum permissions it needs:
name: Secure Workflow
on:
push:
branches: [main]
# Explicitly declare minimum permissions
permissions:
contents: read
issues: none
pull-requests: none
checks: write
packages: none
jobs:
test:
runs-on: ubuntu-latest
permissions:
contents: read # Narrower than the job default
steps:
- uses: actions/checkout@v4
- run: npm ci && npm test
Use permissions: read-all at the top level and only elevate specific jobs that
need write access. This limits the blast radius if a workflow is compromised.
Instead of storing long-lived AWS, Azure, or GCP credentials in GitHub Secrets, use OpenID Connect (OIDC) to generate short-lived tokens per workflow run:
name: Deploy with OIDC
on:
push:
branches: [main]
permissions:
id-token: write # Required for OIDC
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/GitHubActionsDeployRole
aws-region: us-east-1
- name: Deploy
run: aws s3 sync ./build s3://my-bucket
OIDC tokens are valid only for the duration of the workflow run and are automatically revoked when the job completes. This eliminates the risk of a long-lived cloud credential being exfiltrated.
In your repository settings, enable "Require approval for all external contributors":
If you suspect any token has been compromised — whether from a CI/CD incident, a developer machine compromise (like the Mini Shai-Hulud npm attack), or a warning from a secret scanning tool — follow this checklist:
The Grafana breach is not an isolated incident. It's part of a broader trend where attackers target the CI/CD pipeline itself as the attack vector. The Mini Shai-Hulud npm supply chain attack — which compromised 170+ npm packages including TanStack, Mistral AI, and UiPath — used a different entry point (npm install scripts) but targeted the same thing: credentials accessible in CI/CD environments.
For a deeper look at how supply chain attacks work at the npm level, including the technical breakdown of the preinstall hooks, Bun bootstrapper, and credential theft mechanisms, see my complete guide: Mini Shai-Hulud: The npm Supply Chain Attack Explained.
Together, these incidents tell a clear story: CI/CD pipelines are the new perimeter. Whether through compromised npm packages or misconfigured GitHub Actions workflows, attackers are increasingly targeting the automation infrastructure that developers trust implicitly.
If you're a developer or a business owner hiring one, the Grafana breach underscores a critical shift in security priorities. Here's what you need to carry forward:
pull_request_target trigger is a potential liability. Review every one.When hiring a web developer or agency, CI/CD security should be part of the conversation. Ask about their approach to:
When I build web applications for clients, CI/CD security is baked into the delivery process from day one — properly scoped tokens, audited workflow triggers, OIDC for cloud deployments, and regular security reviews. If you're looking for a developer who takes pipeline security seriously, let's talk.
pull_request_target GitHub Action workflow (a Pwn Request vulnerability), which allowed the attacker to steal a privileged token. No customer data or personal information was exposed.pull_request_target GitHub Action in a public repository. When a workflow uses pull_request_target with a script that evaluates code from the PR, the workflow runs in the context of the target repository with access to its secrets. The attacker submitted a malicious pull request that triggered the workflow and extracted the GitHub token from the runner environment.pull_request_target triggers — use pull_request instead. If pull_request_target is unavoidable, never checkout and execute code from the forked repository. Use OIDC for cloud deployments instead of storing long-lived credentials. Rotate tokens regularly. Enable GitHub Advanced Security for secret scanning. For more on securing your web application ecosystem, see my guide on npm supply chain attack prevention.pull_request_target trigger in GitHub Actions. Unlike pull_request (which runs in the fork's context), pull_request_target runs in the context of the target repository with full access to its secrets. If the workflow checks out PR code and executes scripts from it, a malicious PR author can inject arbitrary code that has access to the repository's secrets — including GitHub tokens and cloud credentials.The Grafana GitHub breach is a wake-up call for the entire development ecosystem. CI/CD pipeline security is no longer optional — it's a foundational requirement for any serious web development project. A single misconfigured workflow trigger can expose your entire codebase, and the tools to prevent this are free and well-documented.
If you're building a web application and want a developer who treats CI/CD security as a first-class concern — not an afterthought — reach out to me. I'm a full-stack developer with 20+ years of experience, and I build every project with hardened CI/CD pipelines: properly scoped tokens, audited workflow triggers, OIDC for cloud deployments, and regular security reviews baked into the process.
Have a project in mind? I'll help you choose a secure, modern tech stack and build it right. Free initial consultation.