INFO • SecOpsAI Intelligence

Anatomy of a false positive: clearing a critical npm alert in twenty minutes

SecOpsAI scored a benign desktop-assistant release 100/100. A release diff, install-hook review and rule-by-rule explanation cleared it, and exposed two scoring flaws we have now fixed.

Info By SecOpsAI Research 3 min read Published: 2026-10-09 Updated: 2026-10-09
Original Research Detection Engineering Supply Chain

Summary

On 9 October 2026 SecOpsAI's npm monitor scored a new release of a desktop AI-assistant package 100 out of 100 and raised a critical alert. Twenty minutes of static review showed the release was benign. The alert was wrong for two specific, fixable reasons, and both are now corrected in the scorer. This post walks through the triage so other teams can reuse the method, and explains what changed in our detection logic.

We do not name the package: the developer did nothing wrong, and a false alert should not follow their project around.

What triggered the alert

The release carried four metadata signals:

SignalPointsWhat it really was
New postinstall hook45The hook already existed in the previous release
Suspicious script name (secret)10The word appeared in the test script, which never runs on install
Executable shipped with an install hook15The package's own command-line entry point
Process execution in the artifact6The app launches itself after a global install

Static analysis of the artifact added medium-confidence rule hits for build hooks, credential discovery and PowerShell staging, plus roughly eighty URLs offered as indicators of compromise: Gmail, Slack, Salesforce, OpenAI, Anthropic and similar services.

How the triage went

1. Diff the release, not the package. We collected both the flagged version and its predecessor into quarantine and compared them without installing or executing anything. Only four files changed: two source files, package.json and the changelog. The code change added one onboarding step for phones paired with the desktop app, and the changelog described exactly that change.

2. Read the install hook. The postinstall script was short and commented. On a global install it adds a desktop launcher and opens the app. It reads no credential files and makes no network request. Auto-opening an app during npm install -g is aggressive behaviour, but it is disclosed in the code and is not malicious.

3. Explain every rule hit. The PowerShell staging hit was the app offering an official installer URL for a coding assistant. The credential discovery hits were the app's own settings screens for API keys of the AI providers it integrates with. Accepting user-supplied keys is the product's purpose, and the keys stay in local configuration.

4. Check provenance. Releases were published from a CI workflow linked to a public source repository, at a steady cadence, by the same maintainer.

5. Look for what malware needs. Malicious install hooks typically read ~/.npmrc, environment tokens or wallet files, encode them, and send them to a host the package has no reason to contact. None of that was present.

Verdict: benign, confidence 90, recorded against the case evidence.

Why the score was wrong

The scorer read every npm script, not only install hooks. npm runs lifecycle scripts such as preinstall, install and postinstall on the user's machine; test and lint never run on install. Our token check concatenated all scripts, so node test/secrets.mjs counted as a suspicious install hook. The scorer now inspects install-time scripts only.

A first-observed release counted existing hooks as new. When the monitor has no earlier version to compare against, every hook in the release looked "new" and earned the heaviest weight. A hook is now only treated as new relative to a known previous version.

With both fixes the same release scores below the review threshold, while a genuinely new install hook that downloads and runs a script still scores in the alert range. Both cases are covered by regression tests.

Two robustness fixes found on the way

  • A malformed URL could abort an investigation. A URL with an unbalanced IPv6 bracket in package contents made indicator validation throw an error and stop the whole scan. A crafted package could have used this to evade analysis. Malformed URLs are now recorded as rejected indicators instead.
  • Indicator lists need context. Eighty well-known SaaS endpoints are not indicators of compromise for an integration product. Reviewers should treat bulk URL extraction as a map of the package's integrations, not as IOCs.

Lessons for triage teams

  • Diff against the previous release before reading anything else.
  • Separate install-time scripts from developer scripts.
  • Treat a missing baseline as "unknown", not "new".
  • Every rule hit needs an explanation in plain words before a verdict.
  • A benign verdict is a result. Record it with evidence, like any other.

Comments

Comments are moderated before publication. Do not post secrets, tokens, customer data, or exploit payloads.