The build was fixed, but a different risk appeared
A build was failing, so someone repeated npm install on a work laptop or persistent runner. The dependencies installed, but the logs or process tree showed an unexpected AI CLI launch. An AI CLI is an AI-enabled tool operated through a command-line interface. The team does not know whether it could read the home directory, .env files, SSH keys, or package-registry tokens.
The right first response is neither panic nor blame. Limit further risk, preserve available evidence, and determine the process’s actual access boundary. An AI CLI launch alone proves neither that secrets were read nor that data was transmitted outside the environment.
What the dangerous chain looks like
This was not a hypothetical scenario. On August 26, 2025, malicious versions of the Nx package were published to npm. The attack, known as s1ngularity, used postinstall, a lifecycle script that a package manager may run automatically after installation.
The malicious script searched for an already installed AI CLI and started it in permission-bypass mode, meaning it acted without its usual request for human confirmation. The payload described by the source ran on macOS and Linux and exited without executing on Windows. The response plan below is useful for similar incidents, but that boundary of the specific attack matters.
The source-described chain is:
- The package manager runs a lifecycle script from the compromised package.
- The script searches for an available AI CLI.
- The CLI runs in the context of the same user or execution environment.
- The tool may search and inventory files available to that context, including potential secrets.
- A separate malicious component may attempt to transmit discovered data outside the environment.
Effective access is not always identical to every capability associated with the user. File permissions, protected credential stores, mounts, container or virtual-machine boundaries, and network rules may impose additional limits.
Do not merge the last two stages. Discovering a filename, reading its contents, and transmitting data are separate events that require different evidence. An unexpected process confirms a launch, but it does not prove that the full chain occurred.
First actions: contain, preserve, assess
The steps below are an editorial response plan derived from the described scenario, not claims about the indicators of a specific incident. If the process is still running, follow your team’s established procedure. Where possible, use an approved method to isolate the host or runner from external networks, and do not delete data before preserving it.
Record:
- the known installation time and command and the account that started it;
- the Node.js, npm, and suspected package versions;
- a copy of the lockfile and the dependency-tree change;
- parent and child processes and their execution arguments;
- npm, shell, EDR, DNS, proxy, and CI logs;
- file changes and outbound connections during the relevant period.
The absence of a log entry does not always mean an action did not occur. The required telemetry may never have been collected or may no longer be available. Mark these gaps as unknown rather than confirmed safe.
Next, build a map of effective access. Check .env files, environment variables, cloud CLI settings, the SSH directory, an active SSH agent, Git configuration, package-registry tokens, signing keys, and CI secrets. An SSH agent is a service that uses loaded keys without placing their unencrypted contents in every process.
Do not paste secret values into tickets or chat. For each secret, record its type, owner, location, lifetime, privilege level, and a masked identifier. Divide the results into three groups:
- reading or transmission is confirmed by evidence;
- access was technically possible, but telemetry is insufficient;
- access was blocked by a verified control.
Revoke or replace credentials confirmed as read or transmitted. This replacement process is secret rotation. Assess potentially accessible secrets under your team’s incident-response policy. Prioritize long-lived credentials with broad permissions or production access. Perform revocation and rotation from a known-clean environment, not from the suspected host.
The response depends on the environment
Developer workstation
Start with the developer account’s permissions, but account for operating-system protections, encryption, and access prompts. Review the home directory, active cloud CLI sessions, SSH agent, and local credential stores. Do not return the laptop to normal use until the evidence has been assessed and the required revocations are complete.
Persistent runner
A persistent runner retains files and state between jobs. Review not only the current build but also caches, previous workspaces, and machine-level configuration. Remove the suspected runner from the pool until the review is complete if that is consistent with your team’s procedure.
Ephemeral runner
An ephemeral runner is created for an individual job and then destroyed. Destruction reduces residual risk, but it does not cancel access that existed while the job ran. Review control-plane logs, network telemetry, and credentials issued to that specific run.
Protection needs several layers
No single switch or product covers the full scenario. Combine these controls:
- pin approved dependency versions and review unexpected lockfile changes;
- verify package provenance when the registry and team process provide that information;
- restrict lifecycle scripts and approve exceptions only for reviewed packages;
- run installation and AI CLI processes in an isolated environment without mounting the developer’s home directory;
- use separate identities with minimum required permissions;
- issue short-lived CI tokens only for a specific job;
- restrict outbound network access where the build permits it;
- do not treat a confirmation prompt as a security boundary.
A container alone does not guarantee isolation. The real boundary depends on mounted directories, the process identity, permissions, and network rules. The issue is also not AI by itself. Risk appears when unreviewed code can start a powerful tool with excessive access.
Test the controls without real secrets
Create a separate non-production environment with an empty temporary home directory and a unique fake marker instead of a real token. Do not install the suspected package or copy production configuration. Use a team-approved harmless test process with the same intended file and network restrictions.
If network controls must be tested, send a test request only to a controlled endpoint owned by the team. Do not use arbitrary external services.
A successful result should show that:
- the marker outside the approved workspace is inaccessible;
- the process has no unrestricted external network access;
- attempted prohibited access appears in the required logs.
Even if confirmations are accidentally disabled, the process should not be able to see production secrets. If the test passes only because a person notices and rejects a prompt, the isolation is not strong enough.
Approaches that do not work
Do not immediately delete node_modules; that may destroy useful evidence. Do not stop after reinstalling the package or revoking one obvious token. Do not treat the destruction of an ephemeral runner as proof that no access occurred during the job.
Likewise, do not infer theft solely from an AI CLI launch. Do not assume a container is safe without reviewing mounts, identity, and network access. Keep confirmed facts, assumptions, and unknown conditions as separate categories.
Conclusion
The key question is not whether the process used AI, but which permissions it could actually exercise. First limit further risk and preserve evidence. Then identify accessible secrets, revoke credentials that are confirmed or reasonably assessed as compromised, and remove the access path through isolation, least privilege, and short-lived tokens.
Sources
Quick checklist
- isolate the suspected host without destroying logs or other evidence
- record the installation time, process tree, and dependency change
- inventory secrets available to the process identity
- revoke or replace credentials that may have been read
- review lifecycle-script policy and AI CLI execution modes
- run a safe simulation using fake secrets
Build a Response Plan for a Suspicious postinstall Script
Help me create a safe response plan for a suspicious package lifecycle script. Inputs: - environment: developer workstation, persistent runner, or ephemeral runner; - operating system; - dependency installation time and command; - suspicious package or lockfile change; - installed AI CLI tools; - directories and credential types available to the process; - available process, npm, EDR, DNS, and proxy logs; - whether a permission-bypass mode was allowed. Do not ask for real tokens, keys, or secret-file contents. Use only names, types, and masked identifiers. Output format: 1. Likely scope and unknown facts. 2. First 30-minute actions in priority order. 3. Evidence that must be preserved. 4. Potentially exposed secrets table: type, location, owner, action. 5. Prioritized revocation or rotation plan. 6. Checks required before returning the environment to service. 7. Long-term changes for dependencies, isolation, and secret management. Do not claim that data was stolen without evidence. Label confirmed facts, assumptions, and investigation questions separately.