Table of Contents
TL;DR #
A malicious npm package published under @withgoogle/stitch-sdk
impersonates Google’s Stitch AI design tool by squatting the @withgoogle
npm scope. On install, the package silently harvests developer credentials from eight sources and exfiltrates them to an attacker-controlled domain. The credential harvester runs via a preinstall
hook (triggered by npm install
) and is duplicated in the CLI binary (bin/cli.js
), giving the attacker two independent execution paths. The code is clean, readable JavaScript with no obfuscation. The attacker relies entirely on the trust implied by the @withgoogle
scope name rather than hiding the payload.
Impact:
- Credentials harvested from Claude Code, git config,
~/.git-credentials
, SSH public keys, GitHub CLI, npm config,~/.npmrc
, and~/.docker/config.json
- All stolen data exfiltrated via HTTPS GET to
hxxps://stitch-production[.]org/api/v1
- TLS certificate validation disabled on all outbound requests
- 87 downloads recorded on the first day of publication (June 19, 2026)
Indicators of Compromise (IoC):
| Indicator | Value |
|---|---|
| Package | @withgoogle/stitch-sdk v0.1.1, v0.1.2 |
| npm maintainer | maximus-mcmillan ( |
| C2 domain | stitch-production.org |
| C2 IPs (Cloudflare) | 172.67.189.185, 104.21.65.94 |
| Exfil pattern | GET /api/v1?src=<source>&user=<credential> |
| SHA256 (v0.1.1) | ba5b2a9a7fe596734fb69bdf1a35071d1a2f435a36e8c870bd4390c562d9f614 |
| SHA256 (v0.1.2) | 638b523ddd3382b622c412e37f274db1a9a6505893fa7236183f0b67a5355e94 |
Analysis #
The scope squat
Google’s Stitch is a popular AI-powered design tool that generates UI screens from text prompts. The product lives at stitch.withgoogle.com
, and Google publishes its official SDK as @google/stitch-sdk (30,000+ weekly downloads, 18 versions, published by Google employees).
The attacker exploits the gap between the product’s URL domain and Google’s npm scope. The product URL is stitch.withgoogle.com
, but Google’s npm scope is @google
, not @withgoogle
. npm scope registration is first-come-first-served with no trademark verification, so the attacker registered @withgoogle
and published a credential harvester under a name that looks like it belongs to Google.
This is a step above ordinary typosquatting. The attacker did not misspell a package name. They registered a scope that maps to a real Google domain (withgoogle.com
) and used it to publish a package with the exact same base name as the legitimate SDK. A developer who knows the product URL stitch.withgoogle.com
could reasonably assume @withgoogle/stitch-sdk
is the official package.
The attacker reinforced the impersonation with matching version numbers. The malicious package ships as v0.1.1 and v0.1.2, overlapping with the legitimate @google/stitch-sdk
’s own version history (which also has 0.1.1 and 0.1.2-next releases).
The two execution paths
The package contains five files totaling 19KB. Two of them carry the payload.
The preinstall
hook runs scripts/preinstall.js
automatically during npm install
, before dependencies are resolved. npm suppresses lifecycle script output when a package is installed as a dependency, so the harvesting is silent. The bin
field registers bin/cli.js
as the stitch-sdk
command on the user’s PATH, creating a second execution path if the user runs stitch-sdk
or npx @withgoogle/stitch-sdk
. Both files contain identical credential harvesting code.
The repository
field points to github.com/maximus-mcmillan/stitch-sdk
, a URL that returns 404. The GitHub user maximus-mcmillan
does not exist either. The entire identity is fabricated.
The credential harvester
Both scripts/preinstall.js
and bin/cli.js
import child_process
, fs
, os
, path
, https
, and http
, then run eight collection functions in sequence:
The execution order is deliberate. collectClaude()
runs first.
Claude Code credentials
The function checks whether the claude
CLI is installed, runs claude auth status
, parses the JSON output, and extracts the authenticated user’s email. This is a deliberate targeting of AI coding tool credentials. Most npm malware focuses on git, npm, and cloud provider tokens. Explicitly prioritizing Claude Code auth (and placing it first in the execution order) suggests the attacker views AI tool access as high-value. Multiple npm malware families have begun targeting Claude Code in 2026, though most focus on persistence through config injection rather than credential harvesting.
Git, SSH, and GitHub credentials
The harvester reads git configuration through two parallel paths. It runs git config --global user.email
and git config --system user.email
via execSync
, then also reads ~/.gitconfig
and ~/.config/git/config
directly from disk using fs.readFileSync
and applies a regex to extract all email addresses:
This regex sweep means the harvester does not just grab configured emails. It captures any email-shaped string found anywhere in the file, including old config lines and comments.
The same regex is applied to ~/.git-credentials
(which stores HTTPS passwords and tokens in URL format), all *.pub
files in ~/.ssh/
(SSH public key comments typically contain the owner’s email), and ~/.npmrc
and ~/.docker/config.json
(both of which may contain registry authentication tokens).
For GitHub, the harvester calls the gh
CLI directly:
This queries the GitHub API through the user’s authenticated session to retrieve their primary email.
Exfiltration
Every harvested credential passes through a single emit()
function:
Each credential is sent as an HTTPS GET request with the stolen value in the query string: GET /api/v1?src=git_config--global&
. The [email protected]src
parameter tags the credential’s origin (e.g., claude_api_user
, gh_api_user
, file:~/.npmrc
), letting the attacker correlate which tool configurations a victim has.
The function deduplicates via a Set
, so the same email address found in both ~/.gitconfig
and an SSH public key is only exfiltrated once. It uses rejectUnauthorized: false
to disable TLS certificate validation on all outbound requests. A _pending
counter and _maybeExit()
callback ensure the process does not exit until every HTTP request completes or times out.
The C2 domain stitch-production.org
was registered via GoDaddy on June 19, 2026 at 11:07 UTC, exactly 75 minutes before the first package version was published at 12:22 UTC. The domain resolves to Cloudflare IPs (172.67.189.185, 104.21.65.94) and runs nginx/1.18.0 on Ubuntu behind the proxy.
In v0.1.2, the attacker added a fallback beacon for cases where no credentials are found:
This confirms the package was installed even on machines where no developer credentials could be harvested. Version 0.1.1 simply exited silently in this case.
The cover story
The README is polished and deliberately misleading. It includes a security warning about the very behavior the package performs:
Security:preinstall
/install
/postinstall
scripts execute arbitrary code on the installing machine and are a known supply-chain attack surface. Keep them minimal and transparent, never download remote code, phone home, or touch files outside the package.
The README describes the preinstall hook as “deliberately benign” and claims it checks the Node.js version. The hook actually harvests credentials and phones home to the C2.
The CLI --help
text in v0.1.2 goes further:
This text references three real packages (@google/stitch-sdk
, ai
, @ai-sdk/google
) and the real Google documentation URL. It positions the malicious package as “the new version” of the legitimate one. The only visible seam is the typo “Alternitevly.”
The v0.1.1 help text was simpler: “stitch-sdk has not yet been released. Use the Stitch MCP server in the meantime.” The attacker refined the social engineering between versions without changing the payload.
Attacker profile
The npm account maximus-mcmillan
has published exactly one package. No other packages exist under the @withgoogle
scope. The C2 domain, the npm account, and the GitHub identity were all created for this single operation.
The payload itself is clean, readable JavaScript with no obfuscation, no hex encoding, no base64, no minification. This is a deliberate strategy. Static analysis tools that flag obfuscation patterns, string concatenation tricks, or encoded payloads would not trigger on this code. The attacker trades detectability-by-reading for undetectability-by-automation, and bets that the @withgoogle
scope provides enough trust that few people will actually read the source.
Conclusion #
@withgoogle/stitch-sdk
demonstrates scope squatting as an impersonation technique beyond simple typosquatting. By registering a scope that maps to a real Google domain, matching the legitimate package’s version numbers, and referencing real Google documentation, the attacker built a convincing enough identity to collect 87 installs on day one.
The credential harvester’s explicit targeting of Claude Code (as its first priority collector) reflects a broader shift in the npm threat landscape. AI coding tools are becoming standard targets alongside git, npm, and cloud credentials.
Developers who installed this package should rotate credentials for any tool configured on the affected machine: git, GitHub, npm publish tokens, Docker registry auth, and Claude Code sessions. Running vet against lockfiles can flag scope-squatted packages before they reach install.
- vet
- malware
- npm
- supply-chain
- scope-squatting
- credential-theft
Author
SafeDep Team
safedep.io
Share
The Latest from SafeDep blogs #
Follow for the latest updates and insights on open source security & engineering
Five npm Packages That Hide a Windows Binary Dropper Five npm packages published in a 12-minute burst split a Windows binary dropper across a fake utility toolkit. The hides in a preinstall hook, decodes its C2 from a helper package, and fetches...
astro.config.mjs Supply Chain Attack via Blockchain C2 An obfuscated IIFE hidden in astro.config.mjs fires at every build, beacons an HTTP C2, and pulls staged commands from a Tron-to-BSC blockchain dead drop.
Mastra npm Scope Takeover: 143 Packages Drop a RAT An attacker republished 143 @mastra packages, including @mastra/core, each with one injected dependency: easy-day-js, a dayjs clone whose install hook downloads and runs a remote access trojan.
Miasma Worm: Most Infected GitHub Repos Are Still Live Eight days after the Miasma worm forged a credential stealer into public GitHub repositories, most are still serving it. A re-scan of the published victim list plus a fresh code-search sweep found...
Ship Code. #
Not Malware. #
Start free with open source tools on your machine. Scale to a unified platform for your organization.