Cloud Security
Malicious npm Dependencies: Credential Exposure Response
Distinguish malicious npm package presence, installation, execution, secret access, and exfiltration before rotating tokens, rebuilding CI, or clearing caches.

A malicious npm package can turn a dependency review into an identity and build-system investigation. Current public guidance describes attacks that scanned developer environments, CI systems, and cloud tooling for tokens and secrets, but the right conclusion depends on evidence: a package listed in a lockfile is not the same as a package downloaded, installed, executed, able to read a secret, or shown to have sent data out. [1] [5] [7] This refresh gives teams a staged response for npm and similar JavaScript delivery paths. It covers lockfiles, package-manager and artifact caches, CI runners, token rotation, provenance, and downstream verification. It uses the public CISA, npm, GitHub, CERT-In, OpenSSF, and SLSA records reviewed on 2026-09-25; incident-specific claims remain bounded by those records and by what an organization can prove in its own telemetry. [1] [4] [6] [7] [8] [9]
Separate package presence from compromise
Use five evidence states when triaging a suspicious dependency. **Presence** means the name and version appear in a manifest, lockfile, node_modules tree, image, or cache. **Installation** means package-manager or build records show that bytes were fetched and placed into an environment. **Execution** means a lifecycle hook, imported code, binary, or build step ran. **Secret access** means logs, host telemetry, or code review show that the process could read a named secret or credential. **Confirmed exfiltration** means network, provider, repository, or other evidence shows that data left the environment. These states can overlap, but none should be silently substituted for another. [2] [3] [4] [5]
A package in a lockfile deserves review because it can identify affected projects and transitive paths. It does not, by itself, prove that the package was fetched, that an install script ran, that a runner held secrets, or that an attacker received data. CISA asks organizations to review dependency trees and caches, while GitHub notes that a hosted runner does not scan code downloaded by a job. The response should record the highest state actually supported for each project, host, runner, and credential. [1] [5]
- Record the evidence state, time window, package name, version, resolved URL, integrity value, environment, and confidence for every finding.
- Treat absence of a log as unknown unless retention, coverage, and clock alignment show that the event would have been recorded.
- Do not label an organization compromised solely because a vulnerable or malicious version is present.
Bound the npm window and dependency scope
Start with the registry operator, vendor, or government record that names affected package versions and dates. The CISA alert on the 2025 Shai-Hulud campaign says the worm compromised more than 500 packages, scanned for sensitive credentials, targeted GitHub tokens and cloud API keys, and recommends pinning to known-safe releases produced before September 16, 2025. That is campaign-level guidance, not proof that every project using npm was affected. [1]
CERT-In’s May 2026 advisory describes a later “Mini Shai-Hulud” campaign spanning npm and PyPI, with possible CI/CD, cloud, and trusted-publishing impact. It warns that affected packages and versions can expand. Use such notices to define a candidate set, then reconcile it against internal manifests, lockfiles, registry download records, artifact repositories, build logs, and deployment inventories. [7]
Preserve the original advisory, its publication date, affected-version list, and any later corrections in the case record. Distinguish the public disclosure date from your own first download, build, or execution date. If the advisory names only an ecosystem or namespace, do not infer that every version or every consumer is affected.
- Capture direct and transitive package paths from package-lock.json, npm-shrinkwrap.json, yarn.lock, pnpm-lock.yaml, SBOMs, and built images where present.
- Compare resolved versions and integrity hashes with the supplier’s affected and fixed ranges; preserve both the pre-remediation and post-remediation records.
- Use registry, proxy, artifact, DNS, and egress records to test whether the candidate package reached each environment.
Make lockfiles and installation behavior part of the proof
npm documents npm ci as the clean-install path for automated environments. It requires an existing package-lock.json, fails when package.json and the lockfile do not match, removes an existing node_modules tree before installing, and does not write either package manifest. Those properties make the lockfile an important review artifact, but they do not make its contents safe automatically: a lockfile can faithfully pin a malicious version. [2]
Review lockfile history, pull requests, generated diffs, registry URLs, integrity fields, overrides, workspace links, optional dependencies, and any package tarballs stored in internal repositories. A changed lockfile is evidence of a dependency-resolution event, not evidence of execution. Conversely, a clean lockfile does not exclude a poisoned cache, a separately supplied tarball, a prior installation, or a compromised build action.
npm lifecycle documentation states that npm ci runs preinstall, install, postinstall, prepublish, preprepare, prepare, and postprepare stages after modules are installed. This is why an installation record must be paired with script, process, and network evidence. Teams that permit scripts should document the approval basis; teams that can safely disable unreviewed install scripts should test that policy against build requirements. [3]
- Prefer reviewed, committed lockfiles and deterministic CI installation; fail builds when the lockfile is absent, unexpectedly changed, or inconsistent with the manifest.
- Scan lockfiles and SBOMs against current malicious-package and advisory data, including transitive dependencies; OpenSSF describes OSV-Scanner support for lockfiles and CI scans. [6]
- Treat an integrity hash as evidence that the fetched bytes matched that hash, not as proof that the publisher or source was benign.
Test installation and execution separately
For each host or runner, establish whether the candidate version was downloaded, unpacked, linked, imported, or executed. Package-manager logs can support installation; process creation, script output, file changes, child processes, and runtime telemetry support execution. A package that was downloaded into an unused cache may be a different risk state from a package whose postinstall hook ran in a privileged build.
The npm scripts record explains that lifecycle scripts run through the platform shell and receive package and environment metadata. That creates a route to inspect what the script could see, but capability is not access: an environment variable’s presence does not prove it was read, and code that could read a file does not prove that it did. Review process arguments, file access, environment capture where lawfully retained, and egress records without copying secrets into the case file. [3]
Use an isolated analysis copy when inspecting suspicious artifacts. Do not execute an untrusted package in a production workstation or a runner that contains live credentials. If execution is suspected, preserve volatile and persistent evidence before cleanup when doing so is safe and consistent with the incident plan.
- Correlate install timestamps with lifecycle-script, shell, node, Bun, package-manager, and build-step telemetry.
- Record whether scripts were enabled, denied, interrupted, or failed, and do not treat a failed script as proof that no code ran.
- Mark unknowns explicitly when telemetry cannot distinguish a package-manager action from an application import.
Review caches, mirrors, and build artifacts
CISA specifically recommends searching cached versions of affected dependencies in artifact repositories and dependency-management tools. Include developer npm caches, CI dependency caches, proxy or mirror stores, container layers, workspace snapshots, prebuilt node_modules archives, and release artifacts. Search by package identity, version, integrity value, tarball digest, and the advisory’s time window. [1]
npm says its cache is content-addressable and verifies data on insertion and extraction; npm cache verify checks the cache index and cached data, while cache clean is normally unnecessary for corruption alone. Integrity verification answers whether cached bytes match their recorded content address. It does not answer whether the package was malicious, whether it executed, or whether a secret was accessible. [4]
Containment should prevent re-use of suspect bytes while preserving a controlled copy for evidence. Quarantine or expire affected cache entries according to the package manager and repository procedures, rebuild from a reviewed lockfile and trusted source, and record cache invalidation time. Do not assume that deleting a local cache removes copies in remote mirrors, runner images, backups, or downstream artifacts.
- Inventory cache keys, retention periods, sharing boundaries, and whether one runner or tenant can write entries consumed by another.
- Compare artifact digests and provenance against the expected package and release; retain original hashes before replacement.
- Re-scan images and release bundles, not only source repositories, because a dependency may already be embedded downstream.
Contain CI runners and workflow secrets
GitHub states that a compromised runner can access secrets exposed to the job, repository data, and the job’s GITHUB_TOKEN within its granted permissions. It also warns that log redaction is not a true security boundary and that an attacker may send secrets or other data to an external server. A malicious dependency in a job therefore raises the priority of runner isolation and secret review, but the exact exposure still depends on triggers, permissions, secret availability, network access, and execution evidence. [5]
Pause or isolate suspect jobs and runners in a way that preserves useful evidence. Review workflow files, reusable workflows, third-party actions, cache configuration, artifacts, logs, repository webhooks, deploy keys, app installations, and recent branch or release changes. GitHub recommends minimum GITHUB_TOKEN permissions and pinning third-party actions to full-length commit SHAs; these controls reduce reach but do not prove that a prior run was safe. [5] [10]
Give special attention to privileged pull-request flows, self-hosted runners, shared workspaces, and deployment jobs. GitHub documents risk when privileged triggers process untrusted pull-request content. Treat a runner as suspect until its image, persistence, workspace, cache, and credential path have been reviewed or replaced. [10]
- Create a run-to-secret map: which job ran, which secrets were available, what permissions were granted, and what destinations were reachable.
- Prefer short-lived, job-scoped identities and clean runner images; separate build, test, and release permissions.
- Review logs for intentional or transformed secret disclosure; delete exposed logs when policy permits and preserve an access-controlled forensic copy.
Rotate credentials by reachability and privilege
CISA recommends immediate rotation of developer credentials after the 2025 npm compromise. CERT-In extends that response set to npm and PyPI publishing tokens, GitHub PATs and Actions secrets, cloud credentials, Vault and Kubernetes service-account tokens, SSH keys, and other CI/CD secrets. Use those lists as a starting scope, then rank identities by what the affected process could reach and by the damage an active token could permit. [1] [7]
If execution or secret access is supported, revoke or replace the relevant identities through their issuing systems, starting with high-privilege and publishing credentials. Disable stale tokens, invalidate sessions where supported, rotate signing or deployment keys when their private material may have been exposed, and update consumers without placing new secrets in the suspect environment. If only package presence is known, document the uncertainty and use risk-based precaution rather than claiming that every credential was stolen.
After rotation, search provider audit logs for use of old credentials, new repositories or packages, changed workflows, unusual releases, unfamiliar regions, metadata-service access, and other activity consistent with the incident record. A successful rotation closes one access path; it does not establish that no data left before rotation.
- Record identity, owner, privilege, reachable systems, last-seen use, rotation time, replacement validation, and residual uncertainty.
- Rotate npm publishing and source-control identities separately from cloud, database, Vault, Kubernetes, SSH, and deployment identities.
- Keep the old credential available only as a controlled indicator for provider-side searches; never restore it for convenience.
Verify downstream consumers before restoring trust
Map every downstream consumer that received an affected package, including internal applications, container images, serverless bundles, desktop tools, plugins, customer distributions, and other packages published from the same build. A clean source branch is not enough if a cached tarball, generated bundle, or release artifact was produced during the suspect window.
OpenSSF describes scanning lockfiles and SBOMs for malicious-package records, while SLSA explains that provenance can help a verifier compare source location, revision, build configuration, parameters, builder, and artifact digest with expected values. Provenance is an integrity signal, not a guarantee that a dependency was harmless; SLSA explicitly places compromised build and runtime dependencies outside the full mitigation scope of its v1.0 dependency section. [6] [8]
Restore a build only after the reviewed dependency set, cache path, runner image, workflow, identity set, and output digest are recorded. Compare rebuilt output with the approved artifact where reproducibility permits. Notify downstream owners with the evidence state and affected versions, not with a blanket assertion of compromise. Ask recipients to validate their own installation, execution, secret access, and egress evidence.
- Generate a consumer list from SBOMs, package metadata, artifact promotion records, and release pipelines.
- Require independent review for lockfile changes, workflow changes, new publishing credentials, and exceptions to provenance checks.
- Keep a dated restoration decision that states what was verified and what remains unknown.
Apply current npm and India-specific controls
GitHub’s September 2025 npm plan describes a move toward required two-factor authentication for local publishing, short-lived granular tokens, and trusted publishing that reduces the need to keep a long-lived API token in a build system. Treat the plan as supplier guidance and check current npm documentation before changing production publishing workflows; do not assume a roadmap item is already enforced for every account. [9]
For organizations operating in India, CERT-In’s May 2026 advisory is a primary local reference for the later campaign. It calls for dependency review, host isolation when an affected version is identified, evidence preservation, credential rotation, MFA, workflow auditing, lifecycle-script restrictions, provenance checks, SBOM monitoring, and threat hunting. Indian teams should coordinate the technical record with their incident-response owner and assess applicable CERT-In reporting and retention duties rather than treating an international alert as their only source of direction. [7]
The India context does not change the evidence ladder. A package listed in a lockfile in an Indian development account is still presence until installation, execution, secret access, or exfiltration is demonstrated. Geography may change notification, data-residency, customer, and regulator questions; it does not justify a stronger technical conclusion than the telemetry supports.
- Review npm account MFA, token age, publishing scope, trusted-publisher configuration, and owner access.
- For India-based operations, preserve timestamps in a consistent time zone and identify the internal and external reporting contacts before an incident occurs.
- Document supplier guidance separately from your own verified facts, inferences, and unknowns.
Close the case with evidence, not reassurance
A defensible closure record should list the affected package identities, versions, lockfiles, environments, cache locations, runner jobs, credential classes, egress findings, downstream artifacts, and restoration decisions. For each item, state observed fact, supported inference, unresolved unknown, source, timestamp, and confidence. This makes later supplier updates or new malicious-package records easier to apply without rewriting the whole investigation.
Do not use “no evidence of exfiltration” as “exfiltration did not occur” unless the logging design can support that conclusion. Likewise, “credential rotated” means a new credential is active and the old one is invalid or constrained; it does not mean historical use was absent. Review the case after new registry advisories, provider findings, or downstream notifications change the scope.
The goal is to restore trusted delivery while preserving a truthful account of what happened. That is safer than either dismissing package presence or declaring a full compromise without evidence.
- Attach source records and internal evidence references without embedding secrets or public clickable evidence URLs in the rendered article.
- Set a follow-up date for supplier, registry, identity-provider, and downstream updates.
- Record the decision owner who accepted residual uncertainty and the controls added to prevent recurrence.
Decision checklist
- Have we recorded whether the package is only present, downloaded, installed, executed, able to access a named secret, or supported by evidence of exfiltration?
- Have we preserved the affected advisory, dates, package versions, integrity values, and the exact download and execution window?
- Have we reviewed direct and transitive dependencies in package-lock.json, npm-shrinkwrap.json, yarn.lock, pnpm-lock.yaml, SBOMs, images, and release bundles?
- Have we searched developer caches, CI dependency caches, artifact repositories, mirrors, runner images, and backup copies for suspect bytes?
- Have we isolated or replaced suspect hosts and runners while preserving evidence appropriate to the case?
- Have we mapped which CI jobs, workflow triggers, permissions, secrets, tokens, and network destinations were available?
- Have we rotated or revoked reachable npm, source-control, cloud, CI/CD, database, Vault, Kubernetes, SSH, signing, and deployment credentials according to privilege?
- Have we checked provider audit logs and repository history for old-token use, workflow changes, new releases, webhooks, apps, or unfamiliar access?
- Have we verified the replacement dependency set, cache state, provenance, runner image, output digest, and downstream consumer list before restoration?
- Have we documented facts, inferences, unknowns, evidence gaps, owner decisions, and the next review date?
- For India operations, have we assessed applicable CERT-In coordination, reporting, retention, customer, and sector obligations with the responsible owner?
Limitations
- Public advisories describe campaign or package scope, not the private execution and credential state of a particular organization.
- Registry withdrawal, cache deletion, log gaps, short retention, clock drift, and runner replacement can remove evidence needed to distinguish installation from execution.
- A lockfile, integrity hash, SBOM, or provenance statement can identify bytes and build relationships, but none alone proves benign intent or rules out secret access.
- Provider logs may show token use without proving which process obtained the token; network logs may show egress without proving which data was sent.
- CERT-In and other government guidance can change as affected package lists and indicators expand; teams must recheck the live advisory and their own supplier notices.
- The npm and GitHub controls cited here are defensive guidance, not a guarantee that every registry, runner, package, or downstream artifact is safe.
Evidence sources
- Cybersecurity and Infrastructure Security Agency (CISA) — Widespread Supply Chain Compromise Impacting npm Ecosystem
- npm Documentation — npm ci
- npm Documentation — Scripts: How npm handles the scripts field
- npm Documentation — npm cache
- GitHub Documentation — Compromised runners
- OpenSSF — Detecting Malicious Packages using the OSV API
- Indian Computer Emergency Response Team (CERT-In) — CERT-In Advisory CIAD-2026-0026: “Mini Shai-Hulud” Supply Chain Attack Campaign Targeting Open-Source
- SLSA — Threats & mitigations
- GitHub Security Lab — Our plan for a more secure npm supply chain
- GitHub Documentation — Secure use reference