On a routine Thursday, developers who ran npm install on SAP's Cloud Application Programming Model packages received more than they expected. Four official SAP packages — @cap-js/sqlite v2.2.2, @cap-js/postgres v2.2.2, @cap-js/db-service v2.10.1, and mbt v1.2.48 — contained malicious preinstall scripts designed to steal credentials and authentication tokens. The compromised versions remained available for approximately two weeks before detection.
This wasn't a typosquatting campaign or a dependency confusion attack. Someone compromised the legitimate SAP publishing pipeline and injected malware into packages that organizations explicitly trust.
Timeline
The attack occurred through SAP's official npm publishing channel. The malicious code executed during package installation via preinstall scripts — a legitimate npm lifecycle hook that runs before a package is installed. When your CI/CD pipeline or local development environment pulled these specific versions, the payload activated immediately.
The malware established persistence by using GitHub commit searches as a command-and-control mechanism. Instead of connecting to obvious external infrastructure, the attackers embedded tokens in GitHub commits, creating a dead-drop system that blends into normal developer traffic. Security firms Aikido and Socket identified the compromise and attributed the attack pattern to TeamPCP, a group with prior supply-chain attack activity.
Which Controls Failed
Package integrity verification
The compromised packages passed through npm's publishing infrastructure without triggering alerts. Your standard npm install workflow has no built-in mechanism to validate that package contents match the maintainer's intent. The preinstall script executed with the same privileges as your build process.
CI/CD environment isolation
These packages target CI/CD environments specifically. If your build agents have access to production credentials, cloud provider tokens, or internal API keys — and most do — the malware had access to those secrets during installation. The attack exploits the reality that CI/CD environments often operate with elevated privileges to deploy code.
Dependency monitoring
The malicious versions existed for two weeks. Organizations that install dependencies without reviewing changes or monitoring for unexpected behavior had no visibility into the compromise until external security firms published their findings.
Outbound network controls
The GitHub dead-drop technique bypassed traditional network monitoring. GitHub is a trusted domain in most development environments. The malware's communication pattern looked identical to legitimate developer activity.
What the Standards Require
PCI DSS v4.0.1 Requirement 6.3.2 mandates that you maintain an inventory of bespoke and custom software, and third-party software components. This includes package dependencies. The requirement exists because you cannot secure what you don't track. When @cap-js/sqlite v2.2.2 appeared in your dependency tree, did your inventory system flag it? Did anyone review what changed between v2.2.1 and v2.2.2?
Requirement 11.6.1 requires you to deploy a change-detection mechanism to alert personnel to unauthorized modifications of HTTP headers and the contents of payment pages. While this requirement focuses on payment pages, the principle extends to your build pipeline. Unexpected preinstall scripts are unauthorized modifications.
NIST 800-53 Rev 5 Control SA-12 (Supply Chain Protection) requires organizations to employ supply chain risk management processes and tools. This includes validating the integrity of software throughout the software development lifecycle. The control explicitly addresses third-party components.
Control SI-7 (Software, Firmware, and Information Integrity) requires integrity verification tools to detect unauthorized changes to software and firmware. Your package manager should verify checksums, but that only confirms the package matches what npm distributed — not that npm distributed what SAP intended.
ISO/IEC 27001:2022 Control 8.31 (Separation of Development, Test and Production Environments) requires you to separate these environments to reduce the risk of unauthorized access or changes. If your CI/CD agents can access production secrets during npm install, you've violated this separation principle.
Lessons and Action Items
Lock your dependencies with checksums
Move from package.json ranges to exact versions in package-lock.json, but go further. Use npm's integrity checksums to verify that the package content matches what you initially installed. Tools like npm ci enforce this, but you need to commit your lockfile and treat it as security-critical.
Audit preinstall and postinstall scripts
Create a policy: no package with install-time scripts enters your environment without review. Use npm config set ignore-scripts true globally, then explicitly allowlist packages after manual inspection. Yes, this breaks some legitimate packages. That's the point — it forces you to make conscious decisions about code execution.
Implement least-privilege CI/CD credentials
Your build agents need deployment credentials, but they don't need them during dependency installation. Restructure your pipeline so that npm install runs in an isolated stage with no access to secrets. Pass credentials only to the deployment stage after your build artifacts are created.
Monitor dependency changes in real-time
Deploy tooling that alerts you when dependencies change, even within your specified version ranges. Socket and Aikido detected this attack through behavioral analysis. You need similar visibility. When a package suddenly adds a preinstall script or makes network requests during installation, that's a signal worth investigating.
Verify package signatures when available
npm now supports package signatures through npm provenance. Configure your environment to require provenance attestations for critical dependencies. This won't catch every attack, but it raises the bar by requiring attackers to compromise signing infrastructure, not just publishing credentials.
Segment your network at the build stage
Your CI/CD environment should operate under strict egress filtering. GitHub access is necessary, but does your build process need to reach arbitrary domains? Create an allowlist. The dead-drop technique used here would still work, but you'd have visibility into what your build process contacts.
Test your dependency update process
Run a tabletop exercise: a critical package in your stack is compromised. How long until you detect it? How do you roll back? Who decides whether to pause deployments? The SAP incident gave organizations a two-week window. Most didn't use it because they didn't know they needed to.
The SAP compromise demonstrates that supply-chain security isn't about trusting vendors less — it's about building systems that remain secure even when trust fails. Your dependency management process should assume that any package, from any source, might be compromised. Design accordingly.



