// Supply-chain guard. // // Fails the build if the known malicious loader signature is reintroduced into // tracked source (e.g. a poisoned eslint.config.js). Added after the 2026 // force-push supply-chain incident. Runs as the first step of `npm run verify`, // so it executes in the repo-owned governance CI job on every PR and push. // // Signatures are the stable markers of the obfuscated, credential-stealing // loader observed in the attack. Keep the list append-only. Patterns are built // from fragments so this file never matches itself. import { execSync } from "node:child_process"; import { readFileSync } from "node:fs"; const SELF = "scripts/payload-guard.mjs"; const CODE_EXT = new Set([".js", ".cjs", ".mjs", ".ts", ".tsx", ".jsx"]); const seed = "global" + ".o"; const shim = "createRequire(import" + ".meta.url)"; /** @type {{name:string, test:(path:string, text:string)=>boolean}[]} */ const RULES = [ { name: "loader seed (global.o='8-…')", test: (_p, t) => new RegExp(seed + "\\s*=\\s*['\"]8-").test(t), }, { name: "permutation variable (_$_…)", test: (_p, t) => /_\$_/.test(t), }, { name: "delimiter trick (String.fromCharCode(127))", test: (_p, t) => /String\.fromCharCode\(\s*127\s*\)/.test(t), }, { name: "ESM→CJS shim injected into eslint flat config", test: (p, t) => /(^|\/)eslint\.config\.(js|mjs|cjs)$/.test(p) && t.includes(shim), }, ]; function trackedFiles() { const out = execSync("git ls-files", { encoding: "utf8", maxBuffer: 64 * 1024 * 1024 }); return out.split("\n").map((s) => s.trim()).filter(Boolean); } function extOf(path) { const i = path.lastIndexOf("."); return i === -1 ? "" : path.slice(i); } const findings = []; for (const file of trackedFiles()) { if (file === SELF) continue; if (!CODE_EXT.has(extOf(file))) continue; let text; try { text = readFileSync(file, "utf8"); } catch { continue; } for (const rule of RULES) { if (rule.test(file, text)) findings.push({ file, rule: rule.name }); } } if (findings.length > 0) { console.error("payload-guard: known supply-chain markers detected:\n"); for (const f of findings) console.error(` ✗ ${f.file} — ${f.rule}`); console.error("\nThis matches the obfuscated loader from the 2026 supply-chain incident."); console.error("Do not merge. Inspect the file(s) and remove the injected payload."); process.exit(1); } console.log("payload-guard: no known payload markers found.");