Last active
September 16, 2025 03:23
-
-
Save guicaulada/52046d419f0873316410eeee9b6b5337 to your computer and use it in GitHub Desktop.
Find malicious NPM packages on any node_modules folder in the system
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/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