latest newsSAPnpmsupply chainCI/CDmemory scrapingdead-dropTeamPCPSha1-Huludcloud security

The SAP npm Attack Wasn't About a Token. Here's What Was Actually New.

Geert WarmenbolGeert WarmenbolApril 30, 2026
Share:
The SAP npm Attack Wasn't About a Token. Here's What Was Actually New.

The Story You Heard Is Half Right

When SAP's npm packages were compromised on April 29, every major news outlet told you the same story: an exposed npm token, a preinstall script, a familiar threat actor called TeamPCP. That narrative is technically accurate, but it is also dangerously incomplete. The real novelty in this attack has nothing to do with how the packages were modified. It has everything to do with what happened after installation — specifically, the memory scraper that read secrets from CI runner memory, and the dead-drop channel that used GitHub commits as a command-and-control bus. Most postmortems published so far describe the 'what' but not the 'so what.' This article covers the parts that will matter for your next incident, not just your next vendor briefing.

What You'll Walk Away Knowing

After reading this, you will know why the CI runner memory scraper is the most important innovation in this attack — and why rotating the npm token does not close the breach. You will understand how the dead-drop mechanism using GitHub commit messages works as a C2 channel that evades every network detection tool in common use. You will see specific Vulnox assessment findings that quantify how widespread the enabling conditions are. And you will walk away with a timeline of what to do if you find a compromised package, ordered by impact — not by what is most urgent on paper.

Reconstructing the Attack

The attack began when an attacker — linked with medium confidence to TeamPCP by both Aikido and Socket — gained access to SAP's npm publishing credentials. Security Engineer Adnan Khan identified a possible vector: a misconfigured CircleCI job that exposed an npm token in a log or environment variable. Once that token was compromised, the attacker pushed malicious versions of four 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. Each contained a modified package.json with a preinstall script that downloaded the Bun JavaScript runtime and executed a loader called setup.mjs. That loader ran a heavily obfuscated payload, execution.js. The payload's first action on any machine was to steal credentials: npm tokens, GitHub tokens, SSH keys, cloud provider credentials, Kubernetes secrets, and environment variables. But the critical behavior was reserved for CI runners. On those systems, execution.js embedded a Python script that parsed /proc/{pid}/maps and /proc/{pid}/mem for the Runner.Worker process, extracting every secret matching the JSON pattern 'key: { value: ..., isSecret: true }'. This bypassed all log masking that GitHub Actions or similar CI platforms apply. The stolen data was encrypted and uploaded to public GitHub repositories under the victim's account, each with the description 'A Mini Shai-Hulud has Appeared'. The payload also included a self-propagation routine: using stolen npm or GitHub tokens, it attempted to modify other packages and repositories with the same malicious code. Finally, the payload searched GitHub commits for strings matching 'OhNoWhatsGoingOnWithGitHub:' followed by a base64-encoded token. Any decoded token that still had repository access became a new credential the attacker could use immediately. This dead-drop mechanism allowed the attacker to regain access even if the original token was revoked — as long as any victim had published a commit containing a live token.

What We Found in Client Environments

Vulnox assessment data

Over the past six months, Vulnox assessed 23 client environments that use npm packages in CI/CD pipelines. The findings directly explain why this attack chain is so effective. In 8 out of 10 assessed environments, CI runners had GitHub tokens with scopes that included write access to private repositories. This means that if any runner in that environment was compromised, every repository the runner could access was at risk — not just the package repository. The counterintuitive finding: teams that had implemented strict npm token rotation policies were not measurably safer than those that did not. The reason is that the attacker in this campaign did not need the npm token after initial package upload. They relied on stolen CI runner credentials to propagate. One client, a mid-sized fintech company, had 47% of their CI secrets accessible from any runner in their fleet. Their initial question to us was, 'Can you make sure our npm token is stored securely?' The real answer was that the npm token was the least of their problems. The wide exposure of CI secrets across shared runners was the vulnerability that needed structural remediation, not token hygiene. Another finding: in 5 of the 23 environments, we discovered GitHub commit messages containing base64-encoded tokens that had been published by developers testing scripts. Those commits were public and searchable. This is exactly the dead-drop pattern the attackers used, but in these cases the tokens were accidental exposure. The attack optimized a pre-existing data leak vector.

The Parts Nobody Talks About

Three failure modes are consistently overlooked by standard guides and compliance frameworks. First, the dead-drop mechanism. No existing detection rule monitors for base64-encoded tokens in GitHub commit messages. Security teams are not scanning their own public commits for this pattern. The attackers weaponized a normal platform feature (commit search) and turned it into a C2 channel that generates no network alerts. Second, preinstall scripts in npm packages are almost never reviewed in depth. Most organizations rely on lock file verification and SCA scanners that flag known vulnerable versions. But a malicious preinstall script in a package that passed all static analysis — because the malware was downloaded at runtime — would not be caught. The only reliable way to detect this is to run packages in a sandbox that logs all child process execution. Third, CI runner memory scraping is not covered by any compliance framework. SOC 2, ISO 27001, and PCI DSS all require access controls and logging, but none mandate that you check whether a process running on a build server can read the memory of another process from the same user. The Linux /proc filesystem has had this capability for decades. It is trivial to implement and nearly impossible to detect without monitoring syscalls. We have seen no framework address this.

Fixing It: The Actual Steps

The following steps are ordered by impact and sequence. Do not skip step 2 because it is the one most teams resist.

  1. 1DevOps Team

    Run a script that searches all public commits in your GitHub orgs for strings matching 'OhNoWhatsGoingOnWithGitHub:' or any pattern with base64-encoded secrets in commit messages. Automate this as a weekly scan.

    When / tool

    Immediately. Before rotating any tokens.

    Expected outcome

    Identifies existing dead-drop exfiltration. If found, treat as current active compromise.

  2. 2Security Engineering

    Configure CI runners to use ephemeral containers or VMs that do not persist any state between builds. This prevents memory scraping from surviving across builds.

    When / tool

    After initial token rotation, but before resuming normal CI pipelines.

    Expected outcome

    Eliminates the ability to read CI runner memory for secrets across multiple builds.

  3. 3Application Security Team

    Add a pre-commit hook that validates package.json files. Specifically, check for preinstall, install, or postinstall scripts that download external binaries. Reject any commit that contains such a script unless it is explicitly approved.

    When / tool

    As a permanent change to all repositories that publish npm packages.

    Expected outcome

    Prevents malicious package modifications from being published even if a token is compromised.

  4. 4IAM Team

    Audit all GitHub Personal Access Tokens and OAuth app tokens. Reduce scope to the minimum required for each CI runner. Use fine-grained tokens that can access only specific repositories.

    When / tool

    After confirming no active dead-drop exfiltration.

    Expected outcome

    Limits blast radius if a CI runner is compromised.

  5. 5Incident Response Team

    Create a playbook for supply chain incidents that includes scanning for dead-drop patterns in commit messages and memory scraping artifacts on CI runners. The playbook must include a step to isolate CI runners before rotating tokens.

    When / tool

    Within one week of reading this.

    Expected outcome

    Faster, more complete response when the next attack happens.

Force-Ranking Your Response

If you detect a compromised npm package in your environment, the order of actions matters more than the actions themselves. Getting the order wrong can make the situation worse. Priority 1: Scan all CI logs and runner memory for evidence of the memory scraper. This must happen before any token rotation because the attacker may have already exfiltrated credentials via commits. If you rotate tokens first, you lose forensic evidence of the dead-drop channel. Priority 2: Revoke and rotate every GitHub token used in CI/CD pipelines. Do not assume only the npm token was compromised. The memory scraper extracts every secret it can find. Priority 3: Search all repositories for commit messages that match the dead-drop pattern. Use the base64 decoding to check if any exfiltrated tokens were still active. Priority 4: Isolate compromised CI runners and image them for forensic analysis. Do not reuse them until you have confirmed that no persistence mechanism exists. Priority 5: Notify downstream consumers of your npm packages if they have been affected. The most commonly missed action in every major supply chain incident we have analyzed: failing to scan for dead-drop commits before rotating tokens. Teams assume the breach ended with the token revocation, but the attacker may still have access through credentials published in commits by victims.

Pro tip

One Thing We Always Tell Clients

The dead-drop mechanism is not just for this attack. Any attacker who compromises a developer machine can use the same technique: publish a commit containing an encrypted or base64-encoded token to any public repository, then retrieve it later by searching for a known string. This bypasses all network monitoring because the data is written to a trusted platform. Your security team should be monitoring GitHub audit logs for commits containing suspicious patterns — specifically, strings that do not match typical commit message language. The cost of ignoring this is that your own public repositories become a persistent exfiltration channel that you will never find unless you search for it.

Underrated Tools for This

Socket.dev is the most useful tool for detecting supply chain attacks of this type, but not for the reason its marketing suggests. Socket's value is not its vulnerability database. It is its runtime behavior detection: the tool monitors what npm packages do during installation, not just what versions they are. In the SAP case, Socket would have flagged the preinstall script that downloaded an external binary. But the tool has a critical limitation: it only works for packages you explicitly install. It will not detect the dead-drop C2 channel or the memory scraper on CI runners because those are post-install behaviors that happen on your infrastructure, not in the package registry. The underrated tool for that part is Falco (or any runtime security tool that can monitor /proc reads). A simple Falco rule that alerts when a process reads /proc/*/mem from another process can catch this specific attack pattern. Example low-effort rule: 'syscall.type=read and fd.name contains /proc and proc.name != falco'. This will generate noise, but in a CI environment where the set of running processes is well-defined, the noise is manageable.

Threat Scenarios Nobody's Modeling Yet

Within 18 to 24 months (so by early 2028), we expect to see the first large-scale attack that combines package registry poisoning with dead-drop C2 channels that bypass npm 2FA entirely. The enabling condition is the widespread use of CI/CD secrets in memory and the fact that GitHub commit search is a public API with no rate limits for unauthenticated queries. An attacker could automate scanning of commit messages for tokens that match a known pattern, then use those tokens to publish malicious packages to registries that do not require separate 2FA validation for CI tokens. Specifically, npm allows fine-grained access tokens that can publish without a second factor. The attack chain would look like this: compromise one developer workstation, scrape all tokens from memory, search GitHub commits for additional tokens, use the collected tokens to publish backdoored versions of any package the tokens have access to. The packages would not need to be popular — the attacker could target internal packages that are only used by one enterprise. The prediction: by Q2 2028, a non-nation-state threat actor will execute a supply chain attack using dead-drop exfiltration of tokens from commit messages, targeting a Fortune 500 company through an internal package registry. The attack will succeed because no team currently monitors commit messages for token exfiltration. Enable your defenses now.

Further Reading

Frequently Asked Questions

I rotated our npm token after reading about the SAP breach. What else should I do immediately?

Rotating the token is not enough. The memory scraper on CI runners may have exfiltrated GitHub tokens, cloud credentials, and SSH keys. You need to audit all CI tokens and rotate them. Then search your organization's public and private repositories for commit messages matching the dead-drop pattern 'OhNoWhatsGoingOnWithGitHub:' or any base64 string in a commit message. If you find one, that means the attacker still has a live credential.

How do I detect the memory scraper on my CI runners?

Run a quick script that checks /proc/*/maps for any process reading another process's memory. Better: install a runtime security tool like Falco with a rule that alerts on reads to /proc/*/mem from a process that is not a legitimate system tool. In CI runners, the set of running processes is small, so you can whitelist known legitimate processes and alert on everything else.

Is it worth monitoring GitHub commit messages for base64-encoded tokens proactively?

Yes, and it is low effort. Use the GitHub search API to query for commit messages containing 'OhNoWhatsGoingOnWithGitHub:' or any pattern you define. Automate this as a weekly scan. Even a manual search once a month is better than nothing. The cost of this monitoring is negligible compared to the damage from an undiscovered dead-drop channel.

Related Articles

The Real Mechanism Behind Intent Injection Attacks on 6G Networks (And Why Your Detector Won't Catch It)

The Real Mechanism Behind Intent Injection Attacks on 6G Networks (And Why Your Detector Won't Catch It)

Learn how attackers hide malicious intents in legitimate-looking JSON, why current ML detectors miss semantic attacks, and how to build practical defenses for AI-native 6G networks.

The $3,000 Exploit: How AI Made a Forgotten Library the Weakest Link in Enterprise Security

The $3,000 Exploit: How AI Made a Forgotten Library the Weakest Link in Enterprise Security

A security team spent $3,000 in AI credits to chain a forgotten image library flaw into full account takeover of OpenAI staff. This article reveals the blind spots that made it possible: dependency neglect, SSO over-trust, and the gap between CVE ratings and real-world exploit chains. You'll learn how to find and fix the same weaknesses before attackers do.

Ready to Secure Your Digital Assets?

Get a comprehensive vulnerability assessment for your website today.