What Happened
On September 15, 2025, attackers published malicious versions of ngx-bootstrap and ng2-file-upload to the npm registry. These compromised packages were designed to exfiltrate cloud credentials, API keys, and secrets from developer machines and CI/CD environments. Although the packages were quickly removed from npm, they were downloaded and integrated into build pipelines across organizations using Angular applications.
The attack targeted on-disk credentials—such as AWS keys, GitHub tokens, and service account credentials stored in configuration files or environment variables. If your build process installed these packages, the malicious code scanned your filesystem, collected credentials, and transmitted them to attacker-controlled infrastructure.
Timeline
September 15, 2025: Malicious versions of ngx-bootstrap and ng2-file-upload published to npm registry.
September 15-17, 2025: Packages downloaded by automated dependency updates and manual installations. Malicious code executes during npm install lifecycle hooks, scanning for credentials.
September 17, 2025: Snyk and other security researchers identify the compromised packages. npm registry maintainers remove malicious versions.
Post-September 17: Organizations begin incident response—credential rotation, environment scanning, and impact assessment.
The 48-hour window between publication and detection was a critical exposure period. If your CI/CD pipeline ran during this time and pulled these packages, you should assume credential compromise.
Which Controls Failed or Were Missing
Dependency verification: Teams installed packages without verifying cryptographic signatures or comparing checksums against known-good versions. Although npm supports package signing, most organizations don't enforce signature verification in their build pipelines.
Least-privilege credential access: Developers and CI/CD runners had access to long-lived credentials stored on disk. The malicious package executed with the same permissions as the build process, accessing everything in that environment—AWS credentials in ~/.aws/credentials, GitHub tokens in environment variables, and service account keys in project directories.
Filesystem isolation: Build processes ran with full access to the developer's home directory or the CI/CD runner's filesystem. No sandboxing or containerization prevented the malicious code from reading arbitrary files.
Network egress controls: The exfiltration occurred over standard HTTPS connections. Without network segmentation or egress filtering, the malicious code transmitted stolen credentials to external endpoints without triggering alerts.
Dependency update review: Automated dependency updates (Dependabot, Renovate) merged package version changes without human review of the package contents or behavioral changes.
What the Relevant Standards Require
PCI DSS v4.0.1 Requirement 6.3.2 mandates that custom software be developed securely based on industry standards. This includes securing the software development environment itself. If your cardholder data environment (CDE) includes CI/CD infrastructure, those systems must meet the same security controls as production. Storing credentials on disk in CI/CD runners that process CDE deployments violates secure development principles.
PCI DSS v4.0.1 Requirement 8.3.2 requires authentication credentials to be protected during transmission and storage using strong cryptography. Long-lived credentials stored in plaintext configuration files—even in a "secure" CI/CD environment—fail this requirement. Use secrets management systems like HashiCorp Vault, AWS Secrets Manager, or Azure Key Vault to provide credentials dynamically and rotate them automatically.
NIST 800-53 Rev 5 Control SA-15 requires organizations to maintain security controls throughout the software development lifecycle, including the tools and dependencies you use. This means verifying the integrity of third-party components before integrating them.
ISO 27001 Control 8.31 requires logical separation between environments. When your CI/CD pipeline has the same credential access as production systems, you've violated this separation. A compromised build tool shouldn't access production AWS accounts or GitHub repositories.
SOC 2 Type II CC6.6 requires that access to data and systems be restricted to authorized users. CI/CD runners with permanent access to production credentials fail this requirement. Use ephemeral credentials that exist only for the duration of a specific build job.
Lessons and Action Items for Your Team
Rotate every credential that existed in any environment where these packages ran. If you ran builds between September 15-17, rotate everything: AWS keys, GitHub tokens, database passwords, API keys, service account credentials. The exfiltration was silent; you won't know what was taken until you see it used.
Implement package signature verification in your build pipeline. Configure npm to require signatures for packages from specific scopes or publishers. Add --ignore-scripts to your npm install commands in CI/CD to prevent lifecycle hooks from executing automatically, then explicitly run only the scripts you've reviewed.
Replace long-lived credentials with short-lived tokens. Use OIDC federation between your CI/CD platform (GitHub Actions, GitLab CI, CircleCI) and your cloud provider. GitHub Actions can assume AWS IAM roles directly without storing credentials—the token exists for 15 minutes and can't be reused. This eliminates the credential theft vector entirely.
Run builds in isolated containers with read-only filesystems. Mount only the specific directories needed for the build. If your CI/CD runner uses Docker, add --read-only and --tmpfs /tmp to prevent the build process from writing to persistent storage. Use --network=none for build steps that don't need internet access.
Deploy network egress controls for CI/CD environments. Allow outbound connections only to your package registries, cloud provider APIs, and version control systems. Block everything else by default. Use DNS filtering or proxy-based egress gateways that log all outbound connections—when a build suddenly connects to an unfamiliar domain, you'll see it.
Review every automated dependency update before merging. Don't let Dependabot or Renovate auto-merge version bumps. Require that a human reviews the package diff—not just the version number change, but the actual code changes in the new version. For critical packages, download the tarball and inspect it manually.
Scan your environment for indicators of compromise. Check CloudTrail logs for API calls from unexpected IP addresses. Review GitHub audit logs for repository access from unfamiliar locations. Look for AWS credentials that were used outside your normal geographic regions or during off-hours. The attackers may have already used stolen credentials—you need to find that activity.
The Shai-Hulud attack succeeded because it exploited the gap between how we think about security (production systems, customer data) and where vulnerabilities actually exist (developer machines, build pipelines, dependency chains). Your CI/CD environment isn't a staging area—it's part of your production infrastructure, and it needs the same controls.



