Skip to content

Instantly share code, notes, and snippets.

@joeskeen
Forked from phxgg/check-npm-cache.sh
Last active September 24, 2025 06:10
Show Gist options
  • Save joeskeen/202fe9f6d7a2f624097962507c5ab681 to your computer and use it in GitHub Desktop.
Save joeskeen/202fe9f6d7a2f624097962507c5ab681 to your computer and use it in GitHub Desktop.
This script will check your npm cache and find if any of the affected packages was pulled in your machine. `chmod +x check-npm-cache.sh` before usage. No dependencies - should work on any system with Bash. (Only tested by me on Linux)

πŸ” NPM Compromised Package Scanner (Dependency-Free)

This script scans your system and project directories for known compromised versions of popular NPM packages, as reported by Aikido Security.

It works without installing any dependencies (no jq, awk, sed, or node) and is compatible with projects using npm, Yarn, pnpm, and nvm. It also inspects Dockerfiles, CI configs, and vendored folders for embedded vulnerabilities.


🚨 What It Detects

Package Version
ansi-regex 6.2.1
ansi-styles 6.2.2
backslash 0.2.1
chalk 5.6.1
chalk-template 1.1.1
color-convert 3.1.1
color-name 2.0.1
color-string 2.1.1
debug 4.4.2
error-ex 1.3.3
has-ansi 6.0.1
is-arrayish 0.3.3
proto-tinker-wc 0.1.87
simple-swizzle 0.2.3
slice-ansi 7.1.1
strip-ansi 7.1.1
supports-color 10.2.1
supports-hyperlinks 4.1.1
wrap-ansi 9.0.1

πŸ“ Where It Scans

πŸ”’ Project-Specific (Relative to Current Working Directory)

  • package-lock.json, package.json, yarn.lock, pnpm-lock.yaml
  • Dockerfiles (Dockerfile)
  • CI/CD config files (.github/workflows/*.yml, .gitlab-ci.yml)
  • Vendored folders: vendor/, third_party/, static/, assets/

πŸ“¦ Global Caches and Install Locations

NPM

  • $HOME/.npm/_cacache
  • $HOME/.npm-packages

Yarn

  • Auto-detected via yarn cache dir
  • Typically ~/.cache/yarn or ~/.yarn/cache

pnpm

  • Auto-detected via pnpm store path
  • Typically ~/.pnpm-store or ~/.local/share/pnpm/store

NVM

  • $NVM_DIR/versions/node/*/lib/node_modules
  • $NVM_DIR/versions/node/*/.npm
  • $NVM_DIR/versions/node/*/node_modules

You can override the NVM path by setting the NVM_DIR environment variable.


βœ… How to Use

  1. Save the script as scan-npm.sh
  2. Make it executable:
    chmod +x scan-npm.sh
  3. Run it from your project root or home directory:
    ./scan-npm.sh

🧠 Why This Script?

  • No dependencies β€” works on minimal systems
  • Cross-manager support β€” npm, Yarn, pnpm, nvm
  • Fast and portable β€” uses only POSIX shell and grep
  • Expanded coverage β€” scans Dockerfiles, CI configs, and vendored folders
  • Quiet but informative β€” logs progress periodically and summarizes findings

πŸ“Š Output

At the end of the scan, you'll see a summary like:

πŸ“ /code/project-a
🚨 Found [email protected] in /code/project-a/package-lock.json
🚨 Found [email protected] in /code/project-a/package-lock.json

πŸ“ /code/project-b
🚨 Found [email protected] in /code/project-b/yarn.lock

πŸ› οΈ Suggested Remediation Commands:
πŸ’‘ cd "/code/project-a" && npm install
πŸ’‘ cd "/code/project-b" && yarn install

πŸ”’ Total findings: 3
#!/usr/bin/env bash
echo "πŸ” Scanning for compromised NPM packages..."
# Define compromised packages and versions
declare -A compromised=(
[ansi-regex]="6.2.1"
[ansi-styles]="6.2.2"
[backslash]="0.2.1"
[chalk]="5.6.1"
[chalk-template]="1.1.1"
[color-convert]="3.1.1"
[color-name]="2.0.1"
[color-string]="2.1.1"
[debug]="4.4.2"
[error-ex]="1.3.3"
[has-ansi]="6.0.1"
[is-arrayish]="0.3.3"
[proto-tinker-wc]="0.1.87"
[simple-swizzle]="0.2.3"
[slice-ansi]="7.1.1"
[strip-ansi]="7.1.1"
[supports-color]="10.2.1"
[supports-hyperlinks]="4.1.1"
[wrap-ansi]="9.0.1"
)
declare -a findings=()
scan_file() {
local file="$1"
for pkg in "${!compromised[@]}"; do
version="${compromised[$pkg]}"
if grep -q "$pkg" "$file" && grep -q "$version" "$file"; then
findings+=("Found $pkg@$version in $file")
fi
done
}
scan_npm_cache() {
local cache_dir="$1"
for pkg in "${!compromised[@]}"; do
version="${compromised[$pkg]}"
while IFS= read -r match; do
findings+=("Found $pkg@$version in cached file: $match")
done < <(find "$cache_dir" -type f -exec grep -l "$pkg@$version" {} + 2>/dev/null)
done
}
scan_nvm_versions() {
local nvm_dir="${NVM_DIR:-$HOME/.nvm}"
if [ ! -d "$nvm_dir" ]; then return; fi
echo "🧠 Scanning NVM-managed Node versions..."
count=0
find "$nvm_dir/versions/node" -type d \( -name "node_modules" -o -name ".npm" \) | while read -r dir; do
scan_npm_cache "$dir"
count=$((count + 1))
if (( count % 5 == 0 )); then
echo " ...scanned $count NVM directories"
fi
done
}
scan_dockerfiles() {
echo "🐳 Scanning Dockerfiles..."
count=0
while IFS= read -r file; do
scan_file "$file"
count=$((count + 1))
if (( count % 5 == 0 )); then
echo " ...scanned $count Dockerfiles"
fi
done < <(find . -type f -iname "Dockerfile")
}
scan_ci_configs() {
echo "βš™οΈ Scanning CI/CD config files..."
count=0
while IFS= read -r file; do
scan_file "$file"
count=$((count + 1))
if (( count % 5 == 0 )); then
echo " ...scanned $count CI config files"
fi
done < <(find . -type f \( -name "*.yml" -o -name "*.yaml" \) -path "*/.github/*" -o -path "*/.gitlab/*")
}
scan_vendored_dirs() {
echo "πŸ“ Scanning vendored folders..."
for dir in vendor third_party static assets; do
[ -d "$dir" ] || continue
while IFS= read -r file; do
scan_file "$file"
done < <(find "$dir" -type f \( -name "*.js" -o -name "*.json" -o -name "*.tgz" \))
done
}
scan_lockfile_resolved() {
local file="$1"
for pkg in "${!compromised[@]}"; do
version="${compromised[$pkg]}"
# Match resolved tarball URLs for compromised versions
if grep -q "$pkg/-/$pkg-$version.tgz" "$file"; then
findings+=("Resolved $pkg@$version in $file")
fi
done
}
echo "πŸ”’ Scanning project lockfiles and package.json..."
count=0
while IFS= read -r file; do
scan_lockfile_resolved "$file" # new accurate match
count=$((count + 1))
if (( count % 10 == 0 )); then
echo " ...scanned $count files"
fi
done < <(find . -type f \( -name "package-lock.json" -o -name "yarn.lock" -o -name "pnpm-lock.yaml" \))
# Global caches
echo "πŸ“¦ Scanning global npm caches..."
[ -d "$HOME/.npm/_cacache" ] && scan_npm_cache "$HOME/.npm/_cacache"
[ -d "$HOME/.npm-packages" ] && scan_npm_cache "$HOME/.npm-packages"
echo "πŸ“¦ Scanning Yarn global cache..."
if command -v yarn >/dev/null 2>&1; then
yarn_cache=$(yarn cache dir 2>/dev/null)
[ -n "$yarn_cache" ] && [ -d "$yarn_cache" ] && scan_npm_cache "$yarn_cache"
fi
echo "πŸ“¦ Scanning pnpm global store..."
if command -v pnpm >/dev/null 2>&1; then
pnpm_cache=$(pnpm store path 2>/dev/null)
[ -n "$pnpm_cache" ] && [ -d "$pnpm_cache" ] && scan_npm_cache "$pnpm_cache"
fi
scan_nvm_versions
scan_dockerfiles
scan_ci_configs
scan_vendored_dirs
echo ""
echo "πŸ“Š Summary of Findings:"
if [ ${#findings[@]} -eq 0 ]; then
echo "βœ… No compromised packages found."
else
declare -A grouped
declare -A remediation
# Group findings by remediation directory
for line in "${findings[@]}"; do
file=$(echo "$line" | awk -F'in ' '{print $2}')
dir=$(dirname "$file")
# Trim path before node_modules if present
if [[ "$dir" == *"/node_modules/"* ]]; then
dir="${dir%%/node_modules/*}"
elif [[ "$dir" == *"/node_modules" ]]; then
dir="${dir%/node_modules}"
fi
# Walk up to find the remediation root
while [ "$dir" != "/" ]; do
if [ -f "$dir/package-lock.json" ]; then
remediation["$dir"]="npm"
break
elif [ -f "$dir/yarn.lock" ]; then
remediation["$dir"]="yarn"
break
elif [ -f "$dir/pnpm-lock.yaml" ]; then
remediation["$dir"]="pnpm"
break
fi
dir=$(dirname "$dir")
done
grouped["$dir"]+="$line"$'\n'
done
# Print grouped findings
for dir in "${!grouped[@]}"; do
echo "πŸ“ $dir"
echo "${grouped[$dir]}"
done
echo ""
echo "πŸ› οΈ Suggested Remediation Commands:"
for dir in "${!remediation[@]}"; do
tool="${remediation[$dir]}"
echo "πŸ’‘ cd \"$dir\" && rm -rf node_modules ${tool}-lock.yaml yarn.lock package-lock.json && $tool install"
done
fi
@djt-auditor
Copy link

@alexkli for the next npm

scan_lockfile_resolved() {
  local file="$1"
  for pkg in "${!compromised[@]}"; do
    version="${compromised[$pkg]}"
    # Match resolved tarball URLs for compromised versions
    if [[ $pkg == @* ]]; then
      if grep -q "$pkg/-/${pkg##*/}-$version.tgz" "$file"; then
        findings+=("Resolved $pkg@$version in $file")
      fi
    elif grep -q "$pkg/-/$pkg-$version.tgz" "$file"; then
      findings+=("Resolved $pkg@$version in $file")
    fi
  done
}

or for this one look the
rg -uu --max-columns=80 --glob '*.js' _0x112fa8

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment