Protecting your Supabase projects from npm supply chain attacks
104.8KSign inStart your project
Open main menu
Back<br>BlogProtecting your Supabase projects from npm supply chain attacks<br>26 May 2026<br>10 minute read
Katerina SkroumpelouEngineering
There has been a growing trend of supply chain attacks on Node Package Manager (NPM). In addition, we have seen other creative attacks, including a typosquat package named supabase-javascript that appeared on npm, copying our name to phish developers. We reported it. npm took it down a few hours later, long enough that the package picked up real downloads.
If you build on Supabase, this matters to you. Edge Functions pull from npm. The Supabase CLI is on npm. supabase-js, @supabase/ssr, and @supabase/server are all on npm. Any of these is a credential leak waiting for the wrong update to land.
This post lays out what we are doing about it and what you should do today.
What we are doing about it at Supabase#
We kicked off a coordinated response across the company. The work in flight:
Publishing a canonical security guide in our docs. A single, agent-readable page that tells you exactly what to do.
Hardening our own GitHub Actions. Our security team finished a pass on pull_request_target usage across the Supabase org months ago and is close to enforcing pinned action SHAs across every repo.
Adding security notes to secret-handling APIs. TSDoc and JSDoc on functions like createClient so editor hovers warn when you are working with sensitive credentials.
Comms across every channel. Our goal is to educate as many people as we can, whether or not they are Supabase customers.
How npm supply chain attacks actually happen#
Supply chain attacks share a shape. The attacker does not break into your computer. They get you to invite their code in, and they do that by getting their code into a package you already trust. The recipes vary, but the three most common patterns are these:
Maintainer compromise. An attacker steals an npm publish token or phishes a maintainer, then publishes a new version of a popular package with malicious code added. The next time you run npm install against that range, you are running their code.
Typosquatting. An attacker registers a package name a few letters away from a real one, like supabase-javascript instead of @supabase/supabase-js. They wait for a developer or, increasingly, an AI coding agent to mistype the name. AI agents hallucinate package names regularly, and that is now a primary attack vector against teams that vibe-code their dependencies.
Build pipeline compromise. This is what hit TanStack. An attacker found a vulnerable GitHub Actions workflow, poisoned the build cache from a fork PR, and waited for the next legitimate release run to pick up the poisoned cache and publish their code under the real maintainer's identity. No stolen tokens. No compromised laptops. The attacker rode the official release train.
Once the malicious code lands on disk in your node_modules, npm's lifecycle scripts run it. By the time npm install returns, the attacker has already read your environment variables, your AWS instance metadata, your kubeconfig, your .npmrc token, your .git-credentials, and your SSH private keys. The TanStack payload exfiltrated through the Session messenger network, which is end-to-end encrypted and has no fixed command-and-control address. You cannot block it at the firewall.
The TanStack postmortem describes the full chain and is worth reading if you maintain a public open source project. The short version: every link in the chain (a pull_request_target workflow, an unsecured Actions cache, a long-lived OIDC publish token) was a known issue with public mitigations. The attack worked because nobody had connected the dots in advance.
Other things you should do today#
Most of what follows takes minutes. The goal is layered defense: no single mitigation stops every attack, but together they raise the cost enough that attackers go bother someone else.
Upgrade to pnpm 11 (or the npm v11 equivalent)#
pnpm 11 sets minimumReleaseAge to 24 hours by default, blocks exotic subdependencies by default, and ships a new Allow Builds model that controls which dependencies are permitted to run install scripts. If your AI coding agent picked pnpm 10.x for you, fix that. Tell it to use pnpm 11.
Then set minimumReleaseAge higher than the default. Three to seven days is a reasonable starting point for most projects. Most malicious npm packages are caught and pulled within twenty-four to forty-eight hours, so a three-day window catches the long tail of detections without throttling legitimate updates too much. Configure it in your project's pnpm-workspace.yaml or .npmrc:
_10minimumReleaseAge: 4320 # minutes, equals 3 days
Pin versions, especially for security-sensitive dependencies#
The ^ and ~ ranges in your package.json are a polite way of telling npm "trust me, take the next minor or patch version." Supply chain attacks...