Last active
September 18, 2025 12:33
-
-
Save jariz/1d77ded091b4a3ff35fb485411b82cb4 to your computer and use it in GitHub Desktop.
check-compromised-lockfiles-recursive.js
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
| #!/usr/bin/env node | |
| /** | |
| * Recursively check npm/pnpm lockfiles for compromised packages. | |
| * Respects .gitignore to skip ignored files/folders. | |
| * | |
| * NOTE: run npm i -g yaml ignore | |
| * | |
| * Usage: | |
| * node check-compromised-lockfiles-recursive.js | |
| */ | |
| const fs = require("fs"); | |
| const path = require("path"); | |
| const yaml = require("yaml"); | |
| const ignore = require("ignore"); | |
| // https://socket.dev/blog/ongoing-supply-chain-attack-targets-crowdstrike-npm-packages#Indicators-of-Compromise | |
| const compromised = [ | |
| "@ahmedhfarag/[email protected]", | |
| "@ahmedhfarag/[email protected]", | |
| "[email protected]", | |
| "@art-ws/[email protected]", | |
| "@art-ws/[email protected]", | |
| "@art-ws/[email protected]", | |
| "@art-ws/[email protected]", | |
| "@art-ws/[email protected]", | |
| "@art-ws/[email protected]", | |
| "@art-ws/[email protected]", | |
| "@art-ws/[email protected]", | |
| "@art-ws/[email protected]", | |
| "@art-ws/[email protected]", | |
| "@art-ws/[email protected]", | |
| "@art-ws/[email protected]", | |
| "@art-ws/[email protected]", | |
| "@art-ws/[email protected]", | |
| "@art-ws/[email protected]", | |
| "@art-ws/[email protected]", | |
| "@art-ws/[email protected]", | |
| "@art-ws/[email protected]", | |
| "@art-ws/[email protected]", | |
| "@art-ws/[email protected]", | |
| "@art-ws/[email protected]", | |
| "@art-ws/[email protected]", | |
| "@art-ws/[email protected]", | |
| "@art-ws/[email protected]", | |
| "@art-ws/[email protected]", | |
| "@art-ws/[email protected]", | |
| "@art-ws/[email protected]", | |
| "@crowdstrike/[email protected]", | |
| "@crowdstrike/[email protected]", | |
| "@crowdstrike/[email protected]", | |
| "@crowdstrike/[email protected]", | |
| "@crowdstrike/[email protected]", | |
| "@crowdstrike/[email protected]", | |
| "@crowdstrike/[email protected]", | |
| "@crowdstrike/[email protected]", | |
| "@crowdstrike/[email protected]", | |
| "@crowdstrike/[email protected]", | |
| "@crowdstrike/[email protected]", | |
| "@crowdstrike/[email protected]", | |
| "@crowdstrike/[email protected]", | |
| "@crowdstrike/[email protected]", | |
| "@crowdstrike/[email protected]", | |
| "@crowdstrike/[email protected]", | |
| "@crowdstrike/[email protected]", | |
| "@crowdstrike/[email protected]", | |
| "@ctrl/[email protected]", | |
| "@ctrl/[email protected]", | |
| "@ctrl/[email protected]", | |
| "@ctrl/[email protected]", | |
| "@ctrl/[email protected]", | |
| "@ctrl/[email protected]", | |
| "@ctrl/[email protected]", | |
| "@ctrl/[email protected]", | |
| "@ctrl/[email protected]", | |
| "@ctrl/[email protected]", | |
| "@ctrl/[email protected]", | |
| "@ctrl/[email protected]", | |
| "@ctrl/[email protected]", | |
| "@ctrl/[email protected]", | |
| "@ctrl/[email protected]", | |
| "@ctrl/[email protected]", | |
| "@ctrl/[email protected]", | |
| "@ctrl/[email protected]", | |
| "@ctrl/[email protected]", | |
| "@ctrl/[email protected]", | |
| "@ctrl/[email protected]", | |
| "@ctrl/[email protected]", | |
| "@ctrl/[email protected]", | |
| "@ctrl/[email protected]", | |
| "@ctrl/[email protected]", | |
| "@ctrl/[email protected]", | |
| "@ctrl/[email protected]", | |
| "@hestjs/[email protected]", | |
| "@hestjs/[email protected]", | |
| "@hestjs/[email protected]", | |
| "@hestjs/[email protected]", | |
| "@hestjs/[email protected]", | |
| "@hestjs/[email protected]", | |
| "@hestjs/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nativescript-community/[email protected]", | |
| "@nexe/[email protected]", | |
| "@nexe/[email protected]", | |
| "@nexe/[email protected]", | |
| "@nstudio/[email protected]", | |
| "@nstudio/[email protected]", | |
| "@nstudio/[email protected]", | |
| "@nstudio/[email protected]", | |
| "@nstudio/[email protected]", | |
| "@nstudio/[email protected]", | |
| "@nstudio/[email protected]", | |
| "@nstudio/[email protected]", | |
| "@nstudio/[email protected]", | |
| "@nstudio/[email protected]", | |
| "@nstudio/[email protected]", | |
| "@nstudio/[email protected]", | |
| "@nstudio/[email protected]", | |
| "@nstudio/[email protected]", | |
| "@nstudio/[email protected]", | |
| "@nstudio/[email protected]", | |
| "@nstudio/[email protected]", | |
| "@nstudio/[email protected]", | |
| "@nstudio/[email protected]", | |
| "@nstudio/[email protected]", | |
| "@nstudio/[email protected]", | |
| "@nstudio/[email protected]", | |
| "@nstudio/[email protected]", | |
| "@nstudio/[email protected]", | |
| "@nstudio/[email protected]", | |
| "@nstudio/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@operato/[email protected]", | |
| "@teselagen/[email protected]", | |
| "@teselagen/[email protected]", | |
| "@teselagen/[email protected]", | |
| "@teselagen/[email protected]", | |
| "@teselagen/[email protected]", | |
| "@teselagen/[email protected]", | |
| "@teselagen/[email protected]", | |
| "@teselagen/[email protected]", | |
| "@teselagen/[email protected]", | |
| "@teselagen/[email protected]", | |
| "@teselagen/[email protected]", | |
| "@teselagen/[email protected]", | |
| "@teselagen/[email protected]", | |
| "@teselagen/[email protected]", | |
| "@teselagen/[email protected]", | |
| "@thangved/[email protected]", | |
| "@things-factory/[email protected]", | |
| "@things-factory/[email protected]", | |
| "@things-factory/[email protected]", | |
| "@things-factory/[email protected]", | |
| "@things-factory/[email protected]", | |
| "@things-factory/[email protected]", | |
| "@things-factory/[email protected]", | |
| "@things-factory/[email protected]", | |
| "@things-factory/[email protected]", | |
| "@things-factory/[email protected]", | |
| "@things-factory/[email protected]", | |
| "@things-factory/[email protected]", | |
| "@things-factory/[email protected]", | |
| "@things-factory/[email protected]", | |
| "@things-factory/[email protected]", | |
| "@things-factory/[email protected]", | |
| "@things-factory/[email protected]", | |
| "@things-factory/[email protected]", | |
| "@things-factory/[email protected]", | |
| "@things-factory/[email protected]", | |
| "@things-factory/[email protected]", | |
| "@things-factory/[email protected]", | |
| "@things-factory/[email protected]", | |
| "@things-factory/[email protected]", | |
| "@things-factory/[email protected]", | |
| "@things-factory/[email protected]", | |
| "@things-factory/[email protected]", | |
| "@things-factory/[email protected]", | |
| "@things-factory/[email protected]", | |
| "@things-factory/[email protected]", | |
| "@things-factory/[email protected]", | |
| "@things-factory/[email protected]", | |
| "@things-factory/[email protected]", | |
| "@things-factory/[email protected]", | |
| "@things-factory/[email protected]", | |
| "@things-factory/[email protected]", | |
| "@things-factory/[email protected]", | |
| "@things-factory/[email protected]", | |
| "@things-factory/[email protected]", | |
| "@things-factory/[email protected]", | |
| "@things-factory/[email protected]", | |
| "@things-factory/[email protected]", | |
| "@things-factory/[email protected]", | |
| "@things-factory/[email protected]", | |
| "@things-factory/[email protected]", | |
| "@things-factory/[email protected]", | |
| "@things-factory/[email protected]", | |
| "@things-factory/[email protected]", | |
| "@things-factory/[email protected]", | |
| "@things-factory/[email protected]", | |
| "@things-factory/[email protected]", | |
| "@tnf-dev/[email protected]", | |
| "@tnf-dev/[email protected]", | |
| "@tnf-dev/[email protected]", | |
| "@tnf-dev/[email protected]", | |
| "@tnf-dev/[email protected]", | |
| "@ui-ux-gang/[email protected]", | |
| "@yoobic/[email protected]", | |
| "@yoobic/[email protected]", | |
| "@yoobic/[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "[email protected]", | |
| "@rxap/[email protected]", | |
| "@rxap/[email protected]", | |
| "[email protected]", | |
| ]; | |
| // Load .gitignore rules | |
| function loadGitIgnore(rootDir) { | |
| const ig = ignore(); | |
| const gitignorePath = path.join(rootDir, ".gitignore"); | |
| if (fs.existsSync(gitignorePath)) { | |
| const content = fs.readFileSync(gitignorePath, "utf8"); | |
| ig.add(content); | |
| } | |
| return ig; | |
| } | |
| // Recursively find lockfiles while respecting .gitignore | |
| function findLockfiles(dir, ig) { | |
| const lockfiles = []; | |
| const entries = fs.readdirSync(dir, { withFileTypes: true }); | |
| for (const entry of entries) { | |
| const fullPath = path.join(dir, entry.name); | |
| const relPath = path.relative(process.cwd(), fullPath); | |
| if (ig.ignores(relPath)) continue; // respect .gitignore | |
| if (entry.isDirectory()) { | |
| lockfiles.push(...findLockfiles(fullPath, ig)); | |
| } else if (["package-lock.json", "pnpm-lock.yaml"].includes(entry.name)) { | |
| lockfiles.push(fullPath); | |
| } | |
| } | |
| return lockfiles; | |
| } | |
| // Check npm lockfile | |
| function checkNpmLock(lockData) { | |
| const findings = []; | |
| function walk(deps) { | |
| if (!deps) return; | |
| for (const [name, info] of Object.entries(deps)) { | |
| const candidate = `${name}@${info.version}`; | |
| if (compromised.includes(candidate)) { | |
| findings.push(candidate); | |
| } | |
| walk(info.dependencies); | |
| } | |
| } | |
| walk(lockData.dependencies); | |
| return findings; | |
| } | |
| // Check pnpm lockfile | |
| function checkPnpmLock(lockData) { | |
| const findings = []; | |
| if (!lockData.packages) return findings; | |
| for (const [pkgPath, info] of Object.entries(lockData.packages)) { | |
| const parts = pkgPath.split("/"); | |
| let name, version; | |
| if (pkgPath.startsWith("/@")) { | |
| name = "@" + parts[1] + "/" + parts[2]; | |
| version = parts[3]; | |
| } else { | |
| name = parts[1]; | |
| version = parts[2]; | |
| } | |
| const candidate = `${name}@${version}`; | |
| if (compromised.includes(candidate)) findings.push(candidate); | |
| } | |
| return findings; | |
| } | |
| // Main | |
| function main() { | |
| const ig = loadGitIgnore(process.cwd()); | |
| const lockfiles = findLockfiles(process.cwd(), ig); | |
| if (lockfiles.length === 0) { | |
| console.log("No lockfiles found."); | |
| return; | |
| } | |
| let anyFindings = false; | |
| for (const lockfile of lockfiles) { | |
| console.log(`\nChecking ${lockfile}...`); | |
| const ext = path.basename(lockfile); | |
| let data; | |
| try { | |
| const content = fs.readFileSync(lockfile, "utf8"); | |
| if (ext === "package-lock.json") { | |
| data = JSON.parse(content); | |
| } else { | |
| data = yaml.parse(content); | |
| } | |
| } catch (err) { | |
| console.error(`Failed to parse ${lockfile}:`, err); | |
| continue; | |
| } | |
| const findings = | |
| ext === "package-lock.json" ? checkNpmLock(data) : checkPnpmLock(data); | |
| if (findings.length === 0) { | |
| console.log("✅ No compromised packages found."); | |
| } else { | |
| anyFindings = true; | |
| console.log("⚠️ Found compromised packages:"); | |
| for (const f of findings) console.log(`- ${f}`); | |
| } | |
| } | |
| if (anyFindings) process.exitCode = 1; | |
| } | |
| main(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment