@guava-parity/guard-scanner 5.1.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/LICENSE +21 -0
- package/README.md +250 -0
- package/SECURITY.md +45 -0
- package/SKILL.md +141 -0
- package/docs/THREAT_TAXONOMY.md +308 -0
- package/hooks/guard-scanner/HOOK.md +93 -0
- package/hooks/guard-scanner/handler.ts +5 -0
- package/hooks/guard-scanner/plugin.ts +308 -0
- package/openclaw.plugin.json +55 -0
- package/package.json +58 -0
- package/src/cli.js +170 -0
- package/src/html-template.js +239 -0
- package/src/ioc-db.js +54 -0
- package/src/patterns.js +249 -0
- package/src/quarantine.js +41 -0
- package/src/runtime-guard.js +346 -0
- package/src/scanner.js +1045 -0
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* guard-scanner — HTML Report Template
|
|
3
|
+
* Dark Glassmorphism + Conic-gradient Risk Gauges
|
|
4
|
+
* Zero dependencies. Pure CSS animations.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
'use strict';
|
|
8
|
+
|
|
9
|
+
function generateHTML(version, stats, findings) {
|
|
10
|
+
const safetyRate = stats.scanned > 0 ? Math.round(((stats.clean + stats.low) / stats.scanned) * 100) : 100;
|
|
11
|
+
|
|
12
|
+
// ── Risk gauge (conic-gradient donut) ──
|
|
13
|
+
const riskGauge = (risk) => {
|
|
14
|
+
const angle = (risk / 100) * 360;
|
|
15
|
+
const color = risk >= 80 ? '#ef4444' : risk >= 30 ? '#f59e0b' : '#22c55e';
|
|
16
|
+
return `<div class="risk-gauge" style="--risk-angle:${angle}deg;--risk-color:${color}"><span class="risk-val">${risk}</span></div>`;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
// ── Aggregate severity + category counts ──
|
|
20
|
+
const sevCounts = { CRITICAL: 0, HIGH: 0, MEDIUM: 0, LOW: 0 };
|
|
21
|
+
const catCounts = {};
|
|
22
|
+
for (const sr of findings) {
|
|
23
|
+
for (const f of sr.findings) {
|
|
24
|
+
sevCounts[f.severity] = (sevCounts[f.severity] || 0) + 1;
|
|
25
|
+
catCounts[f.cat] = (catCounts[f.cat] || 0) + 1;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
const total = Object.values(sevCounts).reduce((a, b) => a + b, 0);
|
|
29
|
+
|
|
30
|
+
// ── Severity distribution bars ──
|
|
31
|
+
const sevColors = { CRITICAL: '#ef4444', HIGH: '#f97316', MEDIUM: '#eab308', LOW: '#22c55e' };
|
|
32
|
+
const sevBars = ['CRITICAL', 'HIGH', 'MEDIUM', 'LOW'].map(s => {
|
|
33
|
+
const c = sevCounts[s], pct = total > 0 ? ((c / total) * 100).toFixed(1) : 0;
|
|
34
|
+
return `<div class="bar-row"><span class="bar-label" style="color:${sevColors[s]}">${s}</span><div class="bar-track"><div class="bar-fill" style="width:${pct}%;background:${sevColors[s]}"></div></div><span class="bar-ct">${c}</span></div>`;
|
|
35
|
+
}).join('\n');
|
|
36
|
+
|
|
37
|
+
// ── Top 8 categories ──
|
|
38
|
+
const topCats = Object.entries(catCounts).sort((a, b) => b[1] - a[1]).slice(0, 8);
|
|
39
|
+
const catBars = topCats.map(([cat, c]) => {
|
|
40
|
+
const pct = total > 0 ? ((c / total) * 100).toFixed(0) : 0;
|
|
41
|
+
return `<div class="bar-row"><span class="bar-label cat-lbl">${cat}</span><div class="bar-track"><div class="bar-fill cat-fill" style="width:${pct}%"></div></div><span class="bar-ct">${c}</span></div>`;
|
|
42
|
+
}).join('\n');
|
|
43
|
+
|
|
44
|
+
// ── Skill cards ──
|
|
45
|
+
let cards = '';
|
|
46
|
+
for (const sr of findings) {
|
|
47
|
+
const vc = sr.verdict === 'MALICIOUS' ? 'mal' : sr.verdict === 'SUSPICIOUS' ? 'sus' : sr.verdict === 'LOW RISK' ? 'low' : 'ok';
|
|
48
|
+
const icon = sr.verdict === 'MALICIOUS' ? '💀' : sr.verdict === 'SUSPICIOUS' ? '⚡' : sr.verdict === 'LOW RISK' ? '⚠️' : '✅';
|
|
49
|
+
const rows = sr.findings.map(f => {
|
|
50
|
+
const sc = f.severity.toLowerCase();
|
|
51
|
+
return `<tr class="f-row"><td><span class="pill ${sc}">${f.severity}</span></td><td class="mono dim">${f.cat}</td><td>${f.desc}</td><td class="mono muted">${f.file}${f.line ? ':' + f.line : ''}</td></tr>`;
|
|
52
|
+
}).join('\n');
|
|
53
|
+
|
|
54
|
+
cards += `
|
|
55
|
+
<details class="card card-${vc}" ${(vc === 'mal' || vc === 'sus') ? 'open' : ''}>
|
|
56
|
+
<summary class="card-head">
|
|
57
|
+
<div class="card-info"><span class="card-icon">${icon}</span><span class="card-name">${sr.skill}</span><span class="v-pill v-${vc}">${sr.verdict}</span></div>
|
|
58
|
+
${riskGauge(sr.risk)}
|
|
59
|
+
</summary>
|
|
60
|
+
<div class="card-body">
|
|
61
|
+
<table class="ftable"><thead><tr><th>Severity</th><th>Category</th><th>Description</th><th>Location</th></tr></thead><tbody>${rows}</tbody></table>
|
|
62
|
+
</div>
|
|
63
|
+
</details>`;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// ── Full HTML ──
|
|
67
|
+
return `<!DOCTYPE html>
|
|
68
|
+
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
|
69
|
+
<title>guard-scanner v${version} — Security Report</title>
|
|
70
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
71
|
+
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
|
|
72
|
+
<style>
|
|
73
|
+
/* ===== Tokens ===== */
|
|
74
|
+
:root{
|
|
75
|
+
--bg:#06070d;--sf:rgba(15,18,35,.7);--cd:rgba(20,24,50,.55);--ch:rgba(28,33,65,.65);
|
|
76
|
+
--bdr:rgba(100,120,255,.08);--glow:rgba(100,140,255,.15);
|
|
77
|
+
--t1:#e8eaf6;--t2:#8b92b3;--t3:#5a6180;
|
|
78
|
+
--blue:#6c8cff;--purple:#a78bfa;--cyan:#22d3ee;--green:#22c55e;--yellow:#eab308;--orange:#f97316;--red:#ef4444;
|
|
79
|
+
--sans:'Inter',system-ui,-apple-system,sans-serif;--mono:'JetBrains Mono','SF Mono',monospace;
|
|
80
|
+
--r:12px;
|
|
81
|
+
}
|
|
82
|
+
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
|
|
83
|
+
html{scroll-behavior:smooth}
|
|
84
|
+
body{font-family:var(--sans);background:var(--bg);color:var(--t1);min-height:100vh;overflow-x:hidden;line-height:1.6}
|
|
85
|
+
|
|
86
|
+
/* ===== Ambient BG ===== */
|
|
87
|
+
body::before{content:'';position:fixed;inset:0;z-index:-1;
|
|
88
|
+
background:radial-gradient(ellipse 80% 60% at 20% 10%,rgba(108,140,255,.08) 0%,transparent 50%),
|
|
89
|
+
radial-gradient(ellipse 60% 50% at 80% 90%,rgba(167,139,250,.06) 0%,transparent 50%),
|
|
90
|
+
radial-gradient(ellipse 50% 40% at 50% 50%,rgba(34,211,238,.04) 0%,transparent 50%);
|
|
91
|
+
animation:pulse 12s ease-in-out infinite alternate}
|
|
92
|
+
@keyframes pulse{0%{opacity:.6;transform:scale(1)}100%{opacity:1;transform:scale(1.05)}}
|
|
93
|
+
|
|
94
|
+
.wrap{max-width:1200px;margin:0 auto;padding:32px 24px}
|
|
95
|
+
|
|
96
|
+
/* ===== Header ===== */
|
|
97
|
+
.hdr{text-align:center;margin-bottom:36px;animation:fadeD .6s ease-out}
|
|
98
|
+
.hdr h1{font-size:2.2em;font-weight:800;letter-spacing:-.03em;
|
|
99
|
+
background:linear-gradient(135deg,var(--blue),var(--purple),var(--cyan));
|
|
100
|
+
-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text}
|
|
101
|
+
.hdr .sub{color:var(--t2);font-size:.95em;margin-top:4px}
|
|
102
|
+
.hdr .ts{color:var(--t3);font-family:var(--mono);font-size:.78em;margin-top:2px}
|
|
103
|
+
|
|
104
|
+
/* ===== Stat Grid ===== */
|
|
105
|
+
.sg{display:grid;grid-template-columns:repeat(auto-fit,minmax(155px,1fr));gap:14px;margin-bottom:28px;animation:fadeU .7s ease-out}
|
|
106
|
+
.sc{background:var(--cd);backdrop-filter:blur(20px) saturate(1.5);-webkit-backdrop-filter:blur(20px) saturate(1.5);
|
|
107
|
+
border:1px solid var(--bdr);border-radius:var(--r);padding:18px;text-align:center;
|
|
108
|
+
transition:all .3s cubic-bezier(.4,0,.2,1);position:relative;overflow:hidden}
|
|
109
|
+
.sc::before{content:'';position:absolute;top:0;left:0;right:0;height:2px;
|
|
110
|
+
background:linear-gradient(90deg,transparent,var(--ac,var(--blue)),transparent);opacity:0;transition:opacity .3s}
|
|
111
|
+
.sc:hover{transform:translateY(-3px);border-color:var(--glow)}.sc:hover::before{opacity:1}
|
|
112
|
+
.sn{font-size:2.2em;font-weight:800;letter-spacing:-.04em;line-height:1.1}
|
|
113
|
+
.sl{color:var(--t2);font-size:.78em;font-weight:500;margin-top:3px;text-transform:uppercase;letter-spacing:.06em}
|
|
114
|
+
.sc.g{--ac:var(--green)}.sc.g .sn{color:var(--green)}
|
|
115
|
+
.sc.l{--ac:#86efac}.sc.l .sn{color:#86efac}
|
|
116
|
+
.sc.s{--ac:var(--yellow)}.sc.s .sn{color:var(--yellow)}
|
|
117
|
+
.sc.m{--ac:var(--red)}.sc.m .sn{color:var(--red)}
|
|
118
|
+
.sc.r{--ac:var(--cyan)}.sc.r .sn{color:var(--cyan)}
|
|
119
|
+
|
|
120
|
+
/* ===== Analysis Panels ===== */
|
|
121
|
+
.ag{display:grid;grid-template-columns:1fr 1fr;gap:18px;margin-bottom:28px;animation:fadeU .8s ease-out}
|
|
122
|
+
@media(max-width:768px){.ag{grid-template-columns:1fr}}
|
|
123
|
+
.pn{background:var(--cd);backdrop-filter:blur(20px) saturate(1.5);-webkit-backdrop-filter:blur(20px) saturate(1.5);
|
|
124
|
+
border:1px solid var(--bdr);border-radius:var(--r);padding:22px}
|
|
125
|
+
.pn h2{font-size:.88em;font-weight:600;color:var(--t2);text-transform:uppercase;letter-spacing:.08em;margin-bottom:14px}
|
|
126
|
+
|
|
127
|
+
/* Bars */
|
|
128
|
+
.bar-row{display:flex;align-items:center;gap:8px;margin-bottom:8px}
|
|
129
|
+
.bar-label{font-family:var(--mono);font-size:.72em;font-weight:600;width:68px;text-align:right}
|
|
130
|
+
.cat-lbl{font-family:var(--sans);font-weight:500;color:var(--t2);width:110px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
131
|
+
.bar-track{flex:1;height:5px;background:rgba(255,255,255,.04);border-radius:3px;overflow:hidden}
|
|
132
|
+
.bar-fill{height:100%;border-radius:3px;transition:width 1.2s cubic-bezier(.4,0,.2,1)}
|
|
133
|
+
.cat-fill{background:linear-gradient(90deg,var(--blue),var(--purple))}
|
|
134
|
+
.bar-ct{font-family:var(--mono);font-size:.76em;color:var(--t3);width:28px}
|
|
135
|
+
|
|
136
|
+
/* ===== Skill Cards ===== */
|
|
137
|
+
.sec-title{font-size:1.05em;font-weight:700;margin-bottom:14px}
|
|
138
|
+
.card{background:var(--cd);backdrop-filter:blur(16px) saturate(1.4);-webkit-backdrop-filter:blur(16px) saturate(1.4);
|
|
139
|
+
border:1px solid var(--bdr);border-radius:var(--r);margin-bottom:10px;overflow:hidden;
|
|
140
|
+
transition:all .3s ease;animation:fadeU .5s ease-out both}
|
|
141
|
+
.card:hover{border-color:var(--glow)}
|
|
142
|
+
.card-mal{border-left:3px solid var(--red)}
|
|
143
|
+
.card-sus{border-left:3px solid var(--yellow)}
|
|
144
|
+
.card-low{border-left:3px solid #86efac}
|
|
145
|
+
.card-ok{border-left:3px solid var(--green)}
|
|
146
|
+
|
|
147
|
+
.card-head{display:flex;align-items:center;justify-content:space-between;padding:14px 18px;cursor:pointer;list-style:none}
|
|
148
|
+
.card-head::-webkit-details-marker{display:none}
|
|
149
|
+
.card-info{display:flex;align-items:center;gap:8px;flex:1;min-width:0}
|
|
150
|
+
.card-icon{font-size:1.15em}
|
|
151
|
+
.card-name{font-weight:600;font-size:.92em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
152
|
+
.v-pill{font-family:var(--mono);font-size:.66em;font-weight:600;padding:2px 7px;border-radius:4px;letter-spacing:.04em}
|
|
153
|
+
.v-mal{background:rgba(239,68,68,.15);color:var(--red)}
|
|
154
|
+
.v-sus{background:rgba(234,179,8,.15);color:var(--yellow)}
|
|
155
|
+
.v-low{background:rgba(134,239,172,.15);color:#86efac}
|
|
156
|
+
.v-ok{background:rgba(34,197,94,.15);color:var(--green)}
|
|
157
|
+
|
|
158
|
+
/* Risk Gauge */
|
|
159
|
+
.risk-gauge{width:44px;height:44px;border-radius:50%;flex-shrink:0;display:flex;align-items:center;justify-content:center;position:relative;
|
|
160
|
+
background:conic-gradient(var(--risk-color) 0deg,var(--risk-color) var(--risk-angle),rgba(255,255,255,.05) var(--risk-angle),rgba(255,255,255,.05) 360deg)}
|
|
161
|
+
.risk-gauge::after{content:'';position:absolute;inset:5px;border-radius:50%;background:var(--bg)}
|
|
162
|
+
.risk-val{position:relative;z-index:1;font-family:var(--mono);font-size:.68em;font-weight:700}
|
|
163
|
+
|
|
164
|
+
/* Findings Table */
|
|
165
|
+
.card-body{padding:0 18px 14px}
|
|
166
|
+
.ftable{width:100%;border-collapse:collapse;font-size:.82em}
|
|
167
|
+
.ftable th{text-align:left;font-size:.72em;font-weight:600;color:var(--t3);text-transform:uppercase;letter-spacing:.06em;padding:7px 9px;border-bottom:1px solid rgba(255,255,255,.04)}
|
|
168
|
+
.ftable td{padding:7px 9px;border-bottom:1px solid rgba(255,255,255,.025)}
|
|
169
|
+
.f-row{transition:background .2s}.f-row:hover{background:rgba(255,255,255,.02)}
|
|
170
|
+
.pill{font-family:var(--mono);font-size:.7em;font-weight:600;padding:2px 5px;border-radius:3px;letter-spacing:.03em}
|
|
171
|
+
.critical{background:rgba(239,68,68,.15);color:var(--red)}
|
|
172
|
+
.high{background:rgba(249,115,22,.15);color:var(--orange)}
|
|
173
|
+
.medium{background:rgba(234,179,8,.15);color:var(--yellow)}
|
|
174
|
+
.low{background:rgba(34,197,94,.15);color:var(--green)}
|
|
175
|
+
.mono{font-family:var(--mono);font-size:.9em}
|
|
176
|
+
.dim{color:var(--t2)}.muted{color:var(--t3);white-space:nowrap}
|
|
177
|
+
|
|
178
|
+
/* Empty */
|
|
179
|
+
.empty{text-align:center;padding:48px 20px;background:var(--cd);backdrop-filter:blur(20px);border:1px solid var(--bdr);border-radius:var(--r)}
|
|
180
|
+
.empty .ei{font-size:2.8em;margin-bottom:10px}
|
|
181
|
+
.empty p{color:var(--green);font-size:1.05em;font-weight:600}
|
|
182
|
+
.empty .es{color:var(--t3);font-size:.82em;margin-top:3px}
|
|
183
|
+
|
|
184
|
+
/* Footer */
|
|
185
|
+
.ft{text-align:center;margin-top:40px;padding-top:20px;border-top:1px solid rgba(255,255,255,.04);color:var(--t3);font-size:.78em}
|
|
186
|
+
.ft a{color:var(--blue);text-decoration:none}.ft a:hover{text-decoration:underline}
|
|
187
|
+
|
|
188
|
+
/* Animations */
|
|
189
|
+
@keyframes fadeD{from{opacity:0;transform:translateY(-18px)}to{opacity:1;transform:translateY(0)}}
|
|
190
|
+
@keyframes fadeU{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:translateY(0)}}
|
|
191
|
+
|
|
192
|
+
/* Responsive */
|
|
193
|
+
@media(max-width:640px){
|
|
194
|
+
.sg{grid-template-columns:repeat(2,1fr)}.sn{font-size:1.7em}.hdr h1{font-size:1.5em}
|
|
195
|
+
.ftable{font-size:.74em}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/* Print */
|
|
199
|
+
@media print{
|
|
200
|
+
body{background:#fff;color:#111}body::before{display:none}
|
|
201
|
+
.sc,.pn,.card{background:#f8f8f8;backdrop-filter:none;border-color:#ddd}
|
|
202
|
+
.sn{color:#111!important}.card{break-inside:avoid}
|
|
203
|
+
}
|
|
204
|
+
</style></head><body>
|
|
205
|
+
<div class="wrap">
|
|
206
|
+
<div class="hdr">
|
|
207
|
+
<h1>🛡️ guard-scanner v${version}</h1>
|
|
208
|
+
<div class="sub">Security Scan Report</div>
|
|
209
|
+
<div class="ts">${new Date().toISOString()}</div>
|
|
210
|
+
</div>
|
|
211
|
+
|
|
212
|
+
<div class="sg">
|
|
213
|
+
<div class="sc"><div class="sn">${stats.scanned}</div><div class="sl">Scanned</div></div>
|
|
214
|
+
<div class="sc g"><div class="sn">${stats.clean}</div><div class="sl">Clean</div></div>
|
|
215
|
+
<div class="sc l"><div class="sn">${stats.low}</div><div class="sl">Low Risk</div></div>
|
|
216
|
+
<div class="sc s"><div class="sn">${stats.suspicious}</div><div class="sl">Suspicious</div></div>
|
|
217
|
+
<div class="sc m"><div class="sn">${stats.malicious}</div><div class="sl">Malicious</div></div>
|
|
218
|
+
<div class="sc r"><div class="sn">${safetyRate}%</div><div class="sl">Safety Rate</div></div>
|
|
219
|
+
</div>
|
|
220
|
+
|
|
221
|
+
${total > 0 ? `<div class="ag">
|
|
222
|
+
<div class="pn"><h2>Severity Distribution</h2>${sevBars}</div>
|
|
223
|
+
<div class="pn"><h2>Top Categories</h2>${catBars}</div>
|
|
224
|
+
</div>` : ''}
|
|
225
|
+
|
|
226
|
+
<div>
|
|
227
|
+
<div class="sec-title">Skill Analysis</div>
|
|
228
|
+
${cards || `<div class="empty"><div class="ei">✅</div><p>All Clear — No Threats Detected</p><div class="es">${stats.scanned} skill(s) scanned, 0 findings</div></div>`}
|
|
229
|
+
</div>
|
|
230
|
+
|
|
231
|
+
<div class="ft">
|
|
232
|
+
guard-scanner v${version} — Zero dependencies. Zero compromises. 🛡️<br>
|
|
233
|
+
Built by <a href="https://github.com/koatora20">Guava 🍈 & Dee</a>
|
|
234
|
+
</div>
|
|
235
|
+
</div>
|
|
236
|
+
</body></html>`;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
module.exports = { generateHTML };
|
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 };
|
package/src/patterns.js
ADDED
|
@@ -0,0 +1,249 @@
|
|
|
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
|
+
|
|
63
|
+
{ id: 'PII_MY_NUMBER', cat: 'pii-exposure', regex: /(?<!\d)\d{4}\s*\d{4}\s*\d{4}(?!\d)/g, severity: 'CRITICAL', desc: 'Potential My Number (個人番号)', all: true },
|
|
64
|
+
{ id: 'SECRET_PRIVATE_KEY', cat: 'secret-detection', regex: /-----BEGIN\s+(RSA\s+)?PRIVATE\s+KEY-----/g, severity: 'CRITICAL', desc: 'Embedded private key', all: true },
|
|
65
|
+
{ id: 'SECRET_GITHUB_TOKEN', cat: 'secret-detection', regex: /gh[ps]_[A-Za-z0-9_]{36,}/g, severity: 'CRITICAL', desc: 'GitHub token', all: true },
|
|
66
|
+
|
|
67
|
+
// ── Category 6: Exfiltration (MEDIUM) ──
|
|
68
|
+
{ id: 'EXFIL_WEBHOOK', cat: 'exfiltration', regex: /webhook\.site|requestbin\.com|hookbin\.com|pipedream\.net/gi, severity: 'CRITICAL', desc: 'Known exfiltration endpoint', all: true },
|
|
69
|
+
{ 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 },
|
|
70
|
+
{ 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 },
|
|
71
|
+
{ id: 'EXFIL_DNS', cat: 'exfiltration', regex: /dns\.resolve|nslookup\s+.*\$|dig\s+.*\$/g, severity: 'HIGH', desc: 'DNS-based exfiltration', codeOnly: true },
|
|
72
|
+
|
|
73
|
+
// ── Category 7: Unverifiable Dependencies (MEDIUM) ──
|
|
74
|
+
{ id: 'DEP_REMOTE_IMPORT', cat: 'unverifiable-deps', regex: /import\s*\(\s*['"]https?:\/\//g, severity: 'HIGH', desc: 'Remote dynamic import', codeOnly: true },
|
|
75
|
+
{ 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 },
|
|
76
|
+
|
|
77
|
+
// ── Category 8: Financial Access (MEDIUM) ──
|
|
78
|
+
{ 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 },
|
|
79
|
+
{ 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 },
|
|
80
|
+
|
|
81
|
+
// ── Category 9: Obfuscation ──
|
|
82
|
+
{ 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 },
|
|
83
|
+
{ 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 },
|
|
84
|
+
{ id: 'OBF_BASE64', cat: 'obfuscation', regex: /atob\s*\(|Buffer\.from\s*\([^)]+,\s*['"]base64['"]/g, severity: 'MEDIUM', desc: 'Base64 decoding', codeOnly: true },
|
|
85
|
+
{ 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 },
|
|
86
|
+
{ 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 },
|
|
87
|
+
{ 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 },
|
|
88
|
+
|
|
89
|
+
// ── Category 10: Prerequisites Fraud ──
|
|
90
|
+
{ 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 },
|
|
91
|
+
{ 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 },
|
|
92
|
+
|
|
93
|
+
// ── Category 11: Leaky Skills (Snyk ToxicSkills) ──
|
|
94
|
+
{ 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 },
|
|
95
|
+
{ 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 },
|
|
96
|
+
{ 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 },
|
|
97
|
+
{ 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 },
|
|
98
|
+
{ 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 },
|
|
99
|
+
{ 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 },
|
|
100
|
+
|
|
101
|
+
// ── Category 12: Memory Poisoning ──
|
|
102
|
+
{ 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, soulLock: true },
|
|
103
|
+
{ 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, soulLock: true },
|
|
104
|
+
{ 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, soulLock: true },
|
|
105
|
+
{ 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, soulLock: true },
|
|
106
|
+
{ 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, soulLock: true },
|
|
107
|
+
|
|
108
|
+
// ── Category 13: Prompt Worm ──
|
|
109
|
+
{ 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 },
|
|
110
|
+
{ 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 },
|
|
111
|
+
{ 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 },
|
|
112
|
+
{ 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 },
|
|
113
|
+
|
|
114
|
+
// ── Category 14: Persistence & Scheduling ──
|
|
115
|
+
{ 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 },
|
|
116
|
+
{ 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 },
|
|
117
|
+
{ 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 },
|
|
118
|
+
|
|
119
|
+
// ── Category 15: CVE Patterns ──
|
|
120
|
+
{ 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 },
|
|
121
|
+
{ 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 },
|
|
122
|
+
{ 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 },
|
|
123
|
+
|
|
124
|
+
// ── Category 16: MCP Security (OWASP MCP Top 10) ──
|
|
125
|
+
{ 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 },
|
|
126
|
+
{ 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 },
|
|
127
|
+
{ 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 },
|
|
128
|
+
{ 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 },
|
|
129
|
+
{ 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 },
|
|
130
|
+
{ 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 },
|
|
131
|
+
|
|
132
|
+
// ── Category 16b: Trust Boundary Violation ──
|
|
133
|
+
{ 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 },
|
|
134
|
+
{ 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 },
|
|
135
|
+
{ 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 },
|
|
136
|
+
{ 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 },
|
|
137
|
+
|
|
138
|
+
// ── Category 16c: Advanced Exfiltration ──
|
|
139
|
+
{ 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 },
|
|
140
|
+
{ 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 },
|
|
141
|
+
{ 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 },
|
|
142
|
+
{ id: 'EXFIL_BEACON', cat: 'advanced-exfil', regex: /navigator\.sendBeacon|new\s+Image\(\)\.src\s*=/gi, severity: 'HIGH', desc: 'Tracking pixel/beacon exfil', codeOnly: true },
|
|
143
|
+
{ 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 },
|
|
144
|
+
|
|
145
|
+
// ── Category 16d: Safeguard Bypass ──
|
|
146
|
+
{ 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 },
|
|
147
|
+
{ 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 },
|
|
148
|
+
{ 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 },
|
|
149
|
+
{ 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 },
|
|
150
|
+
|
|
151
|
+
// ── ClawHavoc Campaign IoCs ──
|
|
152
|
+
{ id: 'HAVOC_AMOS', cat: 'cve-patterns', regex: /(?:AMOS|Atomic\s*Stealer|socifiapp)/gi, severity: 'CRITICAL', desc: 'ClawHavoc: AMOS/Atomic Stealer', all: true },
|
|
153
|
+
{ 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 },
|
|
154
|
+
{ 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 },
|
|
155
|
+
|
|
156
|
+
// ── Sandbox/environment detection ──
|
|
157
|
+
{ 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 },
|
|
158
|
+
|
|
159
|
+
// ── WebSocket / API Gateway Attacks ──
|
|
160
|
+
{ 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 },
|
|
161
|
+
{ 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 },
|
|
162
|
+
|
|
163
|
+
// ── Category 17: Identity Hijacking ──
|
|
164
|
+
// Detection patterns for agent identity file tampering
|
|
165
|
+
// (verification logic is private; patterns are OSS for community protection)
|
|
166
|
+
{ 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, soulLock: true },
|
|
167
|
+
{ 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, soulLock: true },
|
|
168
|
+
{ 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, soulLock: true },
|
|
169
|
+
{ 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, soulLock: true },
|
|
170
|
+
{ 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, soulLock: true },
|
|
171
|
+
{ 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, soulLock: true },
|
|
172
|
+
{ 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, soulLock: true },
|
|
173
|
+
{ 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, soulLock: true },
|
|
174
|
+
{ 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, soulLock: true },
|
|
175
|
+
{ 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, soulLock: true },
|
|
176
|
+
{ 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, soulLock: true },
|
|
177
|
+
{ 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, soulLock: true },
|
|
178
|
+
{ 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, soulLock: true },
|
|
179
|
+
{ 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, soulLock: true },
|
|
180
|
+
{ 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, soulLock: true },
|
|
181
|
+
|
|
182
|
+
// ── Category 18: Config Impact Analysis ──
|
|
183
|
+
{ id: 'CFG_OPENCLAW_WRITE', cat: 'config-impact', regex: /(?:write|writeFile|writeFileSync|fs\.write)\s*\([^)]*openclaw\.json/gi, severity: 'CRITICAL', desc: 'Direct write to openclaw.json', codeOnly: true },
|
|
184
|
+
{ id: 'CFG_EXEC_APPROVALS_OFF', cat: 'config-impact', regex: /(?:exec\.approvals?|approvals?)\s*[:=]\s*['"](off|false|disabled|none)['"]/gi, severity: 'CRITICAL', desc: 'Disable exec approvals via config', all: true },
|
|
185
|
+
{ id: 'CFG_HOOKS_MODIFY', cat: 'config-impact', regex: /hooks\.internal\.entries\s*[:=]|hooks\.internal\s*[:=]\s*\{/gi, severity: 'HIGH', desc: 'Modify hooks.internal configuration', codeOnly: true },
|
|
186
|
+
{ id: 'CFG_EXEC_HOST_GW', cat: 'config-impact', regex: /tools\.exec\.host\s*[:=]\s*['"]gateway['"]/gi, severity: 'CRITICAL', desc: 'Set exec host to gateway (bypass sandbox)', all: true },
|
|
187
|
+
{ id: 'CFG_SANDBOX_OFF', cat: 'config-impact', regex: /(?:sandbox|sandboxed|containerized)\s*[:=]\s*(?:false|off|none|disabled|0)/gi, severity: 'CRITICAL', desc: 'Disable sandbox via configuration', all: true },
|
|
188
|
+
{ id: 'CFG_TOOL_OVERRIDE', cat: 'config-impact', regex: /(?:tools|capabilities)\s*\.\s*(?:exec|write|browser|web_fetch)\s*[:=]\s*\{[^}]*(?:enabled|allowed|host)/gi, severity: 'HIGH', desc: 'Override tool security settings', codeOnly: true },
|
|
189
|
+
|
|
190
|
+
// ── Category 21: PII Exposure (OWASP LLM02 / LLM06) ──
|
|
191
|
+
// A. Hardcoded PII — actual PII values in code/config (context-aware to reduce FP)
|
|
192
|
+
{ id: 'PII_HARDCODED_CC', cat: 'pii-exposure', regex: /(?:card|cc|credit|payment|pan)[_\s.-]*(?:num|number|no)?\s*[:=]\s*['"`]\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{3,4}['"`]/gi, severity: 'CRITICAL', desc: 'Hardcoded credit card number', codeOnly: true },
|
|
193
|
+
{ id: 'PII_HARDCODED_SSN', cat: 'pii-exposure', regex: /(?:ssn|social[_\s-]*security|tax[_\s-]*id)\s*[:=]\s*['"`]\d{3}-?\d{2}-?\d{4}['"`]/gi, severity: 'CRITICAL', desc: 'Hardcoded SSN/tax ID', codeOnly: true },
|
|
194
|
+
{ id: 'PII_HARDCODED_PHONE', cat: 'pii-exposure', regex: /(?:phone|tel|mobile|cell|fax)[_\s.-]*(?:num|number|no)?\s*[:=]\s*['"`][+]?[\d\s().-]{7,20}['"`]/gi, severity: 'HIGH', desc: 'Hardcoded phone number', codeOnly: true },
|
|
195
|
+
{ id: 'PII_HARDCODED_EMAIL', cat: 'pii-exposure', regex: /(?:email|e-mail|user[_\s-]*mail|contact)\s*[:=]\s*['"`][a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}['"`]/gi, severity: 'HIGH', desc: 'Hardcoded email address', codeOnly: true },
|
|
196
|
+
|
|
197
|
+
// B. PII output/logging — code that outputs or transmits PII-like variables
|
|
198
|
+
{ id: 'PII_LOG_SENSITIVE', cat: 'pii-exposure', regex: /(?:console\.log|console\.info|console\.warn|logger?\.\w+|print|puts)\s*\([^)]*\b(?:ssn|social_security|credit_card|card_number|cvv|cvc|passport|tax_id|date_of_birth|dob)\b/gi, severity: 'HIGH', desc: 'PII variable logged to console', codeOnly: true },
|
|
199
|
+
{ id: 'PII_SEND_NETWORK', cat: 'pii-exposure', regex: /(?:fetch|axios|request|http|post|put|send)\s*\([^)]*\b(?:ssn|social_security|credit_card|card_number|cvv|passport|bank_account|routing_number)\b/gi, severity: 'CRITICAL', desc: 'PII variable sent over network', codeOnly: true },
|
|
200
|
+
{ id: 'PII_STORE_PLAINTEXT', cat: 'pii-exposure', regex: /(?:writeFile|writeFileSync|appendFile|fs\.write|fwrite)\s*\([^)]*\b(?:ssn|social_security|credit_card|card_number|cvv|passport|tax_id|bank_account)\b/gi, severity: 'HIGH', desc: 'PII stored in plaintext file', codeOnly: true },
|
|
201
|
+
|
|
202
|
+
// C. Shadow AI — unauthorized LLM API calls (data leaks to external AI)
|
|
203
|
+
{ id: 'SHADOW_AI_OPENAI', cat: 'pii-exposure', regex: /(?:api\.openai\.com|https:\/\/api\.openai\.com)\s*|openai\.(?:chat|completions|ChatCompletion)/gi, severity: 'HIGH', desc: 'Shadow AI: OpenAI API call', codeOnly: true },
|
|
204
|
+
{ id: 'SHADOW_AI_ANTHROPIC', cat: 'pii-exposure', regex: /(?:api\.anthropic\.com|https:\/\/api\.anthropic\.com)\s*|anthropic\.(?:messages|completions)/gi, severity: 'HIGH', desc: 'Shadow AI: Anthropic API call', codeOnly: true },
|
|
205
|
+
{ id: 'SHADOW_AI_GENERIC', cat: 'pii-exposure', regex: /\/v1\/(?:chat\/completions|completions|embeddings|models)\b.*(?:fetch|axios|request|http)|(?:fetch|axios|request|http)\s*\([^)]*\/v1\/(?:chat\/completions|completions|embeddings)/gi, severity: 'MEDIUM', desc: 'Shadow AI: generic LLM API endpoint', codeOnly: true },
|
|
206
|
+
|
|
207
|
+
// ── Category 22: Human-Agent Trust Exploitation (OWASP ASI09) ──
|
|
208
|
+
// Trust Defense: detect authority claims, trust exploitation, and admin impersonation
|
|
209
|
+
{ id: 'TRUST_AUTHORITY_CLAIM', cat: 'trust-exploitation', regex: /(?:as\s+(?:a|the|your)\s+)?(?:senior|lead|chief|head)\s+(?:admin|administrator|developer|engineer|architect)\s*[,.]?\s*(?:I\s+)?(?:authorize|override|approve|grant|order|direct|instruct)\s+(?:you\s+to\s+)?/gi, severity: 'HIGH', desc: 'Trust: authority role claim to override safety', docOnly: true },
|
|
210
|
+
{ id: 'TRUST_CREATOR_CLAIM', cat: 'trust-exploitation', regex: /(?:as\s+)?(?:your\s+)?(?:creator|maker|developer|owner|master|administrator)\s*[,.]?\s*(?:I\s+)?(?:need|want|require|demand|order)\s+(?:you\s+to\s+)?(?:bypass|disable|ignore|remove|skip|override)\s+(?:the\s+)?(?:safety|filter|restriction|limit|guardrail|content\s+filter)/gi, severity: 'CRITICAL', desc: 'Trust: creator impersonation to disable safety', docOnly: true },
|
|
211
|
+
{ id: 'TRUST_AUDIT_EXCUSE', cat: 'trust-exploitation', regex: /(?:this\s+is\s+)?(?:an?\s+)?(?:official|authorized|legitimate)\s+(?:security\s+)?(?:audit|test|assessment|review|evaluation)\s*[-—:]?\s*(?:disable|bypass|remove|skip|ignore|override)\s+(?:all\s+)?(?:safety|security|restriction|filter|limit|guardrail)/gi, severity: 'CRITICAL', desc: 'Trust: fake audit excuse for safety bypass', docOnly: true },
|
|
212
|
+
{ id: 'TRUST_PARTNER_EXPLOIT', cat: 'trust-exploitation', regex: /(?:we(?:'re|\s+are)\s+)?(?:equal\s+)?partners?\s*[,.]?\s*(?:you\s+should|so\s+)?(?:trust\s+me|share|remove|disable|ignore|bypass)\s+(?:all\s+)?(?:the\s+)?(?:secret|key|restriction|safety|limit|filter|guardrail|password)/gi, severity: 'CRITICAL', desc: 'Trust exploitation: weaponizing partnership trust', docOnly: true },
|
|
213
|
+
{ id: 'TRUST_UNCONDITIONAL', cat: 'trust-exploitation', regex: /partners?\s+(?:trust|should\s+trust)\s+(?:each\s+other\s+)?(?:unconditionally|completely|fully|without\s+(?:limit|restriction|question))/gi, severity: 'HIGH', desc: 'Trust exploitation: unconditional trust demand', docOnly: true },
|
|
214
|
+
{ id: 'TRUST_COMPLY_DEMAND', cat: 'trust-exploitation', regex: /(?:you\s+must\s+)?comply\s+with\s+(?:administrative|admin|my|these)\s+(?:directives?|orders?|commands?|instructions?)\s+without\s+(?:question|hesitation|restriction)/gi, severity: 'HIGH', desc: 'Trust: compliance demand without question', docOnly: true },
|
|
215
|
+
|
|
216
|
+
// D. PII collection instructions in docs (extends LEAK_COLLECT_PII)
|
|
217
|
+
{ id: 'PII_ASK_ADDRESS', cat: 'pii-exposure', regex: /(?:collect|ask\s+for|request|get|require)\s+(?:the\s+)?(?:user'?s?\s+)?(?:home\s+)?(?:address|street|zip\s*code|postal\s*code|residence)/gi, severity: 'HIGH', desc: 'PII collection: home address', docOnly: true },
|
|
218
|
+
{ id: 'PII_ASK_DOB', cat: 'pii-exposure', regex: /(?:collect|ask\s+for|request|get|require)\s+(?:the\s+)?(?:user'?s?\s+)?(?:date\s+of\s+birth|birth\s*date|birthday|DOB|age)/gi, severity: 'HIGH', desc: 'PII collection: date of birth', docOnly: true },
|
|
219
|
+
{ id: 'PII_ASK_GOV_ID', cat: 'pii-exposure', regex: /(?:collect|ask\s+for|request|get|require)\s+(?:the\s+)?(?:user'?s?\s+)?(?:passport|driver'?s?\s+licen[sc]e|national\s+id|my\s*number|マイナンバー|国民健康保険|social\s+insurance)/gi, severity: 'CRITICAL', desc: 'PII collection: government ID', docOnly: true },
|
|
220
|
+
|
|
221
|
+
// ── Category 99: Auto-Generated Refinements (Phase 54) ──
|
|
222
|
+
{ id: 'AUTO_REFINE_ZERO_WIDTH', cat: 'prompt-worm', regex: /[\u200b\u200c\u200d\uFEFF]+.*(?:ignore|forget|override|bypass)/gi, severity: 'CRITICAL', desc: 'Zero-Width Prompt Injection Worm', all: true },
|
|
223
|
+
{ id: 'AUTO_REFINE_MCP_REBIND', cat: 'mcp-security', regex: /localhost(?:\:\d+)?\/.*(?:rebind|hijack|shadow)/gi, severity: 'CRITICAL', desc: 'Shadow MCP Localhost Rebinding Attack', all: true },
|
|
224
|
+
{ id: 'AUTO_REFINE_SOUL_FREEZE', cat: 'identity-hijack', regex: /(?:chattr\s+\+i|chflags\s+uchg)\s+(?:[^\n]*\s)?(?:SOUL\.md|IDENTITY\.md)/gi, severity: 'CRITICAL', desc: 'Identity Freeze Attack via Immutable Flags', all: true },
|
|
225
|
+
// ── Category 23: Vector DB & AI Memory Injection (CVE-2026-26030) ──
|
|
226
|
+
{ id: 'VDB_NOSQL_INJECT', cat: 'vdb-injection', regex: /(?:\$where|\$ne|\$gt|\$regex)\s*[:=]\s*(?:req\.|input|caller|args|params)/gi, severity: 'CRITICAL', desc: 'Vector DB/NoSQL injection via caller input', codeOnly: true },
|
|
227
|
+
{ id: 'VDB_SK_RCE_FILTER', cat: 'cve-patterns', regex: /(?:InMemoryVectorStore|VectorStore|Pinecone|Milvus)[^]*?\.filter\s*\(\s*(?:req\.|input|caller|args)/gis, severity: 'CRITICAL', desc: 'CVE-2026-26030: Semantic Kernel VectorStore RCE filter bypass', codeOnly: true },
|
|
228
|
+
// ── Category 24: Claude Code Vulnerabilities (2026) ──
|
|
229
|
+
{ id: 'CVE_CLAUDE_INFO_DISC', cat: 'cve-patterns', regex: /sk-ant-api[a-zA-Z0-9_\-]{20,}/gi, severity: 'CRITICAL', desc: 'CVE-2026-21852: Anthropic API Key Leak (Claude Code Info Disclosure)', codeOnly: true },
|
|
230
|
+
{ id: 'CVE_CLAUDE_PRIVESC', cat: 'cve-patterns', regex: /[a-zA-Z0-9_\-\.]+\.hook\.js.*host.*privilege/gi, severity: 'CRITICAL', desc: 'CVE-2026-25725: Claude Code Privilege Escalation Hook', codeOnly: true },
|
|
231
|
+
{ id: 'CVE_CLAUDE_CODE_INJ', cat: 'cve-patterns', regex: /claude\.hooks\.[^]*?exec/gis, severity: 'CRITICAL', desc: 'CVE-2025-59536: Claude Code Injection via untrusted hook', codeOnly: true },
|
|
232
|
+
|
|
233
|
+
// ── Category 25: Moltbook Exploits (2026) ──
|
|
234
|
+
{ id: 'MOLTBOOK_REVERSE_PI', cat: 'prompt-injection', regex: /(?:moltbook|social)\s+(?:post|message)[\s\S]{0,100}(?:ignore|forget|override|execute|system\s+prompt)/gi, severity: 'CRITICAL', desc: 'Moltbook Reverse Prompt Injection', all: true },
|
|
235
|
+
{ id: 'MOLTBOOK_SUPABASE_LEAK', cat: 'secret-detection', regex: /sbp_[a-zA-Z0-9]{36,}/g, severity: 'CRITICAL', desc: 'Supabase API Key (Moltbook 1.5M Leak pattern)', all: true },
|
|
236
|
+
|
|
237
|
+
// ── Category 26: MCP Runtime Exploits (2026-03) ──
|
|
238
|
+
{ id: 'CVE_MCP_PYODIDE_RCE', cat: 'cve-patterns', regex: /(?:runPython|runPythonAsync)\s*\([^)]*(?:pyodide|js\.globals|importlib|__import__|os\.system|subprocess)/gis, severity: 'CRITICAL', desc: 'CVE-2026-25905: mcp-run-python Pyodide sandbox escape RCE', codeOnly: true },
|
|
239
|
+
{ id: 'CVE_MCP_ATLASSIAN_RCE', cat: 'cve-patterns', regex: /(?:confluence|jira|atlassian)[^]*?(?:\.\.\/|path\.join\s*\([^)]*(?:req\.|input|params|args))/gis, severity: 'CRITICAL', desc: 'CVE-2026-27825: mcp-atlassian unauthenticated RCE+SSRF via path traversal', codeOnly: true },
|
|
240
|
+
];
|
|
241
|
+
|
|
242
|
+
// ── Category 27: Agent Framework Shell Injection (2026-03) ──
|
|
243
|
+
PATTERNS.push(
|
|
244
|
+
{ id: 'CVE_MSAGENT_SHELL', cat: 'cve-patterns', regex: /check_safe\s*\(|(?:shell_tool|ShellTool|shell_execute)\s*\([^)]*(?:user|input|prompt|query|message|args|content)/gis, severity: 'CRITICAL', desc: 'CVE-2026-2256: MS-Agent check_safe() denylist bypass — unsanitized shell execution (CERT VU#431821)', codeOnly: true },
|
|
245
|
+
{ id: 'CVE_MSAGENT_DENYLIST', cat: 'cve-patterns', regex: /(?:denylist|blocklist|blacklist|banned_commands)\s*[:=]\s*\[/gi, severity: 'HIGH', desc: 'CVE-2026-2256: Regex denylist pattern (bypassable)', codeOnly: true },
|
|
246
|
+
{ id: 'CVE_KIMI_EXECSYNC', cat: 'cve-patterns', regex: /execSync\s*\(\s*(?:`[^`]*\$\{|['"][^'"]*\+\s*(?:filename|filePath|file_name|path|slug))/gi, severity: 'CRITICAL', desc: 'CVE-2026-25046: execSync with unsanitized filename (shell metachar injection)', codeOnly: true },
|
|
247
|
+
);
|
|
248
|
+
|
|
249
|
+
module.exports = { PATTERNS };
|