RC RANDOM CHAOS

The Roblox cheat never touched Roblox

How a Roblox cheat turned into a Vercel supply chain compromise - stealer to stolen token to dependency confusion to persistent build-pipeline access.

· 16 min read
The Roblox cheat never touched Roblox

The initial access artifact was a Roblox cheat. Not a renderer zero-day. Not a kernel LPE. A packaged “script executor” and an aimbot loader, distributed through the channels where players go to find them - Discord servers, YouTube description links, cheat forums, repackaged GitHub releases. The advertised function was a game hack. The actual function was credential theft. The delivered binary was an information stealer that ran on developer endpoints, harvested authentication material, and turned that material into an entry point on a deployment pipeline. The pipeline was Vercel.

State the correction before anything else. This is not a Roblox vulnerability. Roblox is the lure, not the target. The game client was never touched. The exploited condition sits two layers away from the game - in how package managers resolve dependencies, and in how CI/CD build environments trust the packages they pull. The cheat is a delivery vehicle for the first stage. The supply chain is where the objective lives.

There is no CVE. That absence is the story, not a gap in it. Dependency confusion, package masquerade, and install-script abuse are not memory-safety defects in a single product. There is no bounds check to add, no use-after-free to close, no patch delta to diff. The behavior being abused is the documented resolution logic of npm and the documented trust model of build systems. A CVE describes a flaw in an implementation. This is the implementation working as specified, with an attacker positioned inside the trust assumption at its base. Scored as a package-registry compromise, the impact lands in critical territory - remote code execution in a privileged build context, credential theft, downstream distribution. But there is no fixed version to move to, because nothing was broken in the software sense. The trust was.

What follows separates what the mechanism guarantees from what any single public account can confirm. The mechanics of stealer-to-supply-chain pivots are well documented. The precise internals of any one incident - dwell time, exact token scope, which package name carried the second stage - are frequently not. Where the record is thin, that is marked.

The lure is a stealer, not a game hack

Game cheats are one of the most reliable malware delivery channels in existence. The victim expects to disable their own antivirus. The victim expects an unsigned binary. The victim expects to run it with elevated privileges, because injecting into a game process requires it. Every friction point a defender relies on is pre-cleared by the victim, voluntarily, because the social frame is “the cheat won’t work unless you turn protection off.” That frame is the payload’s best asset.

The families that ride this channel are known. RedLine Stealer, Lumma Stealer, Vidar, and their many rebrands. They are commodity malware, sold as a service, configured through a builder, delivered as a loader. A Roblox “script executor” is a common skin. The functional payload is generic. Once running, a stealer of this class enumerates a fixed target list - browser credential stores, browser cookie databases, cryptocurrency wallets, Discord tokens, and, relevant here, developer artifacts.

Developer artifacts are the pivot. A stealer reads the filesystem for .npmrc files containing npm auth tokens. It reads environment variable dumps and .env files left in project directories. It reads ~/.aws/credentials, ~/.config, SSH private keys under ~/.ssh, and the configuration and token caches of CLI tools - the Vercel CLI stores an auth token in a local config path, the GitHub CLI stores an OAuth token, cloud CLIs cache session credentials. This maps to T1552.001, credentials in files, and T1552.004, private keys. None of it requires privilege escalation. The token files are readable by the user the stealer already runs as.

The mistake that makes this work is not the developer running a cheat. The mistake is a developer workstation that holds long-lived, high-scope pipeline credentials in plaintext at rest, on the same machine used for anything else. A Vercel deploy token or an npm publish token sitting in a config file is a bearer credential. Possession is authorization. The stealer does not need to crack anything. It reads the file and exfiltrates the contents - T1041 over an HTTPS C2 channel, T1071.001, indistinguishable at the network layer from any other TLS session to a content-delivery front. Many of these operations proxy exfiltration through legitimate services precisely so the destination resolves to a reputable IP range.

At this point no code has run inside Vercel. The attacker holds a token. The rest is authenticated abuse.

How npm decides which package wins

The second stage exploits how package managers resolve names. This is the dependency confusion primitive, and it is worth stating precisely because the entire compromise rests on it.

A package.json lists dependencies by name and version range. When the installer resolves a name, it queries a registry. In a mixed setup - an internal private registry for first-party packages, plus the public npm registry for everything else - the resolution behavior determines which source answers. The failure mode Alex Birsan documented in 2021 is that for an unscoped dependency name, many configurations query the public registry alongside or ahead of the private one, and the public registry can answer with a package the internal team never published. If the public package advertises a higher version number, standard version-range resolution prefers it. Higher semver wins. The installer pulls the attacker’s package believing it is the internal one.

The attacker does not need to guess a secret. Internal package names leak constantly - in committed lockfiles, in stack traces, in cached build logs, in package.json files pushed to public repositories, in error pages. A stealer that already sat on a developer box will have read the internal package names directly. Publishing a public package under a leaked internal name, with a version like 99.0.0, is the whole setup. This is T1195.001, compromise of software dependencies and development tools. It is a name-resolution and version-precedence flaw, not a code flaw. It exists because the resolver’s trust boundary between “my private packages” and “the public commons” is not enforced by default.

Scoped packages change this. A name like @company/internal-lib binds to a registry through scope configuration and does not collide with the public commons unless the scope itself is misconfigured. The presence of unscoped internal names in a build is the enabling condition. The Roblox lure and the stealer exist to discover those names and to steal the token that lets the attacker publish or install with authority. Two techniques compose. Neither is exotic. Together they reach production.

Typosquatting is the adjacent variant. Instead of matching an internal name, the attacker registers a public name one character off a popular one, or a name that a developer under time pressure will plausibly type. Same resolution outcome. A package the pipeline never intended to trust executes with full pipeline privilege.

The install-script execution window

Here is the mechanism that converts a resolved malicious package into code execution. npm packages can declare lifecycle scripts - preinstall, install, postinstall. These run automatically during npm install. They run arbitrary commands. They run with the privileges of the process that invoked the install.

In local development that process is the developer. In a build pipeline that process is the build agent, and the build agent is where the secrets live. This is the distinction that matters. A Vercel build runs the project’s install step to fetch dependencies before it compiles the application. During that step, the build environment holds every environment variable configured for the project - API keys, database connection strings, third-party service tokens - because the framework needs them at build time. It holds the deployment context. It has outbound network reach. A postinstall script in a pulled package executes T1059.007, JavaScript command execution, inside that environment.

What the attacker controls at that moment: arbitrary code, running non-interactively, in a process that can read process.env in full. What that yields: every build-time secret, harvested in one pass, exfiltrated over an outbound HTTPS request that looks identical to the dozens of legitimate outbound requests a normal build makes. No exploit primitive in the memory sense. No heap grooming. The privilege was handed over by the install lifecycle, as designed.

This is the same class of event that has repeatedly hit the npm ecosystem at scale. The nx build-tooling compromise in August 2025 - tracked publicly as the s1ngularity incident - pushed malicious versions of a popular package that ran on install and swept developer machines and CI for tokens and wallet material. The Shai-Hulud npm worm campaign in September 2025 went further, using stolen npm publish tokens to inject self-propagating postinstall payloads into additional packages, turning each compromised maintainer credential into a new distribution node. Both operated through the install-script window. Neither required a novel vulnerability. Both scaled because install scripts run automatically and because publish tokens are bearer credentials.

The game-cheat framing changes only the first hop. Instead of phishing a maintainer or compromising a maintainer’s machine through a fake job interview - the technique the Contagious Interview cluster associated with North Korean operators has used repeatedly against developers - the attacker sources the initial credential from a stealer riding a Roblox cheat. Different bait, same landing zone. A stolen publish or deploy token, and the install lifecycle to run code with it.

From token to persistence

A stolen deploy token is not the objective. It is the position. What is done from that position is where a transient theft becomes durable compromise.

First move is inventory. The token’s scope defines the blast radius. A project-scoped Vercel token reaches one project’s deployments and environment variables. A team- or account-scoped token reaches every project under it. T1078.004, valid cloud accounts - the attacker now operates as a legitimate authenticated principal. Every action taken is, from the platform’s perspective, an authorized action by the token owner. There is no anomaly in the request itself. The anomaly is only in the pattern, and only if someone is watching the pattern.

Second move is reading secrets. Environment variables configured on the project are readable through the token. Those variables are frequently the real prize - a production database URL, a payment processor key, a session-signing secret, a service account for a cloud backend. The deploy pipeline was compromised, but the credentials it stored reach systems far outside the pipeline. This is lateral movement without a single additional exploit. The attacker walks from the build platform to the database to the payment processor using keys that were sitting in the build platform’s configuration, because the application needed them and they lived where the application was built.

Third move is persistence, and this is where a supply chain compromise separates from a smash-and-grab. Two durable footholds are available.

One is at the source. If the attacker’s dependency confusion package remains resolved in the build, every future deployment re-executes the malicious install script. The backdoor is not in the application repository. It is not in any file a developer would review in a pull request. It lives in a transitive dependency pulled from a registry at build time. The repository looks clean. The deployed artifact is not. Persistence through the dependency graph survives code review because code review reads the code, not the resolution of the dependency tree.

Two is at the output. Code injected during the build can modify the deployment artifact itself - the compiled application, a serverless function, an edge function, a client-side bundle shipped to every visitor. This maps toward T1554, compromising a host software binary, and in the web-serving case toward the logic of a web shell, T1505.003, embedded in the deployed function. A modified client bundle is the highest-reach outcome. Every user who loads the site executes attacker-controlled JavaScript in their own browser. A skimmer injected at build time - a Magecart-style form-data interceptor - reaches every checkout the site serves. The trust chain runs from a Roblox cheat, through one developer, through a build environment, out to the entire user base of whatever was deployed. That is the reason the game is a footnote. The mechanism scales trust downhill.

Meta’s React and Vercel’s Next.js sit under enormous numbers of these deployments. The frameworks are not the flaw. But the density of the ecosystem is what makes a single injected transitive dependency worth the effort - one poisoned package resolved across many builds reaches a large blast radius through no additional work.

What the build box never logged

Telemetry is where defenders find out whether this was ever visible. Split it into three surfaces - the developer endpoint, the build environment, and the platform control plane. The visibility on each is different, and the gap between them is where the operation lives.

The developer endpoint is the most instrumented surface, and even there the stealer stage is quiet. On Windows, executing the cheat generates process creation events - Sysmon Event ID 1, and Windows Security 4688 if command-line auditing is enabled. A stealer reading credential files generates file access, but file read auditing on user profile directories is rarely enabled because the event volume is unmanageable. The exfiltration generates a network connection - Sysmon Event ID 3 - to an external host over 443. An EDR product with behavioral detection may flag the sequence: an unsigned binary, spawned from a downloads directory, reading browser credential stores and config files, then opening an outbound TLS connection. That behavioral chain is the strongest detection opportunity in the whole operation, and it fires on the endpoint, before any pipeline is touched. The catch is that the endpoint running the cheat is frequently a personal or under-managed machine, precisely the kind that sits outside EDR coverage, precisely the reason it was running a cheat in the first place. The best detection point is on the box least likely to be monitored.

The build environment is close to blind by default. A managed CI/CD build runs in an ephemeral container that is created, executes, and is destroyed. There is no persistent EDR agent inside it. Process creation during the build is expected - the build spawns compilers, package managers, and scripts by design, so a malicious postinstall spawning a process is statistically invisible against that baseline. Outbound network connections during the build are expected - installs fetch from registries and CDNs constantly, so exfiltration over HTTPS blends into normal install traffic. The one artifact that exists is the build log. A build log will contain the install output, and a lifecycle script that runs unusual commands may leave a trace there. But build logs are high-volume, rarely centralized into a SIEM, rarely parsed for anomalies, and trivially quieted by a payload that suppresses its own output. The environment where the code actually executes with access to the secrets is the environment with the least telemetry. That inversion is the core detection gap.

The platform control plane is where the durable signal lives, and it is a pattern signal, not an event signal. Vercel, like Okta and other identity-bearing platforms, emits audit logs - token usage, deployment creation, environment variable reads, configuration changes. A stolen token used from a new ASN, a new geography, at an unusual hour, is an authentication anomaly visible only by correlating the token’s normal usage baseline against the new activity. The individual API calls are all authorized and all valid. Deployment triggered outside the normal CI path, environment variables read through the API when they are normally only read at build time, a new token minted, a project setting changed - each is legitimate in isolation. The detection requires baselining the identity’s behavior and alerting on deviation. This is standard identity-provider anomaly logic, the same discipline that catches stolen Okta sessions. It works only if the audit logs are ingested and if a baseline exists. Absent that, the compromise is a set of perfectly authorized actions that never trip a single hard rule.

The network IOCs are weak by construction. Exfiltration to a reputable CDN front or a paste service resolves to trusted infrastructure. Cloudflare and similar fronts are used specifically because their IP ranges are on no blocklist. C2 over HTTPS with valid certificates defeats TLS inspection that stops at certificate validity. The domain may be days old, which is one of the few durable signals - newly registered domain contacted by a build agent is worth alerting on - but the payload can equally exfiltrate to an established, abused legitimate service and remove even that.

Summarize the gap plainly. The loudest stage runs on the least-monitored machine. The highest-privilege stage runs in the least-instrumented environment. The most detectable stage - anomalous authenticated API use on the control plane - is only detectable to a team that ingests platform audit logs and baselines identity behavior, which is the exact discipline most teams skip because the platform “handles security.” The platform handles the platform. It does not handle a valid token in the wrong hands.

What survives rotation

There is no patch boundary, because there is no patched product. Remediation is credential and configuration work, and the sequencing determines whether the attacker is actually evicted or merely inconvenienced.

Token rotation is necessary and insufficient. Every credential the stealer could have read is burned the moment the stealer ran - npm tokens, deploy tokens, the environment variables inside the build, the cloud keys those variables pointed to, the SSH and cloud CLI caches on the endpoint. Rotating them invalidates the stolen copies. It does nothing about persistence that no longer depends on those copies. If a malicious dependency remains resolved in the build, the next deployment re-establishes access after rotation, using freshly harvested secrets from the fresh build. Rotation without removing the poisoned dependency is a reset button the attacker holds a copy of. The dependency graph has to be audited and the malicious package pinned out, the lockfile regenerated from a known-clean state, and the resolution behavior corrected so an unscoped internal name can no longer be answered by the public registry.

Artifact integrity is the second residual. If code was injected into a deployed function or a client bundle during a poisoned build, redeploying from clean source removes it only if the source and the dependency tree are both clean. A backdoor that lived in a transitive dependency, not in the repository, will survive a redeploy from the same package.json unless the dependency is explicitly removed. Any artifact deployed during the compromise window is suspect and has to be rebuilt from a verified dependency set, not merely rolled forward.

Downstream exposure is the residual that outlives the pipeline entirely. If a client-side skimmer shipped to real users, every session served during the window is potentially compromised - form data, session tokens, whatever the injected script could read from the DOM. Rotating the pipeline’s credentials does nothing for the users who already loaded the poisoned bundle. That exposure is measured in the traffic served, and it belongs in incident scoping, not deployment cleanup. Under Australian obligations, credential and personal-data exposure of this kind engages Privacy Act notification thresholds, and where the deployed system supports a regulated sector it engages SOCI incident reporting. Active downstream compromise is a matter for the responsible security and legal teams, escalated on the timeline the regulation defines, not a matter for a rollback.

The controls that break this chain are structural, not reactive, and they attach to the trust assumptions the attack abused. Scoping internal package names so the public registry cannot answer for them. Enforcing registry resolution so a private name never resolves to a public source. Disabling install-script execution for dependencies in CI, or gating it behind an allow-list, so a postinstall in an unexpected package cannot run automatically. Signature verification and hash pinning on dependencies, so a substituted package fails resolution rather than executing. Scoping pipeline tokens to the minimum function and the shortest lifetime, so a stolen token reaches one project for one hour rather than one account forever. Ingesting platform audit logs and baselining identity behavior, so authorized-but-anomalous activity surfaces. Keeping high-scope pipeline credentials off general-purpose developer machines, so a stealer on an endpoint reaches nothing that matters. Each control breaks one link. The chain needs every link.

The technical reality is that none of this was advanced. A stealer is commodity malware. Dependency confusion is five years documented. Install-script abuse is the default behavior of a package manager. Token theft is reading a file. The operation reached production because commodity technique met unenforced trust at four separate boundaries - the endpoint that ran unsigned code, the resolver that trusted the public commons, the build that ran arbitrary install code with full secret access, and the control plane that accepted a valid token without questioning who held it. The Roblox cheat is the part that gets the headline. The four unenforced trust boundaries are the part that gets exploited again next quarter, with a different lure and the same path.

See also: NordVPN for tunneled traffic when operating outside controlled networks.


#ad Contains an affiliate link.

Share

Keep Reading

Stay in the loop

New writing delivered when it's ready. No schedule, no spam.