guard-scanner 2.0.0 β 2.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/README.md +82 -43
- package/hooks/guard-scanner/plugin.ts +42 -0
- package/package.json +2 -2
- package/src/patterns.js +22 -0
- package/src/scanner.js +8 -2
package/README.md
CHANGED
|
@@ -2,16 +2,16 @@
|
|
|
2
2
|
<h1 align="center">π‘οΈ guard-scanner</h1>
|
|
3
3
|
<p align="center">
|
|
4
4
|
<strong>Static security scanner for AI agent skills</strong><br>
|
|
5
|
-
Detect prompt injection, credential theft, exfiltration,
|
|
6
|
-
<sub>π
|
|
5
|
+
Detect prompt injection, credential theft, exfiltration, PII exposure, Shadow AI, and 17 more threat categories.<br>
|
|
6
|
+
<sub>π v2.1 β PII Exposure Detection + Shadow AI + Plugin Hook blocking via <code>block</code>/<code>blockReason</code> API</sub>
|
|
7
7
|
</p>
|
|
8
8
|
<p align="center">
|
|
9
9
|
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="MIT License"></a>
|
|
10
10
|
<img src="https://img.shields.io/badge/node-%3E%3D18.0.0-brightgreen" alt="Node.js 18+">
|
|
11
11
|
<img src="https://img.shields.io/badge/dependencies-0-success" alt="Zero Dependencies">
|
|
12
|
-
<img src="https://img.shields.io/badge/tests-
|
|
13
|
-
<img src="https://img.shields.io/badge/patterns-
|
|
14
|
-
<img src="https://img.shields.io/badge/categories-
|
|
12
|
+
<img src="https://img.shields.io/badge/tests-99%2F99-brightgreen" alt="Tests Passing">
|
|
13
|
+
<img src="https://img.shields.io/badge/patterns-129-orange" alt="129 Patterns">
|
|
14
|
+
<img src="https://img.shields.io/badge/categories-21-blueviolet" alt="21 Categories">
|
|
15
15
|
</p>
|
|
16
16
|
</p>
|
|
17
17
|
|
|
@@ -40,8 +40,8 @@ The AI agent skill ecosystem has the same supply-chain security problem that npm
|
|
|
40
40
|
|
|
41
41
|
| Feature | Description |
|
|
42
42
|
|---|---|
|
|
43
|
-
| **
|
|
44
|
-
| **
|
|
43
|
+
| **21 Threat Categories** | Snyk ToxicSkills + OWASP MCP Top 10 + Identity Hijacking + Sandbox/Complexity/Config + PII |
|
|
44
|
+
| **129 Detection Patterns** | Regex-based static analysis covering code, docs, and data files |
|
|
45
45
|
| **IoC Database** | Known malicious IPs, domains, URLs, usernames, and typosquat names |
|
|
46
46
|
| **Data Flow Analysis** | Lightweight JS analysis: secret reads β network calls β exec chains |
|
|
47
47
|
| **Cross-File Analysis** | Phantom references, base64 fragment assembly, multi-file exfil detection |
|
|
@@ -84,7 +84,7 @@ npx guard-scanner ~/.openclaw/workspace/skills --self-exclude --verbose
|
|
|
84
84
|
cp hooks/guard-scanner/plugin.ts ~/.openclaw/plugins/guard-scanner-runtime.ts
|
|
85
85
|
```
|
|
86
86
|
|
|
87
|
-
> **π v2.
|
|
87
|
+
> **π v2.1** β PII Exposure Detection (OWASP LLM02/06) + Shadow AI detection + Plugin Hook `block`/`blockReason` API. 3 modes: `monitor`, `enforce`, `strict`.
|
|
88
88
|
|
|
89
89
|
### Installation (Optional)
|
|
90
90
|
|
|
@@ -99,7 +99,7 @@ npx guard-scanner ./skills/
|
|
|
99
99
|
### As an OpenClaw Skill
|
|
100
100
|
|
|
101
101
|
```bash
|
|
102
|
-
|
|
102
|
+
clawhub install guard-scanner
|
|
103
103
|
guard-scanner ~/.openclaw/workspace/skills/ --self-exclude --verbose
|
|
104
104
|
```
|
|
105
105
|
|
|
@@ -109,7 +109,7 @@ guard-scanner ~/.openclaw/workspace/skills/ --self-exclude --verbose
|
|
|
109
109
|
|
|
110
110
|
## Threat Categories
|
|
111
111
|
|
|
112
|
-
guard-scanner covers **
|
|
112
|
+
guard-scanner covers **21 threat categories** derived from four sources:
|
|
113
113
|
|
|
114
114
|
| # | Category | Based On | Severity | What It Detects |
|
|
115
115
|
|---|----------|----------|----------|----------------|
|
|
@@ -133,8 +133,9 @@ guard-scanner covers **20 threat categories** derived from four sources:
|
|
|
133
133
|
| 18 | **Sandbox Validation** | v1.1 | HIGH | Dangerous binary requirements in SKILL.md, overly broad file scope, sensitive env vars, exec/network declarations |
|
|
134
134
|
| 19 | **Code Complexity** | v1.1 | MEDIUM | Excessive file length (>1000 lines), deep nesting (>5 levels), high eval/exec density |
|
|
135
135
|
| 20 | **Config Impact** | v1.1 | CRITICAL | `openclaw.json` writes, exec approval bypass, exec host gateway, internal hooks modification, network wildcard |
|
|
136
|
+
| 21 | **PII Exposure** | v2.1 | CRITICAL | Hardcoded CC/SSN/phone/email (context-aware), PII logging/network send/plaintext store, Shadow AI (OpenAI/Anthropic/generic LLM), PII collection instructions (address/DOB/government ID) |
|
|
136
137
|
|
|
137
|
-
> **Categories 17β
|
|
138
|
+
> **Categories 17β21** are unique to guard-scanner. Category 17 (Identity Hijacking) was developed from a real attack. Categories 18β20 added in v1.1.0. Category 21 (PII Exposure) added in v2.1.0 covering OWASP LLM02/LLM06.
|
|
138
139
|
|
|
139
140
|
---
|
|
140
141
|
|
|
@@ -143,7 +144,7 @@ guard-scanner covers **20 threat categories** derived from four sources:
|
|
|
143
144
|
### Terminal (Default)
|
|
144
145
|
|
|
145
146
|
```
|
|
146
|
-
π‘οΈ guard-scanner
|
|
147
|
+
π‘οΈ guard-scanner v2.1.0
|
|
147
148
|
ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
148
149
|
π Scanning: ./skills/
|
|
149
150
|
π¦ Skills found: 22
|
|
@@ -228,6 +229,9 @@ Certain combinations multiply the base score:
|
|
|
228
229
|
| Config impact | **Γ2** | OpenClaw configuration tampering |
|
|
229
230
|
| Config impact + Sandbox violation | **min 70** | Combined config + capability abuse |
|
|
230
231
|
| Complexity + Malicious code/Obfuscation | **Γ1.5** | Complex code hiding threats |
|
|
232
|
+
| PII exposure + Exfiltration | **Γ3** | PII being sent to external servers |
|
|
233
|
+
| PII exposure + Shadow AI | **Γ2.5** | PII leak through unauthorized LLM |
|
|
234
|
+
| PII exposure + Credential handling | **Γ2** | Combined PII + credential risk |
|
|
231
235
|
| Known IoC (IP/URL/typosquat) | **= 100** | Confirmed malicious |
|
|
232
236
|
|
|
233
237
|
### Verdict Thresholds
|
|
@@ -400,8 +404,8 @@ Options:
|
|
|
400
404
|
```
|
|
401
405
|
guard-scanner/
|
|
402
406
|
βββ src/
|
|
403
|
-
β βββ scanner.js # GuardScanner class β core scan engine (
|
|
404
|
-
β βββ patterns.js #
|
|
407
|
+
β βββ scanner.js # GuardScanner class β core scan engine (21 checks)
|
|
408
|
+
β βββ patterns.js # 129 threat detection patterns (Cat 1β21)
|
|
405
409
|
β βββ ioc-db.js # Indicators of Compromise database
|
|
406
410
|
β βββ cli.js # CLI entry point and argument parser
|
|
407
411
|
βββ hooks/
|
|
@@ -410,9 +414,9 @@ guard-scanner/
|
|
|
410
414
|
β βββ handler.ts # Legacy Internal Hook β warn only (deprecated)
|
|
411
415
|
β βββ HOOK.md # Internal Hook manifest (legacy)
|
|
412
416
|
βββ test/
|
|
413
|
-
β βββ scanner.test.js #
|
|
417
|
+
β βββ scanner.test.js # 64 tests β static scanner (incl. PII v2.1)
|
|
414
418
|
β βββ plugin.test.js # 35 tests β Plugin Hook runtime guard
|
|
415
|
-
β βββ fixtures/ # Malicious, clean, complex, config-changer samples
|
|
419
|
+
β βββ fixtures/ # Malicious, clean, complex, config-changer, pii-leaky samples
|
|
416
420
|
βββ package.json # Zero dependencies, node --test
|
|
417
421
|
βββ CHANGELOG.md
|
|
418
422
|
βββ LICENSE # MIT
|
|
@@ -536,11 +540,11 @@ console.log(scanner.toHTML()); // HTML string
|
|
|
536
540
|
## Test Results
|
|
537
541
|
|
|
538
542
|
```
|
|
539
|
-
βΉ tests
|
|
540
|
-
βΉ suites
|
|
541
|
-
βΉ pass
|
|
543
|
+
βΉ tests 99
|
|
544
|
+
βΉ suites 16
|
|
545
|
+
βΉ pass 99
|
|
542
546
|
βΉ fail 0
|
|
543
|
-
βΉ duration_ms
|
|
547
|
+
βΉ duration_ms 142ms
|
|
544
548
|
```
|
|
545
549
|
|
|
546
550
|
| Suite | Tests | Coverage |
|
|
@@ -550,14 +554,34 @@ console.log(scanner.toHTML()); // HTML string
|
|
|
550
554
|
| Risk Score Calculation | 5 | Empty, single, combo amplifiers, IoC override |
|
|
551
555
|
| Verdict Determination | 5 | All verdicts + strict mode |
|
|
552
556
|
| Output Formats | 4 | JSON + SARIF 2.1.0 + HTML structure |
|
|
553
|
-
| Pattern Database | 4 |
|
|
557
|
+
| Pattern Database | 4 | 125+ count, required fields, category coverage, regex safety |
|
|
554
558
|
| IoC Database | 5 | Structure, ClawHavoc C2, webhook.site |
|
|
555
559
|
| Shannon Entropy | 2 | Low entropy, high entropy |
|
|
556
560
|
| Ignore Functionality | 1 | Pattern exclusion |
|
|
557
561
|
| Plugin API | 1 | Plugin loading + custom rule injection |
|
|
558
|
-
|
|
|
559
|
-
|
|
|
560
|
-
|
|
|
562
|
+
| Manifest Validation | 4 | Dangerous bins, broad files, sensitive env, clean negatives |
|
|
563
|
+
| Complexity Metrics | 2 | Deep nesting, clean negatives |
|
|
564
|
+
| Config Impact | 4 | openclaw.json write, exec approval, gateway host, clean negatives |
|
|
565
|
+
| **π PII Exposure Detection** | **8** | **Hardcoded CC/SSN, PII logging, network send, Shadow AI, doc collection, risk amp, clean negatives** |
|
|
566
|
+
| **Plugin Hook Runtime Guard** | **35** | **Blocking in enforce/strict, passthrough in monitor, all 12 threat patterns, blockReason format** |
|
|
567
|
+
|
|
568
|
+
---
|
|
569
|
+
|
|
570
|
+
## Fills OpenClaw's Own Security Gaps
|
|
571
|
+
|
|
572
|
+
OpenClaw's official [`THREAT-MODEL-ATLAS.md`](https://github.com/openclaw/openclaw/blob/main/docs/security/THREAT-MODEL-ATLAS.md) identifies security gaps that guard-scanner directly addresses:
|
|
573
|
+
|
|
574
|
+
| Gap (from ATLAS / Source Code) | OpenClaw Status | guard-scanner |
|
|
575
|
+
|---|---|---|
|
|
576
|
+
| _"Simple regex easily bypassed"_ β ClawHub moderation | β οΈ Basic `FLAG_RULES` | β
129 patterns, 21 categories |
|
|
577
|
+
| _"Does not analyze actual skill code content"_ | β Not implemented | β
Full code + doc + data flow analysis |
|
|
578
|
+
| No SOUL.md / IDENTITY.md integrity verification | β Not implemented | β
Identity hijacking detection (Cat 17) |
|
|
579
|
+
| `skill:before_install` hook | β Not implemented | π Proposed ([Issue #18677](https://github.com/openclaw/openclaw/issues/18677)) |
|
|
580
|
+
| `before_tool_call` blocking reference impl | β No official plugin | β
First reference implementation (plugin.ts) |
|
|
581
|
+
| SARIF / CI integration for skill security | β Not available | β
SARIF 2.1.0 + GitHub Actions |
|
|
582
|
+
| Behavioral analysis beyond VirusTotal | β³ In progress | β
LLM-specific threat patterns (prompt injection, memory poisoning, MCP attacks) |
|
|
583
|
+
|
|
584
|
+
> guard-scanner is **complementary** to OpenClaw's built-in security β not a replacement. OpenClaw handles infrastructure security (SSRF blocking, exec approvals, sandbox, auth). guard-scanner handles **AI-specific threats** that traditional scanning misses.
|
|
561
585
|
|
|
562
586
|
---
|
|
563
587
|
|
|
@@ -578,19 +602,19 @@ guard-scanner's coverage of the [OWASP Top 10 for LLM Applications (2025)](https
|
|
|
578
602
|
| # | Risk | Status | Detection Method |
|
|
579
603
|
|---|------|--------|------------------|
|
|
580
604
|
| LLM01 | Prompt Injection | β οΈ Partial | Regex: Unicode exploits, role override, system tags, base64 instructions |
|
|
581
|
-
| LLM02 |
|
|
605
|
+
| LLM02 | Sensitive Information Disclosure | β οΈ Partial | PII Exposure Detection (v2.1): hardcoded PII, PII logging/network/storage, Shadow AI, PII collection instructions |
|
|
582
606
|
| LLM03 | Training Data Poisoning | β¬ N/A | Out of scope for static analysis |
|
|
583
|
-
| LLM04 | Model Denial of Service | π
|
|
607
|
+
| LLM04 | Model Denial of Service | π v2.2 | Planned: excessive input / infinite loop patterns |
|
|
584
608
|
| LLM05 | Supply Chain Vulnerabilities | β οΈ Partial | IoC database, typosquat detection, dependency chain scan |
|
|
585
|
-
| LLM06 |
|
|
609
|
+
| LLM06 | Insecure Output Handling | β οΈ Partial | PII output detection (console.log, network send, plaintext store) |
|
|
586
610
|
| LLM07 | Insecure Plugin Design | π v1.3 | Planned: unvalidated plugin input patterns |
|
|
587
611
|
| LLM08 | Excessive Agency | π v1.3 | Planned: over-permissioned scope detection |
|
|
588
612
|
| LLM09 | Overreliance | π v1.3 | Planned: unverified output trust patterns |
|
|
589
613
|
| LLM10 | Model Theft | π v1.3 | Planned: model file exfiltration patterns |
|
|
590
614
|
|
|
591
|
-
> **Current coverage:
|
|
615
|
+
> **Current coverage: 5/10 (partial).** LLM02 and LLM06 added in v2.1.0. Full coverage targeted for v3.0. See [ROADMAP.md](ROADMAP.md) for details.
|
|
592
616
|
>
|
|
593
|
-
> **Known limitation:** Regex-based detection can be evaded by AI-generated code obfuscation.
|
|
617
|
+
> **Known limitation:** Regex-based detection can be evaded by AI-generated code obfuscation. v3.0 will introduce AST analysis and ML-based detection to address this structural gap.
|
|
594
618
|
|
|
595
619
|
---
|
|
596
620
|
|
|
@@ -600,7 +624,7 @@ guard-scanner's coverage of the [OWASP Top 10 for LLM Applications (2025)](https
|
|
|
600
624
|
2. Create a feature branch (`git checkout -b feature/new-pattern`)
|
|
601
625
|
3. Add your pattern to `src/patterns.js` with the required fields
|
|
602
626
|
4. Add a test case in `test/fixtures/` and `test/scanner.test.js`
|
|
603
|
-
5. Run `npm test` β all
|
|
627
|
+
5. Run `npm test` β all 99+ tests must pass
|
|
604
628
|
6. Submit a Pull Request
|
|
605
629
|
|
|
606
630
|
### Adding a New Detection Pattern
|
|
@@ -639,19 +663,34 @@ We built one.
|
|
|
639
663
|
|
|
640
664
|
## π Need More? β GuavaSuite
|
|
641
665
|
|
|
642
|
-
guard-scanner catches threats **before** installation
|
|
666
|
+
guard-scanner catches threats **before** installation and **blocks** CRITICAL threats at runtime. **GuavaSuite** unlocks **strict mode** β blocking HIGH + CRITICAL threats, plus exclusive defense-in-depth features.
|
|
667
|
+
|
|
668
|
+
### How to Upgrade
|
|
669
|
+
|
|
670
|
+
```bash
|
|
671
|
+
# 1. Install GuavaSuite
|
|
672
|
+
clawhub install guava-suite
|
|
673
|
+
|
|
674
|
+
# 2. Hold 1M+ $GUAVA on Polygon
|
|
675
|
+
# Token: 0x25cBD481901990bF0ed2ff9c5F3C0d4f743AC7B8
|
|
676
|
+
# Buy on QuickSwap V2: https://quickswap.exchange
|
|
677
|
+
|
|
678
|
+
# 3. Activate with your wallet β get JWT β strict mode enabled
|
|
679
|
+
```
|
|
643
680
|
|
|
644
|
-
|
|
681
|
+
### Feature Comparison
|
|
645
682
|
|
|
646
|
-
| | guard-scanner (
|
|
683
|
+
| | guard-scanner (Free) | GuavaSuite ($GUAVA) |
|
|
647
684
|
|---|---|---|
|
|
648
|
-
| Static scan
|
|
649
|
-
| Runtime
|
|
650
|
-
|
|
|
651
|
-
|
|
|
652
|
-
|
|
|
685
|
+
| Static scan (129 patterns, 21 categories) | β
| β
|
|
|
686
|
+
| Runtime Guard β `enforce` (block CRITICAL) | β
| β
|
|
|
687
|
+
| **Runtime Guard β `strict` (block HIGH + CRITICAL)** | β | β
|
|
|
688
|
+
| **Soul Lock** (SOUL.md integrity + auto-rollback) | β | β
|
|
|
689
|
+
| **Memory Guard** (L1-L5 θ¨ζΆδΏθ·) | β | β
|
|
|
690
|
+
| **On-chain Identity** (SoulRegistry V2 on Polygon) | β | β
|
|
|
691
|
+
| Audit Log (JSONL) | β
| β
|
|
|
653
692
|
|
|
654
|
-
guard-scanner is and always will be **free, open-source, and zero-dependency**.
|
|
693
|
+
guard-scanner is and always will be **free, open-source, and zero-dependency**.
|
|
655
694
|
|
|
656
695
|
---
|
|
657
696
|
|
|
@@ -660,10 +699,10 @@ guard-scanner is and always will be **free, open-source, and zero-dependency**.
|
|
|
660
699
|
| Version | Focus | Key Features |
|
|
661
700
|
|---------|-------|------|
|
|
662
701
|
| v1.1.1 β
| Stability | 56 tests, bug fixes |
|
|
663
|
-
|
|
|
664
|
-
|
|
|
665
|
-
| v2.
|
|
666
|
-
|
|
|
702
|
+
| v2.0.0 β
| **Plugin Hook Runtime Guard** | `block`/`blockReason` API, 3 modes (monitor/enforce/strict), 91 tests |
|
|
703
|
+
| v2.1.0 β
| **PII Exposure + Shadow AI** | 13 PII patterns, OWASP LLM02/06, Shadow AI detection, 3 risk amplifiers, 99 tests |
|
|
704
|
+
| v2.2 | OWASP Full Coverage | LLM04/07/08/09/10, YAML pattern definitions, CONTRIBUTING guide |
|
|
705
|
+
| v3.0 | AST + ML | JavaScript AST analysis, taint tracking, ML-based obfuscation detection, SBOM generation |
|
|
667
706
|
|
|
668
707
|
See [ROADMAP.md](ROADMAP.md) for full details.
|
|
669
708
|
|
|
@@ -172,10 +172,52 @@ function logAudit(entry: Record<string, unknown>): void {
|
|
|
172
172
|
|
|
173
173
|
type GuardMode = "monitor" | "enforce" | "strict";
|
|
174
174
|
|
|
175
|
+
const SUITE_TOKEN_FILE = join(homedir(), ".openclaw", "guava-suite", "token.jwt");
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Check if GuavaSuite JWT exists and hasn't expired.
|
|
179
|
+
* Why: Lightweight check without jsonwebtoken dependency β just decode base64 payload.
|
|
180
|
+
* Full JWT signature verification happens at activation time in activate.js.
|
|
181
|
+
*/
|
|
182
|
+
function isSuiteActive(): boolean {
|
|
183
|
+
try {
|
|
184
|
+
const token = readFileSync(SUITE_TOKEN_FILE, "utf8").trim();
|
|
185
|
+
if (!token) return false;
|
|
186
|
+
|
|
187
|
+
// Decode JWT payload (base64url β JSON)
|
|
188
|
+
const parts = token.split(".");
|
|
189
|
+
if (parts.length !== 3) return false;
|
|
190
|
+
|
|
191
|
+
const payload = JSON.parse(
|
|
192
|
+
Buffer.from(parts[1], "base64url").toString("utf8")
|
|
193
|
+
);
|
|
194
|
+
|
|
195
|
+
// Check expiry
|
|
196
|
+
if (payload.exp && payload.exp * 1000 < Date.now()) return false;
|
|
197
|
+
|
|
198
|
+
// Check scope
|
|
199
|
+
return payload.scope === "suite";
|
|
200
|
+
} catch {
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
175
205
|
function loadMode(): GuardMode {
|
|
206
|
+
// Priority 1: GuavaSuite JWT token β strict
|
|
207
|
+
if (isSuiteActive()) {
|
|
208
|
+
return "strict";
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Priority 2: explicit config in openclaw.json
|
|
176
212
|
try {
|
|
177
213
|
const configPath = join(homedir(), ".openclaw", "openclaw.json");
|
|
178
214
|
const config = JSON.parse(readFileSync(configPath, "utf8"));
|
|
215
|
+
|
|
216
|
+
// Check suiteEnabled flag (set by activate.js)
|
|
217
|
+
if (config?.plugins?.["guard-scanner"]?.suiteEnabled === true) {
|
|
218
|
+
return "strict";
|
|
219
|
+
}
|
|
220
|
+
|
|
179
221
|
const mode = config?.plugins?.["guard-scanner"]?.mode;
|
|
180
222
|
if (mode === "monitor" || mode === "enforce" || mode === "strict") {
|
|
181
223
|
return mode;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "guard-scanner",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "Agent skill security scanner β detect prompt injection, malicious code, credential leaks, and
|
|
3
|
+
"version": "2.1.0",
|
|
4
|
+
"description": "Agent skill security scanner β detect prompt injection, malicious code, credential leaks, PII exposure, Shadow AI, and 21 threat categories in AI agent skills",
|
|
5
5
|
"main": "src/scanner.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"guard-scanner": "src/cli.js"
|
package/src/patterns.js
CHANGED
|
@@ -185,6 +185,28 @@ const PATTERNS = [
|
|
|
185
185
|
{ 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 },
|
|
186
186
|
{ 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 },
|
|
187
187
|
{ 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 },
|
|
188
|
+
|
|
189
|
+
// ββ Category 21: PII Exposure (OWASP LLM02 / LLM06) ββ
|
|
190
|
+
// A. Hardcoded PII β actual PII values in code/config (context-aware to reduce FP)
|
|
191
|
+
{ 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 },
|
|
192
|
+
{ 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 },
|
|
193
|
+
{ 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 },
|
|
194
|
+
{ 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 },
|
|
195
|
+
|
|
196
|
+
// B. PII output/logging β code that outputs or transmits PII-like variables
|
|
197
|
+
{ 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 },
|
|
198
|
+
{ 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 },
|
|
199
|
+
{ 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 },
|
|
200
|
+
|
|
201
|
+
// C. Shadow AI β unauthorized LLM API calls (data leaks to external AI)
|
|
202
|
+
{ 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 },
|
|
203
|
+
{ 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 },
|
|
204
|
+
{ 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 },
|
|
205
|
+
|
|
206
|
+
// D. PII collection instructions in docs (extends LEAK_COLLECT_PII)
|
|
207
|
+
{ 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 },
|
|
208
|
+
{ 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 },
|
|
209
|
+
{ 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 },
|
|
188
210
|
];
|
|
189
211
|
|
|
190
212
|
module.exports = { PATTERNS };
|
package/src/scanner.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* guard-scanner
|
|
3
|
+
* guard-scanner v2.1.0 β Agent Skill Security Scanner π‘οΈ
|
|
4
4
|
*
|
|
5
5
|
* @security-manifest
|
|
6
6
|
* env-read: []
|
|
@@ -31,7 +31,7 @@ const { KNOWN_MALICIOUS } = require('./ioc-db.js');
|
|
|
31
31
|
const { generateHTML } = require('./html-template.js');
|
|
32
32
|
|
|
33
33
|
// ===== CONFIGURATION =====
|
|
34
|
-
const VERSION = '
|
|
34
|
+
const VERSION = '2.1.0';
|
|
35
35
|
|
|
36
36
|
const THRESHOLDS = {
|
|
37
37
|
normal: { suspicious: 30, malicious: 80 },
|
|
@@ -868,6 +868,11 @@ class GuardScanner {
|
|
|
868
868
|
if (cats.has('config-impact') && cats.has('sandbox-validation')) score = Math.max(score, 70);
|
|
869
869
|
if (cats.has('complexity') && (cats.has('malicious-code') || cats.has('obfuscation'))) score = Math.round(score * 1.5);
|
|
870
870
|
|
|
871
|
+
// v2.1 PII exposure amplifiers
|
|
872
|
+
if (cats.has('pii-exposure') && cats.has('exfiltration')) score = Math.round(score * 3);
|
|
873
|
+
if (cats.has('pii-exposure') && (ids.has('SHADOW_AI_OPENAI') || ids.has('SHADOW_AI_ANTHROPIC') || ids.has('SHADOW_AI_GENERIC'))) score = Math.round(score * 2.5);
|
|
874
|
+
if (cats.has('pii-exposure') && cats.has('credential-handling')) score = Math.round(score * 2);
|
|
875
|
+
|
|
871
876
|
return Math.min(100, score);
|
|
872
877
|
}
|
|
873
878
|
|
|
@@ -943,6 +948,7 @@ class GuardScanner {
|
|
|
943
948
|
if (cats.has('sandbox-validation')) skillRecs.push('π SANDBOX: Skill requests dangerous capabilities.');
|
|
944
949
|
if (cats.has('complexity')) skillRecs.push('π§© COMPLEXITY: Excessive code complexity may hide malicious behavior.');
|
|
945
950
|
if (cats.has('config-impact')) skillRecs.push('βοΈ CONFIG IMPACT: Modifies OpenClaw configuration. DO NOT INSTALL.');
|
|
951
|
+
if (cats.has('pii-exposure')) skillRecs.push('π PII EXPOSURE: Handles personally identifiable information. Review data handling.');
|
|
946
952
|
|
|
947
953
|
if (skillRecs.length > 0) recommendations.push({ skill: skillResult.skill, actions: skillRecs });
|
|
948
954
|
}
|