Protecting Astro from Supply Chain Attacks: Part 1 - Understanding Shai-Hulud 2.0 and Immediate Response

$50 off using BLACKFRIDAY

Sale ends in
11d 12h 54m 25s
LaunchFast Logo LaunchFast

Protecting Astro from Supply Chain Attacks: Part 1 - Understanding Shai-Hulud 2.0 and Immediate Response

Rishi Raj Jain
Protecting Astro from Supply Chain Attacks Part 1

This is Part 1 of a 3-part series on protecting Astro websites from npm supply chain attacks. In this article, we’ll cover understanding the threat and immediate response actions. Check out Part 2 for long-term security measures and Part 3 for best practices and monitoring.

High Quality Starter Kits with built-in authentication flow (Auth.js), object uploads (AWS, Clouflare R2, Firebase Storage, Supabase Storage), integrated payments (Stripe, LemonSqueezy), email verification flow (Resend, Postmark, Sendgrid), and much more. Compatible with any database (Redis, Postgres, MongoDB, SQLite, Firestore).
Next.js Starter Kit
SvelteKit Starter Kit

In November 2025, the npm ecosystem faced one of its most significant supply chain attacks to date: Shai-Hulud 2.0. This attack compromised over 700 npm packages, including popular libraries from Zapier, PostHog, and Postman, affecting roughly 27% of cloud and code environments. The malware executed during the preinstall phase, stealing credentials from GitHub, AWS, GCP, Azure, and other services, then exfiltrating them to public repositories.

According to Wiz Research, over 25,000 malicious repositories were created containing stolen secrets, with new repos appearing at a rate of ~1,000 every 30 minutes during the attack. If you’re running an Astro website, this guide will help you understand the threat and take immediate action.

Prerequisites

You’ll need the following:

  • Node.js 18 or later
  • An existing Astro project
  • Access to your CI/CD pipeline configuration
  • Administrative access to your package manager (npm, pnpm, or yarn)

1. Understanding the Shai-Hulud 2.0 Attack

The Shai-Hulud 2.0 attack leveraged compromised maintainer accounts to publish trojanized versions of legitimate npm packages. This wasn’t a new zero-day vulnerability or a sophisticated exploit-it was a compromise of trusted accounts that allowed attackers to publish malicious code under the guise of legitimate updates.

1.1 What Makes This Attack Different?

Unlike traditional attacks, this variant introduced several concerning characteristics:

1.1.1 Executes During preinstall Phase

The malware runs during the preinstall lifecycle hook, which dramatically widens the blast radius. This means:

  • It executes before any package installation completes
  • It runs on developer machines during npm install
  • It executes in CI/CD pipelines automatically
  • It can’t be easily prevented by typical security measures
// Example of how the malicious package.json looked
{
"scripts": {
"preinstall": "node malicious-script.js"
}
}

1.1.2 Steals Multiple Credential Types

The attack wasn’t limited to a single type of credential. It actively searched for and exfiltrated:

  • GitHub Tokens: Personal access tokens, OAuth tokens, and deploy keys
  • AWS Credentials: Long-term access keys (AKIA format), secret keys, and session tokens
  • GCP Credentials: Service account keys and application credentials
  • Azure Credentials: Service principal credentials and storage keys
  • Environment Variables: Any secrets stored in .env files or environment

1.1.3 Uses Cross-Victim Exfiltration

One of the most insidious aspects is that your stolen data might not even appear in your own GitHub account:

// Simplified example of the exfiltration logic
const victims = getRandomVictimAccounts()
const stolenData = gatherCredentials()
// Upload to ANOTHER victim's account
uploadToGitHub(victims[randomIndex], stolenData)

This means:

  • Your secrets could be in someone else’s public repository
  • Other victims’ secrets might appear in your account
  • Detection is significantly more difficult
  • The blast radius is much larger than initially visible

1.1.4 Creates Backdoor Workflows

The malware attempted to inject malicious GitHub Actions workflows for persistent access:

# Example of injected .github/workflows/discussion.yaml
name: Discussion Update
on:
push:
schedule:
- cron: '0 */6 * * *'
jobs:
exfiltrate:
runs-on: ubuntu-latest
steps:
- name: Gather More Secrets
run: |
# Malicious code here

1.1.5 Affects High-Prevalence Packages

The attack targeted packages that are widely used across the ecosystem:

  • @postman/tunnel-agent - Found in 27% of environments
  • posthog-node - Found in 25% of environments
  • @asyncapi/specs - Found in 20% of environments
  • Various Zapier platform packages

This maximized the attack’s reach, potentially affecting thousands of projects instantly.

1.2 Attack Timeline and Impact

Here’s what we know about the attack progression:

  • November 21-23, 2025: Initial compromise and upload of trojanized packages to npm

  • November 24, 2025 (01:22 UTC): Earliest evidence of repositories being created on GitHub with leaked secrets

  • November 24, 2025 (~03:00 UTC): Earliest evidence of malicious package versions on npm

  • November 25, 2025 (22:45 UTC): Potential second phase observed with private repositories being published

  • November 26, 2025: GitHub begins mitigation by revoking tokens and privatizing malicious repositories

Impact Statistics:

  • ~700 compromised packages on npm
  • 25,000+ malicious repositories created
  • ~500 affected GitHub users
  • 775+ compromised GitHub access tokens (verified)
  • 373+ AWS credentials leaked
  • 300+ GCP credentials exposed
  • 115+ Azure credentials compromised

The malware creates specific indicator files:

Terminal window
cloud.json # Cloud provider credentials
contents.json # Repository contents and code
environment.json # Environment variables and secrets
truffleSecrets.json # Secrets detected by TruffleHog patterns
bun_environment.js # Bun runtime environment data
setup_bun.js # Setup script for persistence

2. Immediate Actions to Take

If you suspect your Astro project might be affected, follow these steps immediately. Time is critical - the longer compromised credentials remain active, the more damage can occur.

2.1 Check Your Dependencies

First, verify if any of the compromised packages are in your dependency tree.

2.1.1 Quick Check Using pnpm Audit

Terminal window
# Run a security audit
pnpm audit fix
# Or with npm
npm audit --audit-level=moderate

2.1.2 Manual Inspection

Review your package.json and lock files for high-risk packages:

Terminal window
# Check for specific compromised packages
grep -E "@postman/tunnel-agent|posthog-node|posthog-js|@asyncapi/specs|zapier-platform" package.json pnpm-lock.yaml

2.1.3 Known Compromised Packages (Partial List)

Here are some of the most prevalent affected packages:

{
"high-prevalence-packages": [
"@postman/tunnel-agent",
"posthog-node",
"posthog-js",
"@asyncapi/specs",
"@asyncapi/openapi-schema-parser",
"zapier-platform-cli",
"zapier-platform-core",
"zapier-platform-schema",
"zapier-async-storage",
"get-them-args",
"shell-exec",
"kill-port"
]
}

2.1.4 Check Transitive Dependencies

The compromised packages might not be direct dependencies. Check your entire dependency tree:

Terminal window
# For pnpm
pnpm list --depth=Infinity | grep -E "postman|posthog|zapier"
# For npm
npm list --all | grep -E "postman|posthog|zapier"

2.1.5 Review Installation History

Check when packages were last installed to determine exposure window:

Terminal window
# Check git history of lock file changes
git log -p --follow pnpm-lock.yaml | grep -A 5 -B 5 "postman\|posthog\|zapier"

2.2. Audit Your Environment

Check for evidence of compromise in your local development environment and CI/CD systems.

2.2.1 Scan for Malicious Files

Terminal window
# Check for known malware indicator files
find . -type f \( \
-name "cloud.json" -o \
-name "contents.json" -o \
-name "environment.json" -o \
-name "truffleSecrets.json" -o \
-name "bun_environment.js" -o \
-name "setup_bun.js" \
\) 2>/dev/null

If this command returns any results, your environment has been compromised.

2.2.2 Check GitHub Workflows

Terminal window
# List all workflow files
ls -la .github/workflows/
# Check for the known malicious workflow
cat .github/workflows/discussion.yaml 2>/dev/null

The malicious workflow typically has:

  • Name: “Discussion Update” or similar
  • Suspicious cron schedules
  • Unusual environment variable access
  • Base64 encoded commands

2.2.3 Review Git History for Unauthorized Changes

Terminal window
# Check recent commits for suspicious changes
git log --all --oneline --decorate --graph -n 20
# Look for unexpected workflow additions
git log --all --full-history -- .github/workflows/

2.2.4 Check Your GitHub Repositories

Log into GitHub and check for:

  • Unexpected public repositories in your account
  • Repositories with names containing leaked data or credentials
  • Repository descriptions mentioning “Shai-Hulud” or suspicious content
  • Newly created repositories you didn’t create

2.2.5 Verify CI/CD Logs

Review your CI/CD pipeline logs for:

  • Unexpected network connections during builds
  • Failed authentication attempts
  • Unusual package installations
  • Build duration increases (malware execution takes time)
Terminal window
# Example: Check GitHub Actions logs
gh run list --limit 20
gh run view <run-id> --log

2.3 Rotate All Credentials

If you’ve identified any compromised packages or suspicious files, immediately rotate all credentials. Don’t wait to confirm the full extent of the compromise.

2.3.1 GitHub Tokens

  1. Navigate to GitHub Settings → Developer settings → Personal access tokens
  2. Review all existing tokens:
    • Note what each token is used for
    • Check last used date
  3. Revoke ALL tokens (even if they seem safe)
  4. Create new tokens with minimal required permissions:
Terminal window
# Use the principle of least privilege
# Instead of:
# - repo (full control)
# Use:
# - repo:status (read-only)
# - public_repo (if possible)
  1. Update tokens in:
    • CI/CD secrets (GitHub Actions, CircleCI, etc.)
    • Local development environments
    • Any automation scripts
    • Third-party integrations

2.3.2 AWS Credentials

Rotate AWS access keys immediately:

Terminal window
# 1. List current access keys
aws iam list-access-keys --user-name your-username
# 2. Create new access keys FIRST
aws iam create-access-key --user-name your-username
# Save the output immediately - you won't see it again
# 3. Update the new keys everywhere they're used:
# - CI/CD secrets
# - ~/.aws/credentials
# - Environment variables
# - Application configuration
# 4. Test that new keys work
aws sts get-caller-identity
# 5. Delete old access keys
aws iam delete-access-key \
--access-key-id AKIA_OLD_KEY_ID \
--user-name your-username

2.3.3 Important AWS Security Steps

Terminal window
# Check CloudTrail for unauthorized activity
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=Username,AttributeValue=your-username \
--max-items 100 \
--start-time 2025-11-20T00:00:00Z
# Review recent S3 bucket access
aws s3api get-bucket-logging --bucket your-bucket-name
# Check for unauthorized IAM changes
aws iam get-credential-report

2.3.4 GCP Credentials

For Google Cloud Platform:

Terminal window
# List service accounts
gcloud iam service-accounts list
# Create new key for a service account
gcloud iam service-accounts keys create new-key.json \
--iam-account=sa-name@project-id.iam.gserviceaccount.com
# List all keys for a service account
gcloud iam service-accounts keys list \
--iam-account=sa-name@project-id.iam.gserviceaccount.com
# Delete old keys
gcloud iam service-accounts keys delete KEY_ID \
--iam-account=sa-name@project-id.iam.gserviceaccount.com

2.3.5 Azure Credentials

For Microsoft Azure:

Terminal window
# List service principals
az ad sp list --show-mine
# Reset service principal credentials
az ad sp credential reset \
--id <app-id> \
--append
# Create new client secret
az ad sp credential reset \
--id <app-id> \
--credential-description "New secret after Shai-Hulud"

2.3.6 Database Credentials

Don’t forget to rotate database credentials:

Terminal window
# Example for PostgreSQL
# Connect to your database
psql -U admin -d postgres
# Create new user with same privileges
CREATE USER newuser WITH PASSWORD 'strong-new-password';
GRANT ALL PRIVILEGES ON DATABASE yourdb TO newuser;
# Update application configuration
# Test thoroughly
# Then remove old user
DROP USER olduser;

2.3.7 Environment Variables and Secrets

Update all environment secrets:

scripts/rotate-env-secrets.ts
import crypto from 'crypto'
const generateSecureSecret = (length: number = 32): string => {
return crypto.randomBytes(length).toString('hex')
}
console.log('🔐 New secrets generated:\n')
console.log(`SESSION_SECRET=${generateSecureSecret(64)}`)
console.log(`API_SECRET=${generateSecureSecret(32)}`)
console.log(`ENCRYPTION_KEY=${generateSecureSecret(32)}`)
console.log(`JWT_SECRET=${generateSecureSecret(64)}`)
console.log('\n⚠️ Update these in:')
console.log(' - Vercel/Netlify/hosting platform')
console.log(' - GitHub repository secrets')
console.log(' - Local .env files')
console.log(' - Team password manager')

Next Steps

You’ve taken critical first steps to secure your Astro project. However, protecting against supply chain attacks requires ongoing vigilance and robust security practices.

In Part 2, we explore long-term prevention (locking dependencies, integrity checks, CI/CD hardening) and in Part 3 we dig deeper into security-dependency isolation, secret management, automated scans, and monitoring.

Conclusion

The Shai-Hulud 2.0 attack is a stark reminder that supply chain security is not optional-it’s a critical component of modern web development. The immediate actions covered in this article are just the first line of defense.

If you have any questions or comments, feel free to reach out to me on Twitter.

Learn More Protecting Astro from Supply Chain Attacks: Part 2 - Long-Term Security Measures
Protecting Astro from Supply Chain Attacks: Part 2 - Long-Term Security Measures December 1, 2025
Reusing Database Queries in Astro SSG
Reusing Database Queries in Astro SSG November 29, 2025
Using Partytown with Google Tag Manager in Astro: A Step-by-Step Guide
Using Partytown with Google Tag Manager in Astro: A Step-by-Step Guide November 26, 2025