Threat Analysis

The Vercel April 2026 breach, read as a campaign

A third-party OAuth grant, a Roblox cheat, and an infostealer two vendors upstream — the same structural pattern that produced Salesloft / Drift in August 2025.

SR
Setu Research
April 23, 2026·11 min read

The Vercel April 2026 breach, read as a campaign

On April 19, 2026, Vercel published the first IOC for an incident that, by the company's own description, was run by an attacker "highly sophisticated based on their operational velocity and in-depth understanding of Vercel's product API surface." Over the following four days the bulletin was updated six times, and follow-on reporting filled in the pieces of the chain that the bulletin itself did not name.

This is a clean specimen of the attack class that defeats event-level detection. Every individual step in Vercel's own environment was a valid API call by a valid principal holding a valid token. The actual origin of the breach sat two vendors upstream and two months back in time. The only signal was structure — a sequence of privilege hops across trust boundaries, ending in a bulk secret-read against the product API at a tempo no human operator would match.

It is also the second time in nine months that this same structural pattern has produced a major disclosure. In August 2025, UNC6395 stole OAuth tokens that Salesloft's Drift integration held on behalf of its customers, and used those tokens to exfiltrate data from more than 700 downstream Salesforce tenancies, including Cloudflare, Google, PagerDuty, Palo Alto Networks, Proofpoint, Tanium, and Zscaler. Same shape: vendor compromise, token inheritance, bulk automated reads at a tempo no human operator would match, credential harvesting as the objective. Different scale, same structure.

This post walks the Vercel chain as now publicly known, shows which of Setu's detection surfaces would have fired and in what order, and then returns to Salesloft / Drift to show that the same surfaces fire on the same signals against the earlier incident. It is also honest about the part of both chains that Setu cannot see.

The chain, as publicly reconstructed

Six steps, of which only the last three happen inside Vercel:

Vercel / Context.ai OAuth breach chain — pre-existing OAuth grant meets February 2026 infostealer, disclosed April 2026
Vercel / Context.ai OAuth breach chain — pre-existing OAuth grant meets February 2026 infostealer, disclosed April 2026

StepWhereWhat happened
1Vercel employee's browser (months prior)Employee signs up for Context.ai's AI Office Suite and grants the "Allow All" OAuth scope against Google Workspace
2Context.ai employee's laptop (Feb 2026)Context.ai employee downloads a Roblox auto-farm cheat
3Context.ai employee's laptop (Feb 2026)The cheat is a wrapper for Lumma Stealer, which harvests the OAuth tokens Context.ai holds on behalf of its users — including the Vercel employee's
4Google Workspace (April 2026)Attacker uses the inherited token to take over the Vercel employee's Google Workspace session
5Vercel control plane (April 2026)From the compromised Workspace session, attacker pivots into the employee's Vercel account and reads non-"sensitive" environment variables via dashboard and API across a limited subset of customer accounts
6April 2026Mandiant engaged; Vercel defaults environment variables to sensitive going forward; the single public IOC is the Google OAuth client ID 110671459871-30f1spbu0hptbs60cb4vsmv79i7bbvqj.apps.googleusercontent.com

The attack is a textbook case of supply-chain token inheritance. The weakest link was two vendors away from the victim. Vercel's own identity surface was hardened — MFA, sensible session controls, the lot — and none of it mattered, because the token the attacker rode in on was already considered trusted by the Workspace layer.

What a SIEM-only SOC sees at Vercel

Feeding the Vercel-side events into a conventional SIEM produces an alert stream that looks like this:

EventDefault rule fires?
New OAuth application authorized in Google Workspace (months prior)No (workspace admins install third-party apps routinely)
Workspace login from employee with valid session tokenNo
Vercel dashboard login from valid Workspace federationNo
Vercel API tokens used to list projectsNo
Vercel API tokens used to read environment variablesNo (this is the API's advertised purpose)
Environment variable read volume 50–500× baselineMaybe (depends on whether a volumetric rule exists for env var reads specifically)

Zero to one alerts fire, and the one is a volumetric threshold on an API most SOCs do not instrument with a threshold, because legitimate CI/CD systems routinely read environment variables in bulk. The campaign is not visible in the alert stream. It becomes visible when Vercel's own security engineering team notices the API tempo in their internal telemetry, which — based on the bulletin's first IOC timestamp relative to the reconstructed attacker actions — is what happened.

This is the normal outcome for identity-layer campaigns that ride valid tokens across trust boundaries. The SIEM's event-level view cannot see the structure.

How Setu's defense surfaces map to the chain

Setu is not a SIEM. It is a structural layer that sits over the identity, endpoint, and control-plane telemetry a customer already has, and produces surfaces that reason about shape rather than events. For this campaign, six of those surfaces are relevant — five of them fire at the right moment, one is an honest blind spot, and it is important to name both.

How Setu sees the same chain
How Setu sees the same chain

Walking them in the order the attacker trips them:

Surface 1 — Hygiene scanner, before the breach

Setu's hygiene scanner runs rule-based checks over the identity surface — the same surface a CSV export of Google Workspace OAuth grants describes. Two of its five rules are directly applicable to Step 1, months before the breach began:

  • Over-privileged third-party grant. An OAuth application holding a domain-wide or near-domain-wide scope (the "Allow All" in the Vercel chain is exactly this pattern). The scanner does not need to know Context.ai will later be compromised to flag it; it flags the shape of the grant against the vendor's adoption footprint.
  • Long-tail OAuth inventory. Third-party OAuth apps with fewer than N installers but high-sensitivity scopes — the classic shadow-IT pattern. One engineer authorized it, everyone forgot about it, and months later it was the blast-radius amplifier.

Neither rule catches the breach in progress. Both reduce the standing inventory of paths by which a breach like this can begin. This is pre-incident hygiene, not detection — and it is where most of the practical value of Surface 1 lives.

Surface 2 — The honest gap (Steps 2 and 3)

Setu has no visibility into Context.ai's own laptops. The Roblox cheat download, the Lumma Stealer execution, the token harvest — all of that happens inside a vendor's infrastructure, which no customer-side tool can reach. A customer running Setu against their own telemetry does not see this step and should not be promised that they will.

What Surface 1 does is reduce the consequences when this kind of step happens at a vendor. A grant scoped to gmail.readonly survives a Lumma harvest very differently than a grant scoped to "Allow All." The hygiene scanner's job is to make sure the blast radius stays small when the upstream supply chain eventually fails — because eventually, it does.

This is the part of the post where we want to be concrete rather than hand-wavy. Setu is not a vendor-laptop sensor. It is a graph over your own environment. Pretending otherwise would be dishonest.

Surface 3 — Entity graph, during the pivot (Step 4)

The entity graph engine does personalized PageRank with event-biased restart — a structural scoring method that elevates nodes as they accumulate edges to high-value resources, with the restart bias weighted toward recent events. Nodes that just did something interesting are heavier than nodes that did something interesting last week.

When the attacker inherits the token and begins operating as the Vercel employee, the relevant subgraph is small and new. Two structural signals show up here:

  • Bridge violation. The employee identity is now a bridge between two clusters that were not previously connected this way — the Workspace identity cluster and the customer-tenancy cluster. Betweenness centrality on the employee node spikes as the traversal widens.
  • Session identity shift. The Workspace session is the same principal, but its device fingerprint, geography, and user-agent have all changed in a coordinated way. The graph's per-node activity scorer puts the delta in the top tail of its distribution.

Neither signal is a rule. Both fall out of the graph's structure.

Surface 4 — Velocity scorer, during enumeration (Step 5)

The same per-node activity scorer that weights recent edges against a 30-day baseline is the surface that directly measures what Vercel's bulletin called "operational velocity." A hijacked identity reading environment variables across many customer tenancies in minutes is, in distribution terms, at the far tail — a 50-to-500× multiple of that identity's own baseline and a fan-out that does not match any legitimate CI/CD pattern, because CI/CD principals have predictable fan-out shapes that cluster tightly.

This is the cleanest signal in the chain. It is also the one that depends most on customers having wired their control-plane audit log into Setu. Without that telemetry, Surface 4 does not fire. With it, Surface 4 fires clearly.

Surface 5 — CTI distribution, after disclosure

Once Vercel published the OAuth client ID on April 19, that indicator became a CTI atom. A customer running Setu with the CTI feed pointed at vendor bulletins got the match against their own Google Workspace audit at the next ingest cycle. This is the surface that tells a different company — one whose employees also happened to install Context.ai — whether they are in the blast radius.

This surface is how known campaigns propagate. It does not detect the novel campaign; it distributes the known one across the customer base.

Surface 6 — Attack Dispatches feed, during and after

The Attack Dispatches feed runs bipartite connected-component clustering and Jaccard identity over the anomalous-subgraph output from Surfaces 3 and 4. Its job is to turn "several nodes lit up, go look" into one narrative object with a title, a severity, and a list of member entities.

For this campaign, the cluster is the inherited OAuth token, the employee Workspace identity, the employee Vercel identity, and the N customer tenancies whose env vars were read. The template narrator produces a headline along the lines of: "Third-party OAuth grant pivoted into a single employee's control-plane identity, which then read secrets across multiple customer tenancies inside a 30-minute window." Rank-score decay keeps it at the top of the feed for hours, because the activity it describes is still in progress.

A human analyst picking the feed off the top of the queue reads one paragraph and sees the shape of the campaign. They do not need to correlate across Workspace audit, Vercel control-plane audit, and the product API log themselves. The correlation is what the feed exists to do.

The campaign as one dispatch

Stacking Surfaces 1, 3, 4, and 6 against the attacker's timeline:

StepAttacker actionSetu surface that firesWhen
1"Allow All" OAuth grant to Context.aiHygiene scanner, if configured for third-party OAuth inventoryMonths before incident, at scanner cadence
2Roblox cheat downloaded on Context.ai laptopNone (honest gap)
3Lumma Stealer harvests Context.ai's held tokensNone (honest gap)
4Token inherited, Workspace session hijackedEntity graph (betweenness delta + session identity shift)Within minutes of first pivot
5Bulk env var read across N tenanciesVelocity scorer (top 0.01% delta)Same window
5Cluster of Surface-3 and Surface-4 signalsAttack Dispatches feed (one clustered narrative)Same window
6DisclosureCTI feed distributes IOC to all customersAt next ingest cycle post-disclosure

The surfaces are independent. Any one of them could miss. Together, they produce one dispatch with four pieces of evidence before the exfiltration completes, and a fifth piece of evidence for the rest of the customer base after disclosure.

The same shape, one scale larger: Salesloft / Drift (August 2025)

The Salesloft Drift breach is the Vercel chain with the vendor-to-customer fan-out dialed up. Drift is a conversational AI chat widget that sits on marketing sites and pushes qualified leads into customer CRMs. To do that, Drift holds OAuth refresh tokens for every customer's Salesforce tenant. The attacker, tracked by Mandiant as UNC6395, compromised Salesloft, harvested Drift's stored OAuth tokens in bulk, and used them between August 9 and August 17, 2025, to access hundreds of downstream Salesforce environments.

Salesloft / Drift OAuth supply chain breach — 700+ downstream Salesforce tenants, August 2025
Salesloft / Drift OAuth supply chain breach — 700+ downstream Salesforce tenants, August 2025

Mapped onto the same six-step chain as Vercel:

StepVercel / Context.ai (April 2026)Salesloft / Drift (August 2025)
1Vercel employee grants "Allow All" Workspace OAuth scope to Context.aiHundreds of companies authorize Drift to connect to Salesforce via standard OAuth scopes
2Context.ai employee downloads a Roblox cheat on their laptopSalesloft infrastructure compromised through means not fully publicly detailed
3Lumma Stealer harvests the OAuth tokens Context.ai holds on behalf of its usersUNC6395 exfiltrates the Drift OAuth refresh tokens Salesloft holds on behalf of its customers
4Attacker inherits one token, takes over one Workspace sessionAttacker inherits a fleet of tokens, drives each one against its paired Salesforce tenant
5Bulk env var reads across a limited subset of Vercel customer accountsAutomated SOQL queries and bulk exports across 700+ Salesforce tenants, mining records for AWS keys, VPN creds, Snowflake tokens
6Disclosure; Vercel defaults env vars to sensitive going forwardSalesloft and Salesforce revoke all active Drift tokens on Aug 20, 2025; Drift removed from AppExchange pending investigation

Two structural differences matter:

  • Fan-out is on the token graph, not the session graph. In the Vercel chain, one token produced one hijacked session which fanned out to many customer tenancies. In the Salesloft chain, one vendor compromise produced many inherited tokens, each producing its own session against a different downstream Salesforce tenant. The fan-out happens one layer up.
  • The detection signal lands on many customer SOCs at once, not on one. In the Vercel incident, the velocity and betweenness signals only exist inside Vercel's own telemetry, because the attacker was operating as a Vercel employee. In the Salesloft incident, the equivalent signal — a long-idle OAuth integration suddenly making bulk SOQL queries from an unusual user-agent string — shows up inside every one of the 700+ customer environments.

That second point is the important one for a Setu customer. In the Vercel shape, a downstream customer has no detection opportunity before Vercel discloses; their only surface is the post-disclosure CTI distribution. In the Salesloft shape, every one of the 700+ downstream customers had the detection opportunity in their own telemetry, independently. Setu's Surface 3 (entity graph) and Surface 4 (velocity scorer) fire on exactly the same signals:

  • A Drift service principal that has averaged N SOQL queries per day for two years suddenly running N × 100 queries, across object types it has never touched before. That is a velocity delta in the top tail and an edge-set that does not match the principal's embedding.
  • The Drift principal now appears as a bridge node across the customer's data objects — Accounts, Contacts, Opportunities, Cases — in a pattern that does not match its historical access shape. Betweenness delta spikes.
  • The Attack Dispatches feed clusters these into one campaign: "Third-party SaaS integration exhibiting bulk data-access tempo and cross-object fan-out inconsistent with its 2-year baseline."

None of these signals require knowing that Salesloft is compromised. They require knowing that this integration is behaving structurally unlike itself, which the graph measures natively. That is the case for running structural detection over your own SaaS-to-SaaS OAuth surface even when you trust the vendor — because the vendor's compromise surfaces in your telemetry before it surfaces in their bulletin.

The Surface 1 hygiene rule that applies to Salesloft is not "do not install Drift" — Drift is legitimate infrastructure for the companies that chose it. The rule is the same as in the Vercel case: inventory every third-party OAuth integration against its scope breadth and its vendor's adoption footprint, surface the ones where the scope exceeds the job, and keep the blast radius small for the eventual day the upstream vendor fails. Because the upstream vendor eventually fails. Salesloft and Vercel are the two most recent proofs of that.

What this post is and isn't claiming

A few honest qualifications:

  • This is a reconstruction, not a deployment. Vercel is not a Setu customer. The above is what Setu's surfaces would produce against the telemetry Vercel has already disclosed publicly, if that telemetry were ingested the way Setu customers ingest their own.
  • The graph surfaces depend on the graph being built. The betweenness and velocity-score signals assume the customer has wired their identity-provider audit log and their control-plane audit log into Setu's ingest. A customer who has Workspace audit in Setu but has not wired their internal SaaS control plane in gets Surface 3 for the pivot into Workspace but not for the pivot out.
  • Velocity is only anomalous relative to a baseline. Customers running CI/CD systems that legitimately read environment variables in bulk need to either exclude those service identities from the velocity scorer or accept a higher false-positive rate there. This is ordinary tuning, not a gotcha.
  • The hygiene scanner finds the standing inventory problem, not the breach. Its value in this incident is the pre-incident work of keeping third-party OAuth grants short and scoped. If the grant had been scoped to a single read endpoint rather than "Allow All," the chain breaks at Step 3 — the harvested token carries less power.
  • If the attacker had moved slower, Surface 4 gets harder. The velocity signal is the clearest one in the disclosure; a patient attacker spreading the same actions over two weeks degrades it substantially. Surfaces 1, 3, and 6 still fire.
  • Surface 2 is the gap. Setu does not see vendor-side laptops, and no graph over customer telemetry can. The honest answer to "what about the Lumma step?" is that you do not prevent it downstream — you prevent it upstream, by keeping the grants that a vendor can lose scoped small enough to not matter.

The broader shape

The pattern here is not Vercel-specific, and it is not Salesloft-specific either. It is the same pattern behind Okta-via-support-vendor in 2023, the Snowflake customer-credential incidents in 2024, Salesloft / Drift in August 2025, and now Vercel / Context.ai in April 2026. In each one, a trusted third party holds tokens or sessions on behalf of a customer, the third party is compromised through a channel the customer cannot see, and the inherited credential is used against the customer's own API surface at a tempo that no human operator would match. In each one, the campaign is structural — a path through identity and control-plane surfaces that valid tokens are allowed to walk — and the individual events look innocuous. The campaign is the dispatch. The events are the sentences.

SIEM-native detection is optimized for sentences. It does a reasonable job there. But it will keep missing the dispatches, because dispatches are structure across events, and an event-ordered index cannot see structure. The entity graph can. That is the whole argument for graph-native detection, and these two incidents — one smaller and more recent, one larger and from last summer — are the current cleanest examples of why it matters.


Sources and further reading


Events are facts. Relationships are context. Campaigns are the dispatch your attacker is writing. You need all three to read it.

SR

Setu Research

Setu Security Research