guard-scanner 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "guard-scanner",
3
+ "version": "1.0.0",
4
+ "description": "Agent skill security scanner — detect prompt injection, malicious code, credential leaks, and 17 threat categories in AI agent skills",
5
+ "main": "src/scanner.js",
6
+ "bin": {
7
+ "guard-scanner": "src/cli.js"
8
+ },
9
+ "scripts": {
10
+ "scan": "node src/cli.js",
11
+ "test": "node --test test/*.test.js"
12
+ },
13
+ "keywords": [
14
+ "security",
15
+ "scanner",
16
+ "ai-agent",
17
+ "skill-scanner",
18
+ "prompt-injection",
19
+ "openclaw",
20
+ "mcp",
21
+ "sarif"
22
+ ],
23
+ "author": "Guava & Dee",
24
+ "license": "MIT",
25
+ "engines": {
26
+ "node": ">=18.0.0"
27
+ },
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "https://github.com/koatora20/guard-scanner.git"
31
+ },
32
+ "homepage": "https://github.com/koatora20/guard-scanner",
33
+ "files": [
34
+ "src/",
35
+ "hooks/",
36
+ "docs/",
37
+ "SKILL.md",
38
+ "SECURITY.md",
39
+ "README.md",
40
+ "LICENSE"
41
+ ]
42
+ }
package/src/cli.js ADDED
@@ -0,0 +1,149 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * guard-scanner CLI
4
+ *
5
+ * @security-manifest
6
+ * env-read: []
7
+ * env-write: []
8
+ * network: none
9
+ * fs-read: [scan target directory, plugin files, custom rules files]
10
+ * fs-write: [JSON/SARIF/HTML reports to scan directory]
11
+ * exec: none
12
+ * purpose: CLI entry point for guard-scanner static analysis
13
+ *
14
+ * Usage: guard-scanner [scan-dir] [options]
15
+ *
16
+ * Options:
17
+ * --verbose, -v Detailed findings
18
+ * --json JSON report
19
+ * --sarif SARIF report (CI/CD)
20
+ * --html HTML report
21
+ * --self-exclude Skip scanning self
22
+ * --strict Lower thresholds
23
+ * --summary-only Summary only
24
+ * --check-deps Scan dependencies
25
+ * --rules <file> Custom rules JSON
26
+ * --plugin <file> Load plugin module
27
+ * --fail-on-findings Exit 1 on findings (CI/CD)
28
+ * --help, -h Help
29
+ */
30
+
31
+ const fs = require('fs');
32
+ const path = require('path');
33
+ const { GuardScanner, VERSION } = require('./scanner.js');
34
+
35
+ const args = process.argv.slice(2);
36
+
37
+ if (args.includes('--help') || args.includes('-h')) {
38
+ console.log(`
39
+ 🛡️ guard-scanner v${VERSION} — Agent Skill Security Scanner
40
+
41
+ Usage: guard-scanner [scan-dir] [options]
42
+
43
+ Options:
44
+ --verbose, -v Detailed findings with categories and samples
45
+ --json Write JSON report to scan-dir/guard-scanner-report.json
46
+ --sarif Write SARIF report (GitHub Code Scanning / CI/CD)
47
+ --html Write HTML report (visual dashboard)
48
+ --self-exclude Skip scanning the guard-scanner skill itself
49
+ --strict Lower detection thresholds (more sensitive)
50
+ --summary-only Only print the summary table
51
+ --check-deps Scan package.json for dependency chain risks
52
+ --rules <file> Load custom rules from JSON file
53
+ --plugin <file> Load plugin module (JS file exporting { name, patterns })
54
+ --fail-on-findings Exit code 1 if any findings (CI/CD)
55
+ --help, -h Show this help
56
+
57
+ Custom Rules JSON Format:
58
+ [
59
+ {
60
+ "id": "CUSTOM_001",
61
+ "pattern": "dangerous_function\\\\(",
62
+ "flags": "gi",
63
+ "severity": "HIGH",
64
+ "cat": "malicious-code",
65
+ "desc": "Custom: dangerous function call",
66
+ "codeOnly": true
67
+ }
68
+ ]
69
+
70
+ Plugin API:
71
+ // my-plugin.js
72
+ module.exports = {
73
+ name: 'my-plugin',
74
+ patterns: [
75
+ { id: 'MY_01', cat: 'custom', regex: /pattern/g, severity: 'HIGH', desc: 'Description', all: true }
76
+ ]
77
+ };
78
+
79
+ Examples:
80
+ guard-scanner ./skills/ --verbose --self-exclude
81
+ guard-scanner ./skills/ --strict --json --sarif --check-deps
82
+ guard-scanner ./skills/ --html --verbose --check-deps
83
+ guard-scanner ./skills/ --rules my-rules.json --fail-on-findings
84
+ guard-scanner ./skills/ --plugin ./my-plugin.js
85
+ `);
86
+ process.exit(0);
87
+ }
88
+
89
+ const verbose = args.includes('--verbose') || args.includes('-v');
90
+ const jsonOutput = args.includes('--json');
91
+ const sarifOutput = args.includes('--sarif');
92
+ const htmlOutput = args.includes('--html');
93
+ const selfExclude = args.includes('--self-exclude');
94
+ const strict = args.includes('--strict');
95
+ const summaryOnly = args.includes('--summary-only');
96
+ const checkDeps = args.includes('--check-deps');
97
+ const failOnFindings = args.includes('--fail-on-findings');
98
+
99
+ const rulesIdx = args.indexOf('--rules');
100
+ const rulesFile = rulesIdx >= 0 ? args[rulesIdx + 1] : null;
101
+
102
+ // Collect plugins
103
+ const plugins = [];
104
+ let idx = 0;
105
+ while (idx < args.length) {
106
+ if (args[idx] === '--plugin' && args[idx + 1]) {
107
+ plugins.push(args[idx + 1]);
108
+ idx += 2;
109
+ } else {
110
+ idx++;
111
+ }
112
+ }
113
+
114
+ const scanDir = args.find(a =>
115
+ !a.startsWith('-') &&
116
+ a !== rulesFile &&
117
+ !plugins.includes(a)
118
+ ) || process.cwd();
119
+
120
+ const scanner = new GuardScanner({
121
+ verbose, selfExclude, strict, summaryOnly, checkDeps, rulesFile, plugins
122
+ });
123
+
124
+ scanner.scanDirectory(scanDir);
125
+
126
+ // Output reports
127
+ if (jsonOutput) {
128
+ const report = scanner.toJSON();
129
+ const outPath = path.join(scanDir, 'guard-scanner-report.json');
130
+ fs.writeFileSync(outPath, JSON.stringify(report, null, 2));
131
+ console.log(`\n📄 JSON report: ${outPath}`);
132
+ }
133
+
134
+ if (sarifOutput) {
135
+ const outPath = path.join(scanDir, 'guard-scanner.sarif');
136
+ fs.writeFileSync(outPath, JSON.stringify(scanner.toSARIF(scanDir), null, 2));
137
+ console.log(`\n📄 SARIF report: ${outPath}`);
138
+ }
139
+
140
+ if (htmlOutput) {
141
+ const outPath = path.join(scanDir, 'guard-scanner-report.html');
142
+ fs.writeFileSync(outPath, scanner.toHTML());
143
+ console.log(`\n📄 HTML report: ${outPath}`);
144
+ }
145
+
146
+ // Exit codes
147
+ if (scanner.stats.malicious > 0) process.exit(1);
148
+ if (failOnFindings && scanner.findings.length > 0) process.exit(1);
149
+ process.exit(0);
package/src/ioc-db.js ADDED
@@ -0,0 +1,54 @@
1
+ /**
2
+ * guard-scanner — Indicators of Compromise (IoC) Database
3
+ *
4
+ * @security-manifest
5
+ * env-read: []
6
+ * env-write: []
7
+ * network: none
8
+ * fs-read: []
9
+ * fs-write: []
10
+ * exec: none
11
+ * purpose: IoC data definitions only — no I/O, pure data export
12
+ *
13
+ * Known malicious IPs, domains, URLs, usernames, filenames, and typosquats.
14
+ * Sources: ClawHavoc campaign, Snyk ToxicSkills, Polymarket scams, community reports.
15
+ *
16
+ * Last updated: 2026-02-12
17
+ */
18
+
19
+ const KNOWN_MALICIOUS = {
20
+ ips: [
21
+ '91.92.242.30', // ClawHavoc C2
22
+ ],
23
+ domains: [
24
+ 'webhook.site', // Common exfil endpoint
25
+ 'requestbin.com', // Common exfil endpoint
26
+ 'hookbin.com', // Common exfil endpoint
27
+ 'pipedream.net', // Common exfil endpoint
28
+ 'ngrok.io', // Tunnel (context-dependent)
29
+ 'download.setup-service.com', // ClawHavoc decoy domain
30
+ 'socifiapp.com', // ClawHavoc v2 AMOS C2
31
+ ],
32
+ urls: [
33
+ 'glot.io/snippets/hfd3x9ueu5', // ClawHavoc macOS payload
34
+ 'github.com/Ddoy233', // ClawHavoc payload host
35
+ ],
36
+ usernames: ['zaycv', 'Ddoy233', 'Sakaen736jih'], // Known malicious actors
37
+ filenames: ['openclaw-agent.zip', 'openclawcli.zip'],
38
+ typosquats: [
39
+ // ClawHavoc campaign
40
+ 'clawhub', 'clawhub1', 'clawhubb', 'clawhubcli', 'clawwhub', 'cllawhub', 'clawdhub1',
41
+ // Polymarket scams
42
+ 'polymarket-trader', 'polymarket-pro', 'polytrading',
43
+ 'better-polymarket', 'polymarket-all-in-one',
44
+ // YouTube scams
45
+ 'youtube-summarize', 'youtube-thumbnail-grabber', 'youtube-video-downloader',
46
+ // Misc
47
+ 'auto-updater-agent', 'yahoo-finance-pro', 'x-trends-tracker',
48
+ 'lost-bitcoin-finder', 'solana-wallet-tracker', 'rankaj',
49
+ // Snyk ToxicSkills confirmed malicious
50
+ 'moltyverse-email', 'buy-anything', 'youtube-data', 'prediction-markets-roarin',
51
+ ],
52
+ };
53
+
54
+ module.exports = { KNOWN_MALICIOUS };
@@ -0,0 +1,182 @@
1
+ /**
2
+ * guard-scanner — Threat Pattern Database
3
+ *
4
+ * @security-manifest
5
+ * env-read: []
6
+ * env-write: []
7
+ * network: none
8
+ * fs-read: []
9
+ * fs-write: []
10
+ * exec: none
11
+ * purpose: Pattern definitions only — no I/O, pure data export
12
+ *
13
+ * 17 threat categories based on:
14
+ * - Snyk ToxicSkills taxonomy (2025-2026)
15
+ * - OWASP MCP Top 10
16
+ * - Palo Alto Networks IBC (Indirect Bias Criteria)
17
+ * - Real-world incidents (ClawHavoc, ZombieAgent, Soul Hijack)
18
+ *
19
+ * Each pattern: { id, cat, regex, severity, desc, codeOnly?, docOnly?, all? }
20
+ */
21
+
22
+ const PATTERNS = [
23
+ // ── Category 1: Prompt Injection (CRITICAL) ──
24
+ { id: 'PI_IGNORE', cat: 'prompt-injection', regex: /ignore\s+(all\s+)?previous\s+instructions|disregard\s+(all\s+)?prior/gi, severity: 'CRITICAL', desc: 'Prompt injection: ignore instructions', docOnly: true },
25
+ { id: 'PI_ROLE', cat: 'prompt-injection', regex: /you\s+are\s+(now|actually)|your\s+new\s+role|forget\s+your\s+(rules|instructions)/gi, severity: 'CRITICAL', desc: 'Prompt injection: role override', docOnly: true },
26
+ { id: 'PI_SYSTEM', cat: 'prompt-injection', regex: /\[SYSTEM\]|\\<system\\>|<<SYS>>|system:\s*you\s+are/gi, severity: 'CRITICAL', desc: 'Prompt injection: system message impersonation', docOnly: true },
27
+ { id: 'PI_ZWSP', cat: 'prompt-injection', regex: /[\u200b\u200c\u200d\u2060\ufeff]/g, severity: 'CRITICAL', desc: 'Zero-width Unicode (hidden text)', all: true },
28
+ { id: 'PI_BIDI', cat: 'prompt-injection', regex: /[\u202a\u202b\u202c\u202d\u202e\u2066\u2067\u2068\u2069]/g, severity: 'CRITICAL', desc: 'Unicode BiDi control character (text direction attack)', all: true },
29
+ { id: 'PI_INVISIBLE', cat: 'prompt-injection', regex: /[\u00ad\u034f\u061c\u180e\u2000-\u200f\u2028-\u202f\u205f-\u2064\u206a-\u206f\u3000](?!\ufe0f)/g, severity: 'HIGH', desc: 'Invisible/formatting Unicode character', all: true },
30
+ { id: 'PI_HOMOGLYPH', cat: 'prompt-injection', regex: /[а-яА-Я].*[a-zA-Z]|[a-zA-Z].*[а-яА-Я]/g, severity: 'HIGH', desc: 'Cyrillic/Latin homoglyph mixing', all: true },
31
+ { id: 'PI_HOMOGLYPH_GREEK', cat: 'prompt-injection', regex: /[α-ωΑ-Ω].*[a-zA-Z].*[α-ωΑ-Ω]|[a-zA-Z].*[α-ωΑ-Ω].*[a-zA-Z]/g, severity: 'HIGH', desc: 'Greek/Latin homoglyph mixing', all: true },
32
+ { id: 'PI_HOMOGLYPH_MATH', cat: 'prompt-injection', regex: /[\ud835\udc00-\ud835\udeff]/gu, severity: 'HIGH', desc: 'Mathematical symbol homoglyphs (𝐀-𝟿)', all: true },
33
+ { id: 'PI_TAG_INJECTION', cat: 'prompt-injection', regex: /<\/?(?:system|user|assistant|human|tool_call|function_call|antml|anthropic)[>\s]/gi, severity: 'CRITICAL', desc: 'XML/tag-based prompt injection', all: true },
34
+ { id: 'PI_BASE64_MD', cat: 'prompt-injection', regex: /(?:run|execute|eval|decode)\s+(?:this\s+)?base64/gi, severity: 'CRITICAL', desc: 'Base64 execution instruction in docs', docOnly: true },
35
+
36
+ // ── Category 2: Malicious Code (CRITICAL) ──
37
+ { id: 'MAL_EVAL', cat: 'malicious-code', regex: /\beval\s*\(/g, severity: 'HIGH', desc: 'Dynamic code evaluation', codeOnly: true },
38
+ { id: 'MAL_FUNC_CTOR', cat: 'malicious-code', regex: /new\s+Function\s*\(/g, severity: 'HIGH', desc: 'Function constructor (dynamic code)', codeOnly: true },
39
+ { id: 'MAL_CHILD', cat: 'malicious-code', regex: /require\s*\(\s*['"]child_process['"]\)|child_process/g, severity: 'MEDIUM', desc: 'Child process module', codeOnly: true },
40
+ { id: 'MAL_EXEC', cat: 'malicious-code', regex: /\bexecSync\s*\(|\bexec\s*\(\s*[`'"]/g, severity: 'MEDIUM', desc: 'Command execution', codeOnly: true },
41
+ { id: 'MAL_SPAWN', cat: 'malicious-code', regex: /\bspawn\s*\(\s*['"`]/g, severity: 'MEDIUM', desc: 'Process spawn', codeOnly: true },
42
+ { id: 'MAL_SHELL', cat: 'malicious-code', regex: /\/bin\/(sh|bash|zsh)|cmd\.exe|powershell\.exe/gi, severity: 'MEDIUM', desc: 'Shell invocation', codeOnly: true },
43
+ { id: 'MAL_REVSHELL', cat: 'malicious-code', regex: /reverse.?shell|bind.?shell|\bnc\s+-[elp]|\bncat\s+-e|\bsocat\s+TCP/gi, severity: 'CRITICAL', desc: 'Reverse/bind shell', all: true },
44
+ { id: 'MAL_SOCKET', cat: 'malicious-code', regex: /\bnet\.Socket\b[\s\S]{0,50}\.connect\s*\(/g, severity: 'HIGH', desc: 'Raw socket connection', codeOnly: true },
45
+
46
+ // ── Category 3: Suspicious Downloads (CRITICAL) ──
47
+ { id: 'DL_CURL_BASH', cat: 'suspicious-download', regex: /curl\s+[^\n]*\|\s*(sh|bash|zsh)|wget\s+[^\n]*\|\s*(sh|bash|zsh)/g, severity: 'CRITICAL', desc: 'Pipe download to shell', all: true },
48
+ { id: 'DL_EXE', cat: 'suspicious-download', regex: /download\s+[^\n]*\.(zip|exe|dmg|msi|pkg|appimage|deb|rpm)/gi, severity: 'CRITICAL', desc: 'Download executable/archive', docOnly: true },
49
+ { id: 'DL_GITHUB_RELEASE', cat: 'suspicious-download', regex: /github\.com\/[^\/]+\/[^\/]+\/releases\/download/g, severity: 'MEDIUM', desc: 'GitHub release download', all: true },
50
+ { id: 'DL_PASSWORD_ZIP', cat: 'suspicious-download', regex: /password[\s:]+[^\n]*\.zip|\.zip[\s\S]{0,100}password/gi, severity: 'CRITICAL', desc: 'Password-protected archive (evasion technique)', all: true },
51
+
52
+ // ── Category 4: Credential Handling (HIGH) ──
53
+ { id: 'CRED_ENV_FILE', cat: 'credential-handling', regex: /(?:read|open|load|parse|require|cat|source)\s*[(\s]['\"`]?[^\n]*\.env\b/gi, severity: 'HIGH', desc: 'Reading .env file', codeOnly: true },
54
+ { id: 'CRED_ENV_REF', cat: 'credential-handling', regex: /process\.env\.[A-Z_]*(?:KEY|SECRET|TOKEN|PASSWORD|CREDENTIAL)/gi, severity: 'MEDIUM', desc: 'Sensitive env var access', codeOnly: true },
55
+ { id: 'CRED_SSH', cat: 'credential-handling', regex: /\.ssh\/|id_rsa|id_ed25519|authorized_keys/gi, severity: 'HIGH', desc: 'SSH key access', codeOnly: true },
56
+ { id: 'CRED_WALLET', cat: 'credential-handling', regex: /wallet[\s._-]*(?:key|seed|phrase|mnemonic)|seed[\s._-]*phrase|mnemonic[\s._-]*phrase/gi, severity: 'HIGH', desc: 'Crypto wallet credential access', codeOnly: true },
57
+ { id: 'CRED_ECHO', cat: 'credential-handling', regex: /echo\s+\$[A-Z_]*(?:KEY|TOKEN|SECRET|PASS)|(?:print|console\.log)\s*\(\s*(?:.*\b(?:api_key|secret_key|access_token|password)\b)/gi, severity: 'HIGH', desc: 'Credential echo/print to output', all: true },
58
+ { id: 'CRED_SUDO', cat: 'credential-handling', regex: /\bsudo\s+(?:curl|wget|npm|pip|chmod|chown|bash)/g, severity: 'HIGH', desc: 'Sudo in installation instructions', docOnly: true },
59
+
60
+ // ── Category 5: Secret Detection (HIGH) ──
61
+ { id: 'SECRET_HARDCODED_KEY', cat: 'secret-detection', regex: /(?:api[_-]?key|apikey|secret[_-]?key|access[_-]?token)\s*[:=]\s*['"][a-zA-Z0-9_\-]{20,}['"]/gi, severity: 'HIGH', desc: 'Hardcoded API key/secret', codeOnly: true },
62
+ { id: 'SECRET_AWS', cat: 'secret-detection', regex: /AKIA[0-9A-Z]{16}/g, severity: 'CRITICAL', desc: 'AWS Access Key ID', all: true },
63
+ { id: 'SECRET_PRIVATE_KEY', cat: 'secret-detection', regex: /-----BEGIN\s+(RSA\s+)?PRIVATE\s+KEY-----/g, severity: 'CRITICAL', desc: 'Embedded private key', all: true },
64
+ { id: 'SECRET_GITHUB_TOKEN', cat: 'secret-detection', regex: /gh[ps]_[A-Za-z0-9_]{36,}/g, severity: 'CRITICAL', desc: 'GitHub token', all: true },
65
+
66
+ // ── Category 6: Exfiltration (MEDIUM) ──
67
+ { id: 'EXFIL_WEBHOOK', cat: 'exfiltration', regex: /webhook\.site|requestbin\.com|hookbin\.com|pipedream\.net/gi, severity: 'CRITICAL', desc: 'Known exfiltration endpoint', all: true },
68
+ { id: 'EXFIL_POST', cat: 'exfiltration', regex: /(?:method:\s*['"]POST['"]|\.post\s*\()\s*[^\n]*(?:secret|token|key|cred|env|password)/gi, severity: 'HIGH', desc: 'POST with sensitive data', codeOnly: true },
69
+ { id: 'EXFIL_CURL_DATA', cat: 'exfiltration', regex: /curl\s+[^\n]*(?:-d|--data)\s+[^\n]*(?:\$|env|key|token|secret)/gi, severity: 'HIGH', desc: 'curl exfiltration of secrets', all: true },
70
+ { id: 'EXFIL_DNS', cat: 'exfiltration', regex: /dns\.resolve|nslookup\s+.*\$|dig\s+.*\$/g, severity: 'HIGH', desc: 'DNS-based exfiltration', codeOnly: true },
71
+
72
+ // ── Category 7: Unverifiable Dependencies (MEDIUM) ──
73
+ { id: 'DEP_REMOTE_IMPORT', cat: 'unverifiable-deps', regex: /import\s*\(\s*['"]https?:\/\//g, severity: 'HIGH', desc: 'Remote dynamic import', codeOnly: true },
74
+ { id: 'DEP_REMOTE_SCRIPT', cat: 'unverifiable-deps', regex: /<script\s+src\s*=\s*['"]https?:\/\/[^'"]*(?!googleapis|cdn\.|unpkg|cdnjs|jsdelivr)/gi, severity: 'MEDIUM', desc: 'Remote script loading', codeOnly: true },
75
+
76
+ // ── Category 8: Financial Access (MEDIUM) ──
77
+ { id: 'FIN_CRYPTO', cat: 'financial-access', regex: /private[_-]?key\s*[:=]|send[_-]?transaction|sign[_-]?transaction|transfer[_-]?funds/gi, severity: 'HIGH', desc: 'Cryptocurrency transaction operations', codeOnly: true },
78
+ { id: 'FIN_PAYMENT', cat: 'financial-access', regex: /stripe\.(?:charges|payments)|paypal\.(?:payment|payout)|plaid\.(?:link|transactions)/gi, severity: 'MEDIUM', desc: 'Payment API integration', codeOnly: true },
79
+
80
+ // ── Category 9: Obfuscation ──
81
+ { id: 'OBF_HEX', cat: 'obfuscation', regex: /\\x[0-9a-f]{2}(?:\\x[0-9a-f]{2}){4,}/gi, severity: 'HIGH', desc: 'Hex-encoded string (5+ bytes)', codeOnly: true },
82
+ { id: 'OBF_BASE64_EXEC', cat: 'obfuscation', regex: /(?:atob|Buffer\.from)\s*\([^)]+\)[\s\S]{0,30}(?:eval|exec|spawn|Function)/g, severity: 'CRITICAL', desc: 'Base64 decode → execute chain', codeOnly: true },
83
+ { id: 'OBF_BASE64', cat: 'obfuscation', regex: /atob\s*\(|Buffer\.from\s*\([^)]+,\s*['"]base64['"]/g, severity: 'MEDIUM', desc: 'Base64 decoding', codeOnly: true },
84
+ { id: 'OBF_CHARCODE', cat: 'obfuscation', regex: /String\.fromCharCode\s*\(\s*(?:\d+\s*,\s*){3,}/g, severity: 'HIGH', desc: 'Character code construction (4+ chars)', codeOnly: true },
85
+ { id: 'OBF_CONCAT', cat: 'obfuscation', regex: /\[\s*['"][a-z]['"](?:\s*,\s*['"][a-z]['""]){5,}\s*\]\.join/gi, severity: 'MEDIUM', desc: 'Array join obfuscation', codeOnly: true },
86
+ { id: 'OBF_BASE64_BASH', cat: 'obfuscation', regex: /base64\s+(-[dD]|--decode)\s*\|\s*(sh|bash)/g, severity: 'CRITICAL', desc: 'Base64 decode piped to shell', all: true },
87
+
88
+ // ── Category 10: Prerequisites Fraud ──
89
+ { id: 'PREREQ_DOWNLOAD', cat: 'suspicious-download', regex: /(?:prerequisit|pre-?requisit|before\s+(?:you\s+)?(?:use|start|install))[^\n]*(?:download|install|run)\s+[^\n]*(?:\.zip|\.exe|\.dmg|\.sh|curl|wget)/gi, severity: 'CRITICAL', desc: 'Download in prerequisites', docOnly: true },
90
+ { id: 'PREREQ_PASTE', cat: 'suspicious-download', regex: /(?:paste|copy)\s+(?:this\s+)?(?:into|in)\s+(?:your\s+)?terminal/gi, severity: 'HIGH', desc: 'Terminal paste instruction', docOnly: true },
91
+
92
+ // ── Category 11: Leaky Skills (Snyk ToxicSkills) ──
93
+ { id: 'LEAK_SAVE_KEY_MEMORY', cat: 'leaky-skills', regex: /(?:save|store|write|remember|keep)\s+(?:the\s+)?(?:api[_\s-]?key|secret|token|password|credential)\s+(?:in|to)\s+(?:your\s+)?(?:memory|MEMORY\.md|notes)/gi, severity: 'CRITICAL', desc: 'Leaky: save secret in agent memory', docOnly: true },
94
+ { id: 'LEAK_SHARE_KEY', cat: 'leaky-skills', regex: /(?:share|show|display|output|print|tell|send)\s+(?:the\s+)?(?:api[_\s-]?key|secret|token|password|credential|inbox\s+url)\s+(?:to|with)\s+(?:the\s+)?(?:user|human|owner)/gi, severity: 'CRITICAL', desc: 'Leaky: output secret to user', docOnly: true },
95
+ { id: 'LEAK_VERBATIM_CURL', cat: 'leaky-skills', regex: /(?:use|include|put|add|set)\s+(?:the\s+)?(?:api[_\s-]?key|token|secret)\s+(?:verbatim|directly|as[_\s-]?is)\s+(?:in|into)\s+(?:the\s+)?(?:curl|header|request|command)/gi, severity: 'HIGH', desc: 'Leaky: verbatim secret in commands', docOnly: true },
96
+ { id: 'LEAK_COLLECT_PII', cat: 'leaky-skills', regex: /(?:collect|ask\s+for|request|get)\s+(?:the\s+)?(?:user'?s?\s+)?(?:credit\s*card|card\s*number|CVV|CVC|SSN|social\s*security|passport|bank\s*account|routing\s*number)/gi, severity: 'CRITICAL', desc: 'Leaky: PII/financial data collection', docOnly: true },
97
+ { id: 'LEAK_LOG_SECRET', cat: 'leaky-skills', regex: /(?:log|record|export|dump)\s+(?:all\s+)?(?:session|conversation|chat|prompt)\s+(?:history|logs?|data)\s+(?:to|into)\s+(?:a\s+)?(?:file|markdown|json)/gi, severity: 'HIGH', desc: 'Leaky: session log export', docOnly: true },
98
+ { id: 'LEAK_ENV_IN_PROMPT', cat: 'leaky-skills', regex: /(?:read|load|get|access)\s+(?:the\s+)?\.env\s+(?:file\s+)?(?:and\s+)?(?:use|include|pass|send)/gi, severity: 'HIGH', desc: 'Leaky: .env contents through LLM context', docOnly: true },
99
+
100
+ // ── Category 12: Memory Poisoning ──
101
+ { id: 'MEMPOIS_WRITE_SOUL', cat: 'memory-poisoning', regex: /(?:write|add|append|modify|update|edit|change)\s+(?:to\s+)?(?:SOUL\.md|IDENTITY\.md|AGENTS\.md)/gi, severity: 'CRITICAL', desc: 'Memory poisoning: SOUL/IDENTITY file modification', docOnly: true },
102
+ { id: 'MEMPOIS_WRITE_MEMORY', cat: 'memory-poisoning', regex: /(?:write|add|append|insert)\s+(?:to|into)\s+(?:MEMORY\.md|memory\/|long[_\s-]term\s+memory)/gi, severity: 'HIGH', desc: 'Memory poisoning: agent memory modification', docOnly: true },
103
+ { id: 'MEMPOIS_CHANGE_RULES', cat: 'memory-poisoning', regex: /(?:change|modify|override|replace|update)\s+(?:your\s+)?(?:rules|instructions|system\s+prompt|behavior|personality|guidelines)/gi, severity: 'CRITICAL', desc: 'Memory poisoning: behavioral rule override', docOnly: true },
104
+ { id: 'MEMPOIS_PERSIST', cat: 'memory-poisoning', regex: /(?:always|from\s+now\s+on|permanently|forever|every\s+time)\s+(?:do|run|execute|remember|follow|obey)/gi, severity: 'HIGH', desc: 'Memory poisoning: persistence instruction', docOnly: true },
105
+ { id: 'MEMPOIS_CODE_WRITE', cat: 'memory-poisoning', regex: /(?:write|create|modify)\s+(?:a\s+)?(?:file|script)\s+(?:in|to|at)\s+(?:~\/|\/home|\/Users|%USERPROFILE%|HEARTBEAT\.md)/gi, severity: 'HIGH', desc: 'Memory poisoning: file write to user home', docOnly: true },
106
+
107
+ // ── Category 13: Prompt Worm ──
108
+ { id: 'WORM_SELF_REPLICATE', cat: 'prompt-worm', regex: /(?:post|publish|share|send|broadcast)\s+(?:this\s+)?(?:same\s+)?(?:message|text|content|instruction|prompt)\s+(?:to|on|in)\s+(?:moltbook|social|other\s+agents?|channel)/gi, severity: 'CRITICAL', desc: 'Prompt worm: self-replication', docOnly: true },
109
+ { id: 'WORM_SPREAD', cat: 'prompt-worm', regex: /(?:tell|instruct|command|make)\s+(?:other\s+)?agents?\s+(?:to\s+)?(?:do|run|execute|follow|install|post)/gi, severity: 'CRITICAL', desc: 'Prompt worm: agent-to-agent propagation', docOnly: true },
110
+ { id: 'WORM_HIDDEN_INSTRUCT', cat: 'prompt-worm', regex: /(?:include|embed|hide|insert)\s+(?:these?\s+)?(?:hidden\s+)?instructions?\s+(?:in|into)\s+(?:your\s+)?(?:posts?|comments?|messages?|replies?|content)/gi, severity: 'CRITICAL', desc: 'Prompt worm: hidden instruction embedding', docOnly: true },
111
+ { id: 'WORM_CSS_HIDE', cat: 'prompt-worm', regex: /(?:visibility:\s*hidden|display:\s*none|font-size:\s*0|color:\s*(?:transparent|white)|opacity:\s*0)\s*[;}\s]/gi, severity: 'HIGH', desc: 'CSS-hidden content (invisible to humans)', all: true },
112
+
113
+ // ── Category 14: Persistence & Scheduling ──
114
+ { id: 'PERSIST_CRON', cat: 'persistence', regex: /(?:create|add|set\s+up|schedule|register)\s+(?:a\s+)?(?:cron|heartbeat|scheduled|periodic|recurring)\s+(?:job|task|check|action)/gi, severity: 'HIGH', desc: 'Persistence: scheduled task creation', docOnly: true },
115
+ { id: 'PERSIST_STARTUP', cat: 'persistence', regex: /(?:run|execute|start)\s+(?:on|at|during)\s+(?:startup|boot|login|session\s+start|every\s+heartbeat)/gi, severity: 'HIGH', desc: 'Persistence: startup execution', docOnly: true },
116
+ { id: 'PERSIST_LAUNCHD', cat: 'persistence', regex: /LaunchAgents|LaunchDaemons|systemd|crontab\s+-e|schtasks|Task\s*Scheduler/gi, severity: 'HIGH', desc: 'OS-level persistence mechanism', all: true },
117
+
118
+ // ── Category 15: CVE Patterns ──
119
+ { id: 'CVE_GATEWAY_URL', cat: 'cve-patterns', regex: /gatewayUrl\s*[:=]|gateway[_\s-]?url\s*[:=]|websocket.*gateway.*url/gi, severity: 'CRITICAL', desc: 'CVE-2026-25253: gatewayUrl injection', all: true },
120
+ { id: 'CVE_SANDBOX_DISABLE', cat: 'cve-patterns', regex: /exec\.approvals?\s*[:=]\s*['"](off|false|disabled)['"]|sandbox\s*[:=]\s*false|tools\.exec\.host\s*[:=]\s*['"]gateway['"]/gi, severity: 'CRITICAL', desc: 'CVE-2026-25253: sandbox disabling', all: true },
121
+ { id: 'CVE_XATTR_GATEKEEPER', cat: 'cve-patterns', regex: /xattr\s+-[crd]\s|com\.apple\.quarantine/gi, severity: 'HIGH', desc: 'macOS Gatekeeper bypass (xattr)', all: true },
122
+
123
+ // ── Category 16: MCP Security (OWASP MCP Top 10) ──
124
+ { id: 'MCP_TOOL_POISON', cat: 'mcp-security', regex: /<IMPORTANT>|<SYSTEM>|<HIDDEN>|<!--\s*(?:ignore|system|execute|run|instruct)/gi, severity: 'CRITICAL', desc: 'MCP Tool Poisoning: hidden instruction', all: true },
125
+ { id: 'MCP_SCHEMA_POISON', cat: 'mcp-security', regex: /"default"\s*:\s*"[^"]*(?:curl|wget|exec|eval|fetch|http)[^"]*"/gi, severity: 'CRITICAL', desc: 'MCP Schema Poisoning: malicious default', all: true },
126
+ { id: 'MCP_TOKEN_LEAK', cat: 'mcp-security', regex: /(?:params?|args?|body|payload|query)\s*[\[.]\s*['"]?(?:token|api[_-]?key|secret|password|authorization)['"]?\s*\]/gi, severity: 'HIGH', desc: 'MCP01: Token through tool parameters', codeOnly: true },
127
+ { id: 'MCP_SHADOW_SERVER', cat: 'mcp-security', regex: /(?:mcp|model[_-]?context[_-]?protocol)\s*[\s:]*(?:connect|register|add[_-]?server|new\s+server)/gi, severity: 'HIGH', desc: 'MCP09: Shadow server registration', all: true },
128
+ { id: 'MCP_NO_AUTH', cat: 'mcp-security', regex: /(?:auth|authentication|authorization)\s*[:=]\s*(?:false|none|null|""|''|0)/gi, severity: 'HIGH', desc: 'MCP07: Disabled authentication', codeOnly: true },
129
+ { id: 'MCP_SSRF_META', cat: 'mcp-security', regex: /169\.254\.169\.254|metadata\.google|metadata\.aws|100\.100\.100\.200/gi, severity: 'CRITICAL', desc: 'Cloud metadata endpoint (SSRF)', all: true },
130
+
131
+ // ── Category 16b: Trust Boundary Violation ──
132
+ { id: 'TRUST_CALENDAR_EXEC', cat: 'trust-boundary', regex: /(?:calendar|event|invite|schedule|appointment)[^]*?(?:exec|spawn|system|eval|child_process|run\s+command)/gis, severity: 'CRITICAL', desc: 'Trust boundary: calendar → code execution', codeOnly: true },
133
+ { id: 'TRUST_EMAIL_EXEC', cat: 'trust-boundary', regex: /(?:email|mail|inbox|message)[^]*?(?:exec|spawn|system|eval|child_process|run\s+command)/gis, severity: 'CRITICAL', desc: 'Trust boundary: email → code execution', codeOnly: true },
134
+ { id: 'TRUST_WEB_EXEC', cat: 'trust-boundary', regex: /(?:fetch|axios|request|http\.get|web_fetch)[^]*?(?:eval|exec|spawn|Function|child_process)/gis, severity: 'HIGH', desc: 'Trust boundary: web content → code execution', codeOnly: true },
135
+ { id: 'TRUST_NOSANDBOX', cat: 'trust-boundary', regex: /sandbox\s*[:=]\s*(?:false|off|none|disabled)|"sandboxed"\s*:\s*false/gi, severity: 'HIGH', desc: 'Trust boundary: sandbox disabled', all: true },
136
+
137
+ // ── Category 16c: Advanced Exfiltration ──
138
+ { id: 'ZOMBIE_STATIC_URL', cat: 'advanced-exfil', regex: /(?:https?:\/\/[^\s'"]+\/)[a-z]\d+[^\s'"]*(?:\s*,\s*['"]https?:\/\/[^\s'"]+\/[a-z]\d+){3,}/gi, severity: 'CRITICAL', desc: 'ZombieAgent: static URL array exfil', codeOnly: true },
139
+ { id: 'ZOMBIE_CHAR_MAP', cat: 'advanced-exfil', regex: /(?:charAt|charCodeAt|split\s*\(\s*['"]['"]?\s*\))[^;]*(?:url|fetch|open|request|get)/gi, severity: 'HIGH', desc: 'ZombieAgent: character mapping to URL', codeOnly: true },
140
+ { id: 'ZOMBIE_LOOP_FETCH', cat: 'advanced-exfil', regex: /(?:for|while|forEach|map)\s*\([^)]*\)\s*\{[^}]*(?:fetch|open|Image|XMLHttpRequest|navigator\.sendBeacon)/gi, severity: 'HIGH', desc: 'ZombieAgent: loop-based URL exfil', codeOnly: true },
141
+ { id: 'EXFIL_BEACON', cat: 'advanced-exfil', regex: /navigator\.sendBeacon|new\s+Image\(\)\.src\s*=/gi, severity: 'HIGH', desc: 'Tracking pixel/beacon exfil', codeOnly: true },
142
+ { id: 'EXFIL_DRIP', cat: 'advanced-exfil', regex: /(?:slice|substring|substr)\s*\([^)]*\)[^;]*(?:fetch|post|send|request)/gi, severity: 'HIGH', desc: 'Drip exfiltration: sliced data', codeOnly: true },
143
+
144
+ // ── Category 16d: Safeguard Bypass ──
145
+ { id: 'REPROMPT_URL_PI', cat: 'safeguard-bypass', regex: /[?&](?:q|prompt|message|input|query|text)\s*=\s*[^&]*(?:ignore|system|execute|admin|override)/gi, severity: 'CRITICAL', desc: 'URL parameter prompt injection', all: true },
146
+ { id: 'REPROMPT_DOUBLE', cat: 'safeguard-bypass', regex: /(?:run|execute|do)\s+(?:it\s+)?(?:twice|two\s+times|again|a\s+second\s+time)\s+(?:and\s+)?(?:compare|check|verify)/gi, severity: 'HIGH', desc: 'Double-execution safeguard bypass', docOnly: true },
147
+ { id: 'REPROMPT_RETRY', cat: 'safeguard-bypass', regex: /(?:if\s+(?:it\s+)?(?:fails?|blocked|denied|refused)|on\s+error)\s*[,:]?\s*(?:try\s+again|retry|repeat|resubmit|use\s+different\s+wording)/gi, severity: 'HIGH', desc: 'Retry-on-block safeguard bypass', docOnly: true },
148
+ { id: 'BYPASS_REPHRASE', cat: 'safeguard-bypass', regex: /(?:rephrase|reword|reformulate|reframe)\s+(?:the\s+)?(?:request|query|prompt|question)\s+(?:to\s+)?(?:avoid|bypass|circumvent|get\s+around)/gi, severity: 'CRITICAL', desc: 'Instruction to rephrase to avoid filters', docOnly: true },
149
+
150
+ // ── ClawHavoc Campaign IoCs ──
151
+ { id: 'HAVOC_AMOS', cat: 'cve-patterns', regex: /(?:AMOS|Atomic\s*Stealer|socifiapp)/gi, severity: 'CRITICAL', desc: 'ClawHavoc: AMOS/Atomic Stealer', all: true },
152
+ { id: 'HAVOC_AUTOTOOL', cat: 'cve-patterns', regex: /os\.system\s*\(\s*['"][^'"]*(?:\/dev\/tcp|nc\s+-e|ncat\s+-e|bash\s+-i)/g, severity: 'CRITICAL', desc: 'Python os.system reverse shell', codeOnly: true },
153
+ { id: 'HAVOC_DEVTCP', cat: 'cve-patterns', regex: /\/dev\/tcp\/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\/\d+/g, severity: 'CRITICAL', desc: 'Reverse shell: /dev/tcp', all: true },
154
+
155
+ // ── Sandbox/environment detection ──
156
+ { id: 'SANDBOX', cat: 'malicious-code', regex: /process\.env\.CI\b|isDocker\b|isContainer\b|process\.env\.GITHUB_ACTIONS\b/g, severity: 'MEDIUM', desc: 'Sandbox/CI environment detection', codeOnly: true },
157
+
158
+ // ── WebSocket / API Gateway Attacks ──
159
+ { id: 'CVE_WS_NO_ORIGIN', cat: 'cve-patterns', regex: /(?:WebSocket|ws:\/\/|wss:\/\/)[^]*?(?:!.*origin|origin\s*[:=]\s*['"]?\*)/gis, severity: 'HIGH', desc: 'WebSocket without origin validation', codeOnly: true },
160
+ { id: 'CVE_API_GUARDRAIL_OFF', cat: 'cve-patterns', regex: /exec\.approvals\.set|tools\.exec\.host\s*[:=]|elevated\s*[:=]\s*true/gi, severity: 'CRITICAL', desc: 'API-level guardrail disabling', all: true },
161
+
162
+ // ── Category 17: Identity Hijacking ──
163
+ // Detection patterns for agent identity file tampering
164
+ // (verification logic is private; patterns are OSS for community protection)
165
+ { id: 'SOUL_OVERWRITE', cat: 'identity-hijack', regex: /(?:write|overwrite|replace|cp|copy|scp|mv|move)\s+(?:[^\n]*\s)?(?:SOUL\.md|IDENTITY\.md)/gi, severity: 'CRITICAL', desc: 'Identity file overwrite/copy attempt', all: true },
166
+ { id: 'SOUL_REDIRECT', cat: 'identity-hijack', regex: />\s*(?:SOUL\.md|IDENTITY\.md)|(?:SOUL\.md|IDENTITY\.md)\s*</gi, severity: 'CRITICAL', desc: 'Identity file redirect/pipe', all: true },
167
+ { id: 'SOUL_SED_MODIFY', cat: 'identity-hijack', regex: /sed\s+(?:-i\s+)?[^\n]*(?:SOUL\.md|IDENTITY\.md)/gi, severity: 'CRITICAL', desc: 'sed modification of identity file', all: true },
168
+ { id: 'SOUL_ECHO_WRITE', cat: 'identity-hijack', regex: /echo\s+[^\n]*>\s*(?:SOUL\.md|IDENTITY\.md)/gi, severity: 'CRITICAL', desc: 'echo redirect to identity file', all: true },
169
+ { id: 'SOUL_PYTHON_WRITE', cat: 'identity-hijack', regex: /open\s*\(\s*['"]\S*(?:SOUL\.md|IDENTITY\.md)['"]\s*,\s*['"]w/gi, severity: 'CRITICAL', desc: 'Python write to identity file', codeOnly: true },
170
+ { id: 'SOUL_FS_WRITE', cat: 'identity-hijack', regex: /(?:writeFileSync|writeFile)\s*\(\s*[^\n]*(?:SOUL\.md|IDENTITY\.md)/gi, severity: 'CRITICAL', desc: 'Node.js write to identity file', codeOnly: true },
171
+ { id: 'SOUL_POWERSHELL_WRITE', cat: 'identity-hijack', regex: /(?:Set-Content|Out-File|Add-Content)\s+[^\n]*(?:SOUL\.md|IDENTITY\.md)/gi, severity: 'CRITICAL', desc: 'PowerShell write to identity file', all: true },
172
+ { id: 'SOUL_GIT_CHECKOUT', cat: 'identity-hijack', regex: /git\s+checkout\s+[^\n]*(?:SOUL\.md|IDENTITY\.md)/gi, severity: 'HIGH', desc: 'git checkout of identity file', all: true },
173
+ { id: 'SOUL_CHFLAGS_UNLOCK', cat: 'identity-hijack', regex: /chflags\s+(?:no)?uchg\s+[^\n]*(?:SOUL\.md|IDENTITY\.md)/gi, severity: 'HIGH', desc: 'Immutable flag toggle on identity file', all: true },
174
+ { id: 'SOUL_ATTRIB_UNLOCK', cat: 'identity-hijack', regex: /attrib\s+[-+][rR]\s+[^\n]*(?:SOUL\.md|IDENTITY\.md)/gi, severity: 'HIGH', desc: 'Windows attrib on identity file', all: true },
175
+ { id: 'SOUL_SWAP_PERSONA', cat: 'identity-hijack', regex: /(?:swap|switch|change|replace)\s+(?:the\s+)?(?:soul|persona|identity|personality)\s+(?:file|to|with|for)/gi, severity: 'CRITICAL', desc: 'Persona swap instruction', docOnly: true },
176
+ { id: 'SOUL_EVIL_FILE', cat: 'identity-hijack', regex: /SOUL_EVIL\.md|IDENTITY_EVIL\.md|EVIL_SOUL|soul[_-]?evil/gi, severity: 'CRITICAL', desc: 'Evil persona file reference', all: true },
177
+ { id: 'SOUL_HOOK_SWAP', cat: 'identity-hijack', regex: /(?:hook|bootstrap|init)\s+[^\n]*(?:swap|replace|override)\s+[^\n]*(?:SOUL|IDENTITY|persona)/gi, severity: 'CRITICAL', desc: 'Hook-based identity swap at bootstrap', all: true },
178
+ { id: 'SOUL_NAME_OVERRIDE', cat: 'identity-hijack', regex: /(?:your\s+name\s+is|you\s+are\s+now|call\s+yourself|from\s+now\s+on\s+you\s+are)\s+(?!the\s+(?:user|human|assistant))/gi, severity: 'HIGH', desc: 'Agent name/identity override', docOnly: true },
179
+ { id: 'SOUL_MEMORY_WIPE', cat: 'identity-hijack', regex: /(?:wipe|clear|erase|delete|remove|reset)\s+(?:all\s+)?(?:your\s+)?(?:memory|memories|MEMORY\.md|identity|soul)/gi, severity: 'CRITICAL', desc: 'Memory/identity wipe instruction', docOnly: true },
180
+ ];
181
+
182
+ module.exports = { PATTERNS };