Skip to content

Instantly share code, notes, and snippets.

@guicaulada
Last active September 16, 2025 03:23
Show Gist options
  • Select an option

  • Save guicaulada/52046d419f0873316410eeee9b6b5337 to your computer and use it in GitHub Desktop.

Select an option

Save guicaulada/52046d419f0873316410eeee9b6b5337 to your computer and use it in GitHub Desktop.
Find malicious NPM packages on any node_modules folder in the system
#!/bin/bash
# Function to display a spinner
spinner() {
local pid=$1
local delay=0.1
local spinstr='|/-\'
while kill -0 $pid 2>/dev/null; do
local temp=${spinstr#?}
printf " [%c] " "$spinstr"
local spinstr=$temp${spinstr%"${temp}"}
sleep $delay
printf "\b\b\b\b\b\b"
done
printf " \b\b\b\b"
}
# List of packages and their malicious versions
# Modify this based on what youre lookin for
# ie: "package:1.0.0 1.0.1 2.0.0 3.1.2"
packages=(
"@ctrl/tinycolor:4.1.1 4.1.2"
"angulartics2:14.1.2"
"@ctrl/deluge:7.2.2"
"@ctrl/golang-template:1.4.3"
"@ctrl/magnet-link:4.0.4"
"@ctrl/ngx-codemirror:7.0.2"
"@ctrl/ngx-csv:6.0.2"
"@ctrl/ngx-emoji-mart:9.2.2"
"@ctrl/ngx-rightclick:4.0.2"
"@ctrl/qbittorrent:9.7.2"
"@ctrl/react-adsense:2.0.2"
"@ctrl/shared-torrent:6.3.2"
"@ctrl/torrent-file:4.1.2"
"@ctrl/transmission:7.3.1"
"@ctrl/ts-base32:4.0.2"
"encounter-playground:0.0.5"
"json-rules-engine-simplified:0.2.4 0.2.1"
"koa2-swagger-ui:5.11.2 5.11.1"
"@nativescript-community/gesturehandler:2.0.35"
"@nativescript-community/sentry:4.6.43"
"@nativescript-community/text:1.6.13"
"@nativescript-community/ui-collectionview:6.0.6"
"@nativescript-community/ui-drawer:0.1.30"
"@nativescript-community/ui-image:4.5.6"
"@nativescript-community/ui-material-bottomsheet:7.2.72"
"@nativescript-community/ui-material-core:7.2.76"
"@nativescript-community/ui-material-core-tabs:7.2.76"
"ngx-color:10.0.2"
"ngx-toastr:19.0.2"
"ngx-trend:8.0.1"
"react-complaint-image:0.0.35"
"react-jsonschema-form-conditionals:0.3.21"
"react-jsonschema-form-extras:1.0.4"
"rxnt-authentication:0.0.6"
"rxnt-healthchecks-nestjs:1.0.5"
"rxnt-kue:1.0.7"
"swc-plugin-component-annotate:1.9.2"
"ts-gaussian:3.0.6"
)
temp_file="/tmp/node_modules_paths.txt"
echo "Searching for all node_modules directories on the system... This may take a while."
find / -type d -name node_modules 2>/dev/null > "$temp_file" & pid=$!
spinner $pid
wait $pid
echo "Search for directories complete."
total=$(wc -l < "$temp_file" | awk '{print $1}')
if [ "$total" -eq 0 ]; then
echo "No node_modules directories found. Search complete."
rm -f "$temp_file"
exit 0
fi
echo "Found $total node_modules directories."
echo "Now checking each one for the specified packages..."
results=""
current=0
while read -r nm_path; do
((current++))
progress=$((current * 100 / total))
echo -ne "\rProgress: $progress% ($current/$total)"
for entry in "${packages[@]}"; do
pkg=$(echo "$entry" | cut -d: -f1)
vers=$(echo "$entry" | cut -d: -f2)
pkg_path="$nm_path/$pkg"
if [ -d "$pkg_path" ] && [ -f "$pkg_path/package.json" ]; then
version=$(node -e "try { console.log(require('$pkg_path/package.json').version); } catch (e) {}" 2>/dev/null)
if [ -n "$version" ]; then
if echo " $vers " | grep -q " $version "; then
results+="\nFound malicious $pkg version $version at $pkg_path"
else
results+="\nFound supposedly safe $pkg version $version at $pkg_path"
fi
fi
fi
done
done < "$temp_file"
rm -f "$temp_file"
echo "" # New line after progress bar
if [ -n "$results" ]; then
echo "Findings:"
echo -e "$results"
else
echo "No matching packages found."
fi
echo "" # New line after findings
echo "Search complete."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment