The npm ecosystem enables developers to integrate third-party JavaScript packages into applications quickly. However, malicious packages can abuse this trust to steal credentials, collect sensitive environment variables, access local configuration files, and transmit data to attacker-controlled infrastructure.
Because npm packages may execute scripts during installation or application runtime, malicious behaviour can occur before developers realise that a dependency is unsafe.
For SOC analysts and incident responders, investigating a suspected malicious npm package requires examining package metadata, dependency changes, installation scripts, Node.js process activity, environment-variable access, outbound network connections, and possible credential misuse.
The central challenge is distinguishing legitimate package functionality from unauthorised collection and exfiltration of sensitive information.
1. Introduction: When a Dependency Becomes an Attack Vector
Modern JavaScript development depends heavily on third-party packages. Developers use npm, the Node.js package manager, to install libraries for authentication, logging, application development, testing, and deployment.
This ecosystem accelerates development, but it also introduces a supply chain risk: an application inherits some of the behaviour and security risks of its dependencies.
Imagine a developer installs a package to simplify API requests. The package appears functional and its documentation looks legitimate. However, its installation script or runtime code also reads environment variables and sends selected values to an external server.
Those variables might contain API tokens, cloud credentials, database passwords, or CI/CD secrets. If exposed, they could allow an attacker to access resources beyond the developer's workstation.
The malicious package does not need to exploit a software vulnerability in the traditional sense. It may simply abuse the permissions and access available to the process running it.
2. Understanding the npm Package Attack Surface
An npm package can contain JavaScript source files, compiled code, dependency definitions, lifecycle scripts, and other resources.
Several parts of this structure can become relevant during an investigation.
package.json
The package.json file describes package metadata, dependencies, entry points, and scripts.
Analysts should examine fields such as:
scripts
dependencies
devDependencies
main
exports
bin
A suspicious script or unexpected dependency may provide an investigative lead. However, the presence of an installation script is not automatically malicious; many legitimate packages use lifecycle scripts for setup or compilation.
Installation lifecycle scripts
npm supports lifecycle scripts such as preinstall, install, and postinstall.
Depending on the installation method and configuration, these scripts may execute commands or JavaScript during package installation. This creates an opportunity for malicious code to run before the developer launches the application.
Investigators should determine which lifecycle scripts were defined, whether they executed, and what processes they started.
Runtime dependencies
Some malicious packages remain dormant during installation and execute their payload only when imported or invoked by an application.
For example, malicious code may run when a developer starts a project, builds an application, executes a test suite, or runs a deployment workflow.
Therefore, reviewing installation logs alone is insufficient. Runtime behaviour must also be investigated.
3. How Malicious npm Packages Steal Credentials
Credential theft generally involves identifying sensitive information, accessing it from the compromised environment, and attempting to transmit it outside the organisation.
Stage 1 — Identifying sensitive data
Malicious code may inspect environment variables or local files for secrets.
Potential targets include:
API keys and access tokens.
Cloud-provider credentials.
Database connection strings.
Package registry tokens.
SSH private keys and configuration.
CI/CD secrets exposed to a build process.
Application configuration files containing passwords.
The actual exposure depends on the operating system, user permissions, process environment, and available files.
A package running with limited privileges may not be able to access every file or credential on the system.
Stage 2 — Collecting the data
Malicious JavaScript may use Node.js APIs or operating-system utilities to read accessible data.
For example, legitimate applications commonly read environment variables for configuration. The security concern arises when a package collects sensitive values unrelated to its intended functionality or accesses them without authorisation.
Analysts should examine whether the package reads sensitive information, how the data is selected, and whether the behaviour is consistent with the package's stated purpose.
Stage 3 — Preparing data for transmission
Collected information may be transformed, encoded, compressed, or combined with other system details before transmission.
Encoding alone is not proof of malicious activity. Investigators should consider the entire execution chain, including the original data source, transformation logic, destination, and purpose.
Stage 4 — Exfiltrating the information
The package may transmit collected information through HTTP or HTTPS requests, DNS queries, or another communication channel.
Encrypted network traffic does not necessarily make the activity malicious, but it can limit visibility into the content. Process attribution, DNS telemetry, proxy records, and endpoint events become particularly important when payload inspection is unavailable.
Stage 5 — Using the stolen credentials
Credential theft may create consequences beyond the initial development machine.
An attacker might attempt to use exposed tokens to access cloud resources, publish malicious packages, modify repositories, access databases, or change deployment configurations.
These outcomes must be verified independently. Evidence that a package accessed a token does not automatically prove that the token was successfully exfiltrated or subsequently used.
4. Analysing a Malicious Package: A Hypothetical Example
Consider a fictional npm dependency called build-helper-plus. It is introduced into a project through a dependency update.
The package contains an unexpected postinstall script. During installation, the script launches a Node.js process that reads selected environment variables and attempts to contact an unfamiliar external domain.
This scenario illustrates how analysts can connect package-level evidence with endpoint and network telemetry.
Evidence to investigate
Package metadata: The new version introduces a lifecycle script that was absent from the previously approved version.
File activity: The package accesses environment variables or configuration files that are not required for its documented functionality.
Process activity: An npm installation process launches an unexpected child process or script.
Network activity: The associated Node.js process makes an outbound connection shortly after installation.
Identity activity: A token associated with the development environment is subsequently used from an unusual source.
No individual observation is conclusive. The strongest assessment comes from correlating the package change, execution, data access, outbound communication, and any later use of potentially exposed credentials.
5. Static Analysis: Inspecting the Package Before Execution
Static analysis examines package files without running the suspected code. It is a useful first step because it can reveal suspicious functionality while avoiding unnecessary execution risk.
Step 1 — Preserve the package
Collect the package archive or the installed package directory, relevant lockfiles, package metadata, and available installation records.
Record the package name, version, registry source, acquisition time, and cryptographic hashes of collected artefacts.
Step 2 — Review package metadata
Inspect package.json and compare it with earlier versions or a trusted reference.
Look for unexpected lifecycle scripts, newly introduced dependencies, changes to executable entry points, and unusual installation commands.
Step 3 — Search for sensitive-data access
Review code for use of APIs associated with environment access, filesystem access, process execution, and network communication.
Relevant Node.js functionality may include:
process.env for environment variables.
The fs module for filesystem access.
The child_process module for launching external processes.
HTTP or networking libraries for outbound communication.
These APIs are widely used by legitimate packages. Their presence should guide investigation rather than serve as a standalone malware verdict.
Step 4 — Examine obfuscation and dynamic execution
Look for code that is unusually difficult to interpret, dynamically constructs executable content, or loads additional code from external sources.
Investigate whether the behaviour has a legitimate explanation, particularly for packages that perform compilation, compatibility checks, or code generation.
Step 5 — Compare package versions
Review source changes between the suspicious version and a previously trusted release.
A malicious modification may be concentrated in a small script or dependency change even when the rest of the package appears unchanged.
Preserve both versions and document the exact differences.
6. Dynamic Analysis: Observing Runtime Behaviour
Dynamic analysis examines what a package does when it executes. It can help identify behaviours that are difficult to infer from source code alone.
Safety requirement: Run suspected packages only in a disposable, isolated analysis environment with no production credentials, no sensitive mounted directories, and tightly restricted network access. Do not install them on a normal developer workstation to test their behaviour.
Step 1 — Establish a clean baseline
Record the analysis environment, Node.js version, npm version, package version, and relevant configuration.
Start with an environment that contains no real secrets or access tokens.
Step 2 — Monitor process execution
Capture the process tree and command-line activity associated with package installation and application startup.
Determine whether npm launches unexpected scripts, shell commands, or additional Node.js processes.
Step 3 — Monitor filesystem access
Observe reads and writes involving configuration files, temporary directories, credential locations, and package directories.
Correlate filesystem activity with process execution and the package's documented functionality.
Step 4 — Monitor network behaviour
Capture DNS requests, connection metadata, destination domains and IP addresses, and request timing.
Where authorised and technically feasible, use controlled network simulation or a restricted analysis network. Do not permit unrestricted access to production systems or attacker-controlled infrastructure.
Step 5 — Correlate the observations
Construct a timeline that links installation, process execution, sensitive-data access, and network activity.
A process that reads a configuration file and later initiates an outbound connection warrants investigation, but stronger evidence is needed to establish that the file's contents were transmitted.
7. SOC Investigation: Responding to a Suspected Malicious npm Package
Step 1 — Identify affected projects and endpoints
Search software inventories, repository manifests, lockfiles, build logs, and endpoint telemetry for the package name and affected version.
Determine which developers, CI/CD runners, and production systems installed or executed it.
Do not assume that every system containing the package executed its malicious functionality.
Step 2 — Review dependency changes
Examine changes to package.json, package-lock.json, and other relevant lockfiles.
Identify who introduced the dependency, which version was installed, whether the change was reviewed, and whether the package arrived through a direct or transitive dependency.
A transitive dependency can introduce risk even when developers never added the package directly.
Step 3 — Examine installation and runtime logs
Review npm output, CI/CD job logs, EDR telemetry, and available system logs.
Look for unexpected lifecycle-script execution, process creation, file access, and network activity around the installation or execution time.
Step 4 — Investigate possible secret exposure
Identify which credentials were available to the affected process at the time of execution.
Consider developer environment variables, CI/CD secrets, cloud credentials, package registry tokens, and credentials accessible through self-hosted runners.
Record the credential type and scope without copying secret values into tickets or incident reports.
Step 5 — Search for suspicious outbound traffic
Correlate process telemetry with DNS, firewall, proxy, and network detection records.
Review destinations, connection timing, data volume, and repeated communication patterns. Compare these observations with package behaviour and validated threat-intelligence indicators.
Step 6 — Check for credential misuse
Review relevant identity-provider, cloud-provider, repository, and package-registry audit logs for suspicious activity following the suspected exposure.
Look for unexpected token use, new credentials, repository modifications, unusual API calls, or package publication events.
The absence of suspicious downstream activity does not prove that no credential was exposed, especially when logs are incomplete.
Step 7 — Contain and recover
Follow the organisation's incident-response procedures.
Potential actions include:
Remove or quarantine the affected dependency.
Block or restrict the malicious package version through approved controls.
Preserve package artefacts, logs, and relevant system evidence.
Revoke or rotate potentially exposed credentials.
Review repository and cloud permissions.
Rebuild affected applications in a clean environment.
Verify the integrity of generated artefacts before redeployment.
Monitor for continued access or suspicious follow-on activity.
Credential rotation should be prioritised according to exposure and privilege, and should not be limited to the developer workstation if CI/CD or cloud credentials may also have been accessible.
8. Evidence and Indicators to Collect
Malicious npm package investigations benefit from evidence across the software, endpoint, network, and identity layers.
Evidence sourceWhat to collectInvestigative purposePackage metadataName, version, registry, lifecycle scriptsEstablishes package identity and execution pathsLockfilesResolved versions, dependency tree, integrity metadataIdentifies affected direct and transitive dependenciesSource codeEnvironment access, filesystem operations, network functionsHelps assess potentially malicious behaviourEndpoint telemetryProcess trees, command lines, file activityReconstructs installation and runtime executionDNS and proxy logsDestinations, query timing, request metadataInvestigates possible exfiltrationCI/CD logsJob execution, environment configuration, deployment eventsEstablishes the scope of pipeline exposureIdentity and cloud logsToken use, API activity, access changesIdentifies potential downstream credential misusePackage registry recordsPublication history, versions, maintainersSupports investigation of package provenance
Do not invent package hashes, malicious domains, or IP addresses when describing an incident. Use validated indicators from the actual package under investigation or trusted threat-intelligence reports.
9. MITRE ATT&CK Mapping
The following techniques may be relevant depending on the observed activity:
T1195.001 — Compromise Software Dependencies and Development Tools: Relevant when a malicious dependency or development tool is used to compromise a downstream environment.
T1059.007 — JavaScript: Relevant when JavaScript is used as the execution mechanism for malicious activity.
T1552.001 — Credentials In Files: Applicable when evidence shows that credentials were obtained from files.
T1552.004 — Private Keys: Relevant when private keys are targeted or obtained from accessible locations.
T1041 — Exfiltration Over C2 Channel: Relevant when evidence supports the transmission of collected data through a command-and-control channel.
T1071.001 — Web Protocols: Potentially relevant when adversaries use web protocols for command-and-control communication.
These mappings are evidence-dependent. Reading environment variables, accessing a file, or making an outbound connection does not by itself prove credential theft or exfiltration.
10. Preventing Malicious npm Package Attacks
Review dependencies before installation
Evaluate package maintainers, release history, dependency trees, and the permissions or scripts required by a package.
Use approved registries and dependency review processes. A package's popularity or download count should not be treated as a guarantee of safety.
Use lockfiles and controlled updates
Commit appropriate lockfiles and use consistent installation procedures in development and CI/CD.
Review dependency changes before merging them, and investigate unexpected version changes or newly introduced transitive dependencies.
Control lifecycle scripts
Where practical, restrict or disable lifecycle scripts for dependencies that do not need them. Test changes carefully because some legitimate packages require installation scripts to function correctly.
Apply least privilege to CI/CD
Do not expose production credentials to jobs that only need to run tests. Use short-lived credentials, narrowly scoped tokens, and environment-specific permissions.
Separate untrusted code execution from privileged build and deployment stages.
Use isolated build environments
Prefer ephemeral CI/CD runners that are destroyed after use. Avoid persistent workspaces containing cached secrets or credentials that later jobs could access.
Restrict outbound network access where practical and monitor unexpected destinations.
Scan and monitor dependencies
Use software composition analysis, vulnerability scanning, malware detection, and dependency-change monitoring. These controls complement one another: vulnerability scanners may not detect malicious functionality in a package that has no known vulnerability.
Protect credentials
Store secrets in approved secret-management systems and minimise their exposure to build processes. Review credential scope and expiry, and monitor for unexpected use.
Establish an incident-response process
Maintain procedures for identifying affected package versions, tracing dependency usage, revoking exposed credentials, rebuilding artefacts, and notifying relevant teams.
The response should account for both direct dependencies and packages introduced indirectly through the dependency tree.
Conclusion
Malicious npm packages exploit the trust developers place in the software supply chain. Through installation scripts or runtime behaviour, a compromised dependency may access sensitive data, communicate with external infrastructure, and expose credentials available to the process running it.
For SOC analysts, effective investigation requires correlating package metadata, source code, endpoint execution, network activity, CI/CD configuration, and identity logs. The most important distinction is between suspicious behaviour, confirmed data exposure, and verified downstream misuse.
Organisations can reduce the risk through dependency review, controlled installation, isolated build environments, least-privilege credentials, and continuous monitoring.
A dependency should be treated as executable code with access to its runtime environment—not merely as a library added to a project.
Further Reading
npm Docs — About packages and modules
npm Docs — Scripts
GitHub Docs — Security hardening for GitHub Actions
MITRE ATT&CK — Compromise Software Dependencies and Development Tools (T1195.001)