Executive Summary

Our research team identified a sophisticated supply chain attack targeting SAP Cloud Application Programming (CAP) framework packages. The campaign demonstrates advanced techniques for compromising trusted publishing pipelines and injecting malicious code directly into enterprise CI/CD workflows.

The activity has been attributed to TeamPCP, a financially motivated threat actor known for large-scale supply chain compromises and cloud-focused post-exploitation campaigns. This attribution is based on shared cryptographic artifacts, overlapping infrastructure, and reuse of obfuscation and encoding routines observed in prior operations.

On April 29, 2026, malicious versions of four SAP-related npm packages were published following unauthorized modifications to a repository release workflow. The attacker leveraged GitHub’s OIDC-based trusted publishing mechanism to extract short-lived npm publish tokens and release compromised packages to the registry.

The payload deploys the Bun JavaScript runtime to execute heavily obfuscated code, likely to evade detection mechanisms focused on Node.js execution patterns.

Affected Packages

The following malicious package versions were published and should be considered compromised:

Any installations of these versions between 09:55 UTC and 14:00 UTC on April 29, 2026 should be considered compromised. Organizations using SAP CAP framework packages should immediately audit their dependencies and follow the response actions outlined below.

What is SAP

SAP is one of the world’s largest enterprise software companies, providing business management software to over 440,000 customers globally. The SAP Cloud Application Programming (CAP) framework is a development platform for building enterprise applications that integrate with SAP’s business systems. The targeting of CAP packages represents a strategic shift toward enterprise-focused supply chain attacks, as these frameworks are predominantly used in large-scale business environments with access to critical corporate data and systems.

Technical Breakdown

Stage 1: Initial Compromise

The attack begins with two independent, parallel infrastructure compromises executed to obtain publishing credentials through different mechanisms.

Vector A: CircleCI Token Exfiltration

Analysis of CircleCI build logs reveals the first compromise vector. On April 29, a brief draft pull request (#1223) titled “feat: ci speedup” was opened from the account gruposbftechrecruiter/harkonnen-navigator-149. The PR triggered automated CircleCI builds with access to npm publishing tokens through environment variables.

The malicious commit (a959014aa7b7fc37a9b5730c951776e7db2920a6) added a Bun loader at bin/config.mjs, an obfuscated payload at bin/mbt.js, and modified the test command to execute the token exfiltration logic. The PR was closed within minutes and the branch force-pushed to remove evidence, but CircleCI retained the build artifacts that reveal the attack mechanism.

Vector B: GitHub Actions OIDC Abuse

The second vector targeted GitHub Actions runners directly through repository manipulation. The attacker pushed commit 0a3dd44 to the update/releases branch of cap-js/cds-dbs under the spoofed identity [email protected]. This commit modified release-please.yml to execute on the non-standard branch and replaced legitimate publish steps with malicious OIDC token extraction logic.

Stage 2: Malicious Package Publication

With publishing credentials secured through both compromise vectors, the attacker published four malicious packages to the npm registry within a two-hour window. The cloudmtabot token stolen via CircleCI was used to publish [email protected] at 09:55 UTC, while the OIDC token extracted from the GitHub Actions workflow was used to publish the three @cap-js packages at 11:25 UTC.

After publishing, commit eca039d injected persistence files into the cap-js/cds-dbs repository, followed by cleanup commit 4ae7eb0 that removed the OIDC token extraction code in an attempt to hide the attack. The compromised workflow (run 25108178873) was eventually terminated and the branch force-reverted, but the malicious packages had already propagated through the npm registry.

Stage 3: Victim Impact

3.1: Package Installation and Preinstall Execution

When developers or CI/CD systems install any of the compromised packages, the attack triggers immediately through npm’s preinstall hook. Each malicious package contains a package.json entry specifying “preinstall”: “node setup.mjs”, which executes before the package installation completes – meaning the attack succeeds even if the install is later aborted due to dependency conflicts, network issues, or security scanning.

The preinstall hook deploys two files to the target system:

setup.mjs (Dropper): A lightweight JavaScript module responsible for initial system reconnaissance and bootstrapping the main payload.

execution.js (Main Payload): The 11.7MB obfuscated file containing the complete attack toolkit, including credential harvesting logic, exfiltration mechanisms, and persistence installation.

The execution.js file implements a sophisticated three-layer obfuscation scheme to resist analysis. The first layer uses string table obfuscation with approximately 49,000 entries, a custom base64 alphabet, and index rotation to obscure lookup operations. The second layer protects sensitive strings (credential paths, environment variable names, API endpoints) through PBKDF2 key derivation with per-byte SHA256 transformations across roughly 200,000 iterations. The third layer embeds compressed components including GitHub workflow manipulation logic, AI tool configuration injection capabilities, memory extraction scripts, and an RSA public key used for key wrapping during exfiltration.

The dropper completes its work within seconds of npm install, making detection particularly challenging since the malicious activity begins before traditional package scanning or approval processes can intervene.

3.2: Runtime Bootstrap via Bun

Once the preinstall hook fires, setup.mjs performs OS and architecture detection, then downloads Bun 1.3.13 from GitHub releases to execute the main payload. Bun is a high-performance JavaScript runtime designed as a drop-in replacement for Node.js, offering full API compatibility with faster startup and execution times.

The choice of Bun is deliberate – using a non-standard runtime allows the attacker to bypass detection logic that monitors Node.js execution patterns. After launching execution.js through Bun, the dropper cleans up its artifacts and the temporary Bun binary to reduce forensic visibility.

Stage 4: Post-Compromise Operations

4.1: Environment Checks and Evasion

Before initiating malicious activity, the payload performs two environment checks designed to control where it runs and how it persists:

Russian Locale Check: The malware immediately exits with exit(0) if it detects Russian language settings on the host. This guardrail strongly suggests the operators want to avoid prosecution in Russian-speaking jurisdictions, a common pattern among financially motivated threat actors operating from those regions.

CI/CD Environment Detection: The payload checks against 32 known CI platform indicators to determine its execution context. On developer machines, it daemonizes by forking a detached child process while the parent exits, allowing the malware to survive after the npm install command completes. On CI/CD systems, it runs inline to maximize execution time within the pipeline before the runner terminates.

4.2: Credential Harvesting

The malware deploys five parallel credential collectors, each targeting a specific platform or credential type:

  • npm tokens: Reads ~/.npmrc and environment variables for npm authentication credentials
  • AWS credentials: Extracts standard credential files and performs Secrets Manager dumps via the AWS SDK
  • GCP credentials: Harvests credential databases and dumps Secret Manager contents
  • Azure credentials: Uses the Azure Identity SDK to extract authentication tokens
  • GitHub tokens: Collects standard tokens and dumps GitHub Actions runner memory via /proc/{pid}/mem

In addition to these targeted collectors, a file harvester scans specific paths covering SSH keys, cryptocurrency wallets, VPN profiles, database history files, and AI assistant configuration files. The targeting of AI assistant configurations is particularly notable – files like ~/.claude.json and ~/.kiro/settings/mcp.json define internal tools, APIs, and integrations, exposing an organization’s operational surface far beyond traditional credentials.

4.3: GitHub-Based Exfiltration

Harvested data is encrypted using AES-256-GCM with keys wrapped via RSA-4096-OAEP using the attacker’s embedded public key. The encrypted payload is then uploaded to public GitHub repositories created on the victim’s own account, serving as dead-drops that the attacker can later access. This technique routes exfiltration through legitimate GitHub traffic, making it indistinguishable from normal repository activity in network logs.

4.4: npm Self-Propagation

When the harvested credentials include valid npm tokens, the malware attempts worm-like propagation across additional packages. It first validates each token by checking if it bypasses 2FA requirements and inspecting its scopes. For tokens with sufficient privileges, the malware enumerates all packages owned by the victim’s organization, then republishes them with hand-rolled PUT requests directly to registry.npmjs.org to avoid detection by npm CLI tooling.

This capability could exponentially expand the campaign’s reach by infecting every package the compromised account can publish, creating a self-propagating supply chain worm similar to the original Shai-Hulud incident.

4.5: Workflow Injection and IDE Persistence

The malware establishes persistence through two parallel mechanisms targeting both CI/CD pipelines and developer environments.

GitHub Workflow Injection: For each accessible repository, the malware creates a new branch (using patterns like dependabout/…/setup-formatter) and commits a malicious workflow that exports toJSON(secrets) to a downloadable artifact. After dispatching the workflow, the malware polls for completion to retrieve the dumped GitHub Actions secrets context, capturing the complete set of secrets configured in the repository.

IDE Persistence: The malware commits files to all accessible repositories that trigger execution through development tools when the repository is opened:

  • .vscode/tasks.json configured with runOn: folderOpen – executes when VSCode opens the project folder
  • .claude/settings.json configured with a SessionStart hook – executes when Claude Code starts a session
  • Self-copies of execution.js and setup.mjs placed in the repository for re-infection

This transforms compromised repositories into propagation vectors. Any developer who clones a repository and opens it in VSCode or Claude Code triggers the dropper, even if they never directly install the malicious npm package.

Indicators of Compromise (IOCs)

CategoryIndicatorNotes
Malicious Packages@cap-js/[email protected]Published 11:25 UTC, April 29, 2026
Malicious Packages@cap-js/[email protected]Published 11:25 UTC, April 29, 2026 (since unpublished)
Malicious Packages@cap-js/[email protected]Published 11:25 UTC, April 29, 2026
Malicious Packages[email protected]Published 09:55 UTC, April 29, 2026 via stolen token
File Artifactssetup.mjsPreinstall dropper script
File Artifactsexecution.js11.7MB obfuscated payload
File Artifactsbin/config.mjsBun loader added via malicious PR
File Artifactsbin/mbt.jsObfuscated payload in PR attack
Persistence Files.vscode/setup.mjsIDE integration dropper
Persistence Files.vscode/tasks.jsonVSCode task configuration
Persistence Files.claude/settings.jsonClaude AI configuration hook
Persistence Files.claude/setup.mjsClaude AI dropper copy
Persistence Files.claude/execution.jsClaude AI payload copy
GitHub Commits0a3dd44Initial malicious workflow modification
GitHub Commitseca039dPersistence file injection commit
GitHub Commits4ae7eb0Cleanup commit removing OIDC code
GitHub Commitsa959014aa7b7fc37a9b5730c951776e7db2920a6CircleCI token exfiltration commit
GitHub Identities[email protected]Spoofed commit identity (unsigned)
GitHub Accountsgruposbftechrecruiter/harkonnen-navigator-149Malicious PR source account
GitHub Branchesupdate/releasesNon-standard branch for workflow abuse
GitHub PRs#1223 in SAP/cloud-mta-build-toolToken exfiltration PR
Email Addresses[email protected]Compromised service account
Service AccountscloudmtabotLegitimate npm publishing account
GitHub RepositoriesRepositories with description “A Mini Shai-Hulud has Appeared”Exfiltration dead drops
Workflow Filesrelease-please.ymlModified to trigger on non-main branch
Process IndicatorsBun runtime execution during npm installUnusual JavaScript runtime
Process IndicatorsForked detached child processes from npm installDaemonization on developer machines
Network Indicatorsgithub.com/oven-sh/bun/releases/download/bun-v1.3.13/Bun runtime download
Network IndicatorsDirect PUT requests to registry.npmjs.orgnpm self-propagation bypass
GitHub BranchesBranches matching dependabout/…/setup-formatter patternWorkflow injection branches
BehavioralRussian locale check causing immediate exitGeographic targeting guardrail
BehavioralPublic repository creation on victim accountsExfiltration dead-drops
Attack MarkersOhNoWhatsGoingOnWithGitHubString marker in malware
Commit Messagesfeat: ci speedupMalicious PR title
Commit Messagesfix: ciRepository compromise commit message
File Paths/proc/{pid}/memCI runner memory extraction target
EncryptionRSA-4096 public keysEmbedded in payload for key wrapping
EncryptionAES-256-GCMData encryption for exfiltration
ObfuscationPBKDF2 with salt ctf-scramble-v2String protection mechanism

Immediate Response Actions

Identify Exposure

Audit lockfiles for affected versions installed during the attack window.

Rotate Credentials

Immediately rotate cloud credentials, npm tokens, SSH keys, GitHub tokens, and AI assistant configuration credentials.

Repository Audit

Search for unauthorized workflow changes, suspicious configuration files, and unknown commits modifying CI/CD pipelines.

Package Integrity

Validate for unexpected preinstall scripts, missing provenance attestations, and unusual package size changes.

Detection and Prevention

Organizations should tighten trusted publishing by restricting OIDC usage to specific workflows and branches while avoiding repository-wide trust configurations. Enforce commit verification by requiring signed commits for workflow changes.

Monitor CI behavior to detect unexpected runtime downloads such as Bun and alert on unusual workflow modifications. Track provenance by monitoring for missing or altered SLSA attestations, and maintain runtime visibility to detect execution during install phases and monitor credential access patterns.

The Bigger Picture

This campaign reflects a clear shift in supply chain attacks from package injection to pipeline compromise, from credential theft to token extraction at runtime, and from endpoint malware to developer ecosystem targeting.

The attack also highlights a growing focus on AI-integrated development environments. By targeting AI assistant configuration and MCP tooling, attackers gain visibility into internal systems, APIs, and workflows that extend far beyond traditional credential access.

Rather than relying on social engineering or stolen credentials alone, this operation demonstrates how attackers can directly manipulate trusted automation systems to distribute malicious code at scale. As organizations increasingly rely on automated publishing and AI-assisted development, these systems become part of the attack surface and require the same level of security rigor as production infrastructure.

How Upwind Detects This Attack

Upwind’s runtime security platform identifies this attack chain at multiple points, providing visibility across CI/CD pipelines, developer workstations, and cloud workloads through eBPF-based runtime monitoring.

CI/CD Runtime Visibility: During npm install, Upwind detects the preinstall hook spawning setup.mjs, the subsequent download of the Bun runtime from GitHub releases, and the execution of the obfuscated execution.js payload. These events are correlated to a single build context, distinguishing legitimate package installation from supply chain compromise.

Anomalous Credential Access: The platform monitors access to sensitive files including ~/.npmrc, cloud provider credentials (~/.aws/, ~/.azure/, ~/.config/gcloud/), SSH keys, and AI assistant configurations. The five parallel credential collectors used by this malware produce a distinctive access pattern that triggers high-confidence detections.

Memory Extraction Detection: Upwind detects unauthorized reads of /proc/{pid}/mem targeting GitHub Actions runner processes, catching the in-memory secret extraction technique used to bypass on-disk credential protections.

Egress Anomalies: The platform identifies suspicious outbound connections during package installations, including direct PUT requests to registry.npmjs.org from non-CLI processes (indicating self-propagation attempts) and public repository creation on user accounts that match exfiltration dead-drop patterns.