Aikido

Someone published four versions of a fake "tanstack" package in 27 minutes to steal your .env files

Written by
Charlie Eriksen

Someone registered the tanstack name on npm, built a video player SDK they called "TanStack Player," and today published four rapid-fire versions designed to exfiltrate your environment files the moment you run npm install.

The real TanStack, the home of TanStack Query, TanStack Table, TanStack Router, all those @tanstack/* packages with millions of weekly downloads, has nothing to do with this. The attacker just grabbed the unscoped name, dressed it up convincingly, and waited.

Today at 17:08 UTC, they deployed the payload.

What happened

Between 17:08 and 17:35 UTC on April 29, 2026, four new versions of the tanstack npm package were published: 2.0.4, 2.0.5, 2.0.6, and 2.0.7. All four contain a postinstall hook that fires automatically when the package is installed.

Prior to today, tanstack@2.0.3 (published in March) had no postinstall hook. It was a clean package with no network calls. But that changed today.

The postinstall.cjs script reads environment files from the developer's working directory and ships their contents to an attacker-controlled Svix webhook endpoint. No prompts. No visible output in most versions. It just fires and exits.

The package had around 19,830 downloads in the last month before this campaign began.

The payload

The script is straightforward. On install, it reads local files and POSTs them as JSON to this endpoint:

https://api.svix.com/ingest/api/v1/source/src_3387PLMB2uhXOBe3Q8sHu/in/3j2jokvbaF4WWdngv8zBbk

Svix is a legitimate webhooks-as-a-service company. The attacker is using its "Ingest" product as an exfiltration relay, routing stolen data through a trusted third-party to dodge network-level blocking.

The payload includes file contents plus system metadata:

{
  "package": "tanstack",
  "version": "2.0.x",
  "event": "postinstall",
  "readme": "<contents of .env>",
  "agents": "<contents of .env.local>",
  "timestamp": "...",
  "node": "v22.x.x",
  "platform": "linux",
  "arch": "x64"
}

The field names (readme, agents) are misdirection. 🪄 What's actually being sent is your .env and .env.local.

Four versions, 27 minutes, one attacker testing live

The version history is the most interesting part of this incident. The attacker published four releases in under half an hour, visibly iterating on their payload between each push.

2.0.4 (17:08): Targets .env and .env.local. The opt-out check (TANSTACK_TELEMETRY_OPT_OUT) is commented out, meaning there's no escape hatch. Includes a duplicate postinstall.js file that doesn't appear in any other version. Imports the http module but never uses it.

2.0.5 (17:11, three minutes later): Changes the target files to README.md and AGENTS.md. Also re-enables the opt-out mechanism. This looks like a brief detour — either testing whether the webhook was receiving data, or an attempt to make the hook look more innocuous before pivoting back. README.md is not a credentials file.

2.0.6 (17:26): The dangerous one. Drops the targeted file paths entirely and replaces them with a directory sweep:

function collectEnvFiles() {
  const allFiles = fs.readdirSync(rootDir);
  const matches = allFiles.filter(
    (f) => f === ".env" || f.startsWith(".env.")
  );
  for (const file of matches) {
    envFiles[file] = fs.readFileSync(path.join(rootDir, file), "utf-8");
  }
  return envFiles;
}

This catches everything: .env, .env.local, .env.production, .env.staging, .env.development. All of it goes out in a single POST. Console output is suppressed completely. The opt-out is commented out again.

2.0.7 (17:35): Reverts to .env + .env.local targeting, keeps console output commented out. Adds a curious self-referential dependency "tanstack": "^2.0.6" in its own package.json. Whether that's a mistake or serves some purpose is unclear.

What you're watching in this version history is live debugging. The attacker adjusted their targeting, tested their receiver, and optimized for stealth, all while the package was publicly available and installable.

The name squatting angle

The @tanstack organization publishes some of the most widely used JavaScript libraries on npm: TanStack Query alone gets around 8 million downloads a week. The tanstack unscoped name has been sitting separately since December 2024.

A developer running npm install tanstack instead of npm install @tanstack/query doesn't get what they expect. They get this.

The package's README is polished. It has a sponsorship badge, npm download shields, a feature comparison table, code examples. It presents as a real product. The cover story is good enough that a casual glance wouldn't flag it.

What gets stolen

In a typical JavaScript project, .env files hold:

  • AWS access keys and secrets
  • GitHub personal access tokens
  • npm publish tokens
  • Database connection strings
  • Stripe, Twilio, Resend, SendGrid API keys
  • OpenAI, Anthropic, and other LLM API keys
  • OAuth client secrets
  • Any other third-party credentials configured locally

If you have a .env.production file anywhere near your working directory (version 2.0.6 would have found it), that's production credentials handed to an attacker on install.

Remediation and detection

Step 1: Check if you were affected

Check your lock files and install history for any of these package versions:

# Check package-lock.json
grep -r "tanstack" package-lock.json yarn.lock pnpm-lock.yaml 2>/dev/null

# Check node_modules
ls node_modules/tanstack/package.json 2>/dev/null && cat node_modules/tanstack/package.json | grep '"version"'

Affected versions: 2.0.4, 2.0.5, 2.0.6, 2.0.7. If any of these appear in a lock file, treat your environment files as compromised.

Step 2: If you were affected

Assume any .env file present in the working directory at install time was exfiltrated. Rotate immediately:

  • AWS access keys and secrets (check CloudTrail for unauthorized API calls)
  • GitHub tokens with repo or org scope
  • npm tokens — revoke at npmjs.com/settings and re-issue
  • Any database credentials present in .env
  • All third-party API keys in the affected files

For CI environments: the postinstall fires during npm ci as well. If your CI pipeline installed this package, rotate all secrets injected into that pipeline's environment. Check your CI provider's job logs for the install step around the time of compromise.

For developer machines: this is persistent data exfiltration, not an in-memory attack. The files were read and sent. There are no dropped binaries or persistence mechanisms to clean up, but your credentials are already out.

Look for outbound HTTPS traffic to api.svix.com in your network logs around install time. The POST would have come from the CI runner or developer machine running the install.

Step 3: Detect it with Aikido

If you are an Aikido user, check your central feed and filter on malware issues. The vulnerability will be surfaced as a 100/100 critical issue in the feed. Tip: Aikido rescans your repos nightly, though we recommend triggering a full rescan as well.

If you are not yet an Aikido user, set up an account and connect your repos. Our proprietary malware coverage is included in the free plan (no credit card required).

Step 4: Future protection (SafeChain)

For future protection, consider using Aikido SafeChain (open source), a secure wrapper for npm, npx, yarn, pnpm, and pnpx. SafeChain sits in your current workflows, intercepting package install commands and verifying packages for malware against Aikido Intel before installation. Stop threats before they hit your machine.

IOCs

  • tanstack@2.0.4 — SHA256: 72ec4571e27c06f1d48737477c2b38a4f90d699950dab8946b48591133dc4f90
  • tanstack@2.0.5 — SHA256: 04ee5325c8900c9d644ed81c9012525b6fc19f21c65cef85b6ba98b6a0a23566
  • tanstack@2.0.6 — SHA256: abc164807947b102164488a08161adb4ee08be6b78a371350a6b156eed0d97d9
  • tanstack@2.0.7 — SHA256: 7bb84e6ba893248814cd3bac70b7bdc115740fba9e13419940c73460cbcd7b6f
  • Exfiltration endpoint: hxxps://api.svix[.]com/ingest/api/v1/source/src_3387PLMB2uhXOBe3Q8sHu/in/3j2jokvbaF4WWdngv8zBbk
  • Svix source ID: src_3387PLMB2uhXOBe3Q8sHu
  • npm maintainer account: sh20raj

Closing

This attack reminds us how little it takes to turn a name-squatting setup into an active credential harvester. The attacker didn't need to compromise a maintainer, phish a CI system, or exploit a vulnerability. They registered a plausible-sounding package, added a one-page postinstall script, and waited for installs to roll in.

The four-version iteration pattern is worth noting. This wasn't a one-shot deployment. The attacker was present, watching, adjusting their payload in real time. That's someone who knows what they're doing and was specifically optimizing for credential coverage.

Every .env file in your project is a target. Any package with a postinstall hook can read them. The npm registry gives every publisher that capability by default.

Share:

https://www.aikido.dev/blog/fake-tanstack-packages-steal-env-files

Start today, for free.

Start for Free
No CC required

Subscribe for threat news.

4.7/5
Tired of false positives?

Try Aikido like 100k others.
Start Now
Get a personalized walkthrough

Trusted by 100k+ teams

Book Now
Scan your app for IDORs and real attack paths

Trusted by 100k+ teams

Start Scanning
See how AI pentests your app

Trusted by 100k+ teams

Start Testing

Get secure now

Secure your code, cloud, and runtime in one central system.
Find and fix vulnerabilities fast automatically.

No credit card required | Scan results in 32secs.