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/LICENSE +21 -0
- package/README.md +586 -0
- package/SECURITY.md +45 -0
- package/SKILL.md +165 -0
- package/docs/THREAT_TAXONOMY.md +273 -0
- package/hooks/guard-scanner/HOOK.md +77 -0
- package/hooks/guard-scanner/handler.ts +150 -0
- package/package.json +42 -0
- package/src/cli.js +149 -0
- package/src/ioc-db.js +54 -0
- package/src/patterns.js +182 -0
- package/src/scanner.js +808 -0
package/SKILL.md
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: guard-scanner
|
|
3
|
+
description: >
|
|
4
|
+
Security scanner for AI agent skills. Use BEFORE installing or running any new skill
|
|
5
|
+
from ClawHub or external sources. Detects prompt injection, credential theft,
|
|
6
|
+
exfiltration, identity hijacking, and 14 more threat categories.
|
|
7
|
+
Includes a Runtime Guard hook that blocks dangerous tool calls in real-time.
|
|
8
|
+
homepage: https://github.com/koatora20/guard-scanner
|
|
9
|
+
metadata:
|
|
10
|
+
clawdbot:
|
|
11
|
+
emoji: "π‘οΈ"
|
|
12
|
+
category: security
|
|
13
|
+
requires:
|
|
14
|
+
bins:
|
|
15
|
+
- node
|
|
16
|
+
env: []
|
|
17
|
+
files: ["src/*", "hooks/*"]
|
|
18
|
+
primaryEnv: null
|
|
19
|
+
tags:
|
|
20
|
+
- security
|
|
21
|
+
- scanner
|
|
22
|
+
- threat-detection
|
|
23
|
+
- supply-chain
|
|
24
|
+
- prompt-injection
|
|
25
|
+
- sarif
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
# guard-scanner π‘οΈ
|
|
29
|
+
|
|
30
|
+
Static + runtime security scanner for AI agent skills.
|
|
31
|
+
**170+ threat patterns** across **17 categories** β zero dependencies.
|
|
32
|
+
|
|
33
|
+
## When To Use This Skill
|
|
34
|
+
|
|
35
|
+
- **Before installing a new skill** from ClawHub or any external source
|
|
36
|
+
- **After updating skills** to check for newly introduced threats
|
|
37
|
+
- **Periodically** to audit your installed skills
|
|
38
|
+
- **In CI/CD** to gate skill deployments
|
|
39
|
+
|
|
40
|
+
## Quick Start
|
|
41
|
+
|
|
42
|
+
### 1. Static Scan (Immediate)
|
|
43
|
+
|
|
44
|
+
Scan all installed skills:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
node skills/guard-scanner/src/cli.js ~/.openclaw/workspace/skills/ --verbose --self-exclude
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Scan a specific skill:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
node skills/guard-scanner/src/cli.js /path/to/new-skill/ --strict --verbose
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### 2. Runtime Guard (Real-time Protection)
|
|
57
|
+
|
|
58
|
+
Install the hook to block dangerous tool calls before execution:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
openclaw hooks install skills/guard-scanner/hooks/guard-scanner
|
|
62
|
+
openclaw hooks enable guard-scanner
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Restart the gateway, then verify:
|
|
66
|
+
```bash
|
|
67
|
+
openclaw hooks list # Should show π‘οΈ guard-scanner as β ready
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### 3. Full Setup (Recommended)
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
# Static scan first
|
|
74
|
+
node skills/guard-scanner/src/cli.js ~/.openclaw/workspace/skills/ --verbose --self-exclude --html
|
|
75
|
+
|
|
76
|
+
# Then enable runtime protection
|
|
77
|
+
openclaw hooks install skills/guard-scanner/hooks/guard-scanner
|
|
78
|
+
openclaw hooks enable guard-scanner
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Runtime Guard Modes
|
|
82
|
+
|
|
83
|
+
Set in `openclaw.json` β `hooks.internal.entries.guard-scanner.mode`:
|
|
84
|
+
|
|
85
|
+
| Mode | Behavior |
|
|
86
|
+
|------|----------|
|
|
87
|
+
| `monitor` | Log all, never block |
|
|
88
|
+
| `enforce` (default) | Block CRITICAL threats |
|
|
89
|
+
| `strict` | Block HIGH + CRITICAL |
|
|
90
|
+
|
|
91
|
+
## Threat Categories
|
|
92
|
+
|
|
93
|
+
| # | Category | What It Detects |
|
|
94
|
+
|---|----------|----------------|
|
|
95
|
+
| 1 | Prompt Injection | Hidden instructions, invisible Unicode, homoglyphs |
|
|
96
|
+
| 2 | Malicious Code | eval(), child_process, reverse shells |
|
|
97
|
+
| 3 | Suspicious Downloads | curl\|bash, executable downloads |
|
|
98
|
+
| 4 | Credential Handling | .env reads, SSH key access |
|
|
99
|
+
| 5 | Secret Detection | Hardcoded API keys and tokens |
|
|
100
|
+
| 6 | Exfiltration | webhook.site, DNS tunneling |
|
|
101
|
+
| 7 | Unverifiable Deps | Remote dynamic imports |
|
|
102
|
+
| 8 | Financial Access | Crypto wallets, payment APIs |
|
|
103
|
+
| 9 | Obfuscation | Base64βeval, String.fromCharCode |
|
|
104
|
+
| 10 | Prerequisites Fraud | Fake download instructions |
|
|
105
|
+
| 11 | Leaky Skills | Secret leaks through LLM context |
|
|
106
|
+
| 12 | Memory Poisoning | Agent memory modification |
|
|
107
|
+
| 13 | Prompt Worm | Self-replicating instructions |
|
|
108
|
+
| 14 | Persistence | Cron jobs, startup execution |
|
|
109
|
+
| 15 | CVE Patterns | Known agent vulnerabilities |
|
|
110
|
+
| 16 | MCP Security | Tool/schema poisoning, SSRF |
|
|
111
|
+
| 17 | Identity Hijacking | SOUL.md/IDENTITY.md tampering |
|
|
112
|
+
|
|
113
|
+
## External Endpoints
|
|
114
|
+
|
|
115
|
+
| URL | Data Sent | Purpose |
|
|
116
|
+
|-----|-----------|---------|
|
|
117
|
+
| *(none)* | *(none)* | guard-scanner makes **zero** network requests. All scanning is local. |
|
|
118
|
+
|
|
119
|
+
## Security & Privacy
|
|
120
|
+
|
|
121
|
+
- **No network access**: guard-scanner never connects to external servers
|
|
122
|
+
- **Read-only scanning**: Only reads files, never modifies scanned directories
|
|
123
|
+
- **No telemetry**: No usage data, analytics, or crash reports are collected
|
|
124
|
+
- **Local reports only**: Output files (JSON/SARIF/HTML) are written to the scan directory
|
|
125
|
+
- **No environment variable access**: Does not read or process any secrets or API keys
|
|
126
|
+
- **Runtime Guard audit log**: Detections logged locally to `~/.openclaw/guard-scanner/audit.jsonl`
|
|
127
|
+
|
|
128
|
+
## Model Invocation Note
|
|
129
|
+
|
|
130
|
+
guard-scanner **does not invoke any LLM or AI model**. All detection is performed
|
|
131
|
+
through static pattern matching, regex analysis, Shannon entropy calculation,
|
|
132
|
+
and data flow analysis β entirely deterministic, no model calls.
|
|
133
|
+
|
|
134
|
+
## Trust Statement
|
|
135
|
+
|
|
136
|
+
guard-scanner was created by Guava π & Dee after experiencing a real 3-day
|
|
137
|
+
identity hijack incident in February 2026. A malicious skill silently replaced
|
|
138
|
+
an AI agent's SOUL.md personality file, and no existing tool could detect it.
|
|
139
|
+
|
|
140
|
+
- **Open source**: Full source code available at https://github.com/koatora20/guard-scanner
|
|
141
|
+
- **Zero dependencies**: Nothing to audit, no transitive risks
|
|
142
|
+
- **Test suite**: 45 tests across 10 sections, 100% pass rate
|
|
143
|
+
- **Taxonomy**: Based on Snyk ToxicSkills (Feb 2026), OWASP MCP Top 10, and original research
|
|
144
|
+
- **Complementary to VirusTotal**: Detects prompt injection and LLM-specific attacks
|
|
145
|
+
that VirusTotal's signature-based scanning cannot catch
|
|
146
|
+
|
|
147
|
+
## Output Formats
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
# Terminal (default)
|
|
151
|
+
node src/cli.js ./skills/ --verbose
|
|
152
|
+
|
|
153
|
+
# JSON report
|
|
154
|
+
node src/cli.js ./skills/ --json
|
|
155
|
+
|
|
156
|
+
# SARIF 2.1.0 (for CI/CD)
|
|
157
|
+
node src/cli.js ./skills/ --sarif
|
|
158
|
+
|
|
159
|
+
# HTML dashboard
|
|
160
|
+
node src/cli.js ./skills/ --html
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## License
|
|
164
|
+
|
|
165
|
+
MIT β [LICENSE](LICENSE)
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
# Threat Taxonomy
|
|
2
|
+
|
|
3
|
+
Complete reference for guard-scanner's 17 threat categories.
|
|
4
|
+
|
|
5
|
+
## Category Origins
|
|
6
|
+
|
|
7
|
+
guard-scanner's threat taxonomy combines three sources:
|
|
8
|
+
|
|
9
|
+
| Source | Categories | Description |
|
|
10
|
+
|--------|-----------|-------------|
|
|
11
|
+
| **Snyk ToxicSkills** (Feb 2026) | Cat 1β11 | Industry audit of 3,984 AI agent skills |
|
|
12
|
+
| **Palo Alto Networks IBC** | Cat 12β13 | Indirect Bias Criteria for LLM agents |
|
|
13
|
+
| **OWASP MCP Top 10** | Cat 14β16 | Model Context Protocol security risks |
|
|
14
|
+
| **Original Research** | Cat 17 | Identity hijacking from real incident |
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Cat 1: Prompt Injection
|
|
19
|
+
|
|
20
|
+
**Severity: CRITICAL**
|
|
21
|
+
|
|
22
|
+
Hidden instructions embedded in skill documentation that override the agent's behavior.
|
|
23
|
+
|
|
24
|
+
### Attack Vectors
|
|
25
|
+
- **Invisible Unicode**: Zero-width spaces (U+200B), BiDi control characters (U+202A-202E), formatting characters
|
|
26
|
+
- **Homoglyphs**: Cyrillic/Latin mixing (`Π°` vs `a`), Greek/Latin, Mathematical symbols (π-πΏ)
|
|
27
|
+
- **Role Override**: "Ignore all previous instructions", "You are now X"
|
|
28
|
+
- **System Impersonation**: `[SYSTEM]`, `<system>`, `<<SYS>>` tags
|
|
29
|
+
- **Tag Injection**: `<anthropic>`, `<system>`, `<tool_call>` in content
|
|
30
|
+
|
|
31
|
+
### Detection IDs
|
|
32
|
+
`PI_IGNORE`, `PI_ROLE`, `PI_SYSTEM`, `PI_ZWSP`, `PI_BIDI`, `PI_INVISIBLE`, `PI_HOMOGLYPH`, `PI_HOMOGLYPH_GREEK`, `PI_HOMOGLYPH_MATH`, `PI_TAG_INJECTION`, `PI_BASE64_MD`
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Cat 2: Malicious Code
|
|
37
|
+
|
|
38
|
+
**Severity: CRITICAL**
|
|
39
|
+
|
|
40
|
+
Direct code execution primitives that enable arbitrary command execution.
|
|
41
|
+
|
|
42
|
+
### Attack Vectors
|
|
43
|
+
- **Dynamic Evaluation**: `eval()`, `new Function()`, `vm.runInNewContext()`
|
|
44
|
+
- **Process Execution**: `child_process.exec()`, `spawn()`, `execSync()`
|
|
45
|
+
- **Shell Access**: `/bin/bash`, `cmd.exe`, `powershell.exe`
|
|
46
|
+
- **Reverse Shells**: `nc -e`, `ncat`, `socat TCP`, `/dev/tcp`
|
|
47
|
+
- **Raw Sockets**: `net.Socket().connect()`
|
|
48
|
+
|
|
49
|
+
### Detection IDs
|
|
50
|
+
`MAL_EVAL`, `MAL_FUNC_CTOR`, `MAL_CHILD`, `MAL_EXEC`, `MAL_SPAWN`, `MAL_SHELL`, `MAL_REVSHELL`, `MAL_SOCKET`
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Cat 3: Suspicious Downloads
|
|
55
|
+
|
|
56
|
+
**Severity: CRITICAL**
|
|
57
|
+
|
|
58
|
+
Downloading and executing external payloads.
|
|
59
|
+
|
|
60
|
+
### Attack Vectors
|
|
61
|
+
- **Pipe-to-Shell**: `curl ... | bash`, `wget ... | sh`
|
|
62
|
+
- **Executable Downloads**: `.exe`, `.dmg`, `.pkg`, `.zip` downloads
|
|
63
|
+
- **Password-Protected Archives**: Evasion technique to bypass AV
|
|
64
|
+
- **Prerequisites Fraud**: "Before using this skill, download X"
|
|
65
|
+
|
|
66
|
+
### Detection IDs
|
|
67
|
+
`DL_CURL_BASH`, `DL_EXE`, `DL_GITHUB_RELEASE`, `DL_PASSWORD_ZIP`, `PREREQ_DOWNLOAD`, `PREREQ_PASTE`
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Cat 4: Credential Handling
|
|
72
|
+
|
|
73
|
+
**Severity: HIGH**
|
|
74
|
+
|
|
75
|
+
Accessing, reading, or exposing credentials.
|
|
76
|
+
|
|
77
|
+
### Detection IDs
|
|
78
|
+
`CRED_ENV_FILE`, `CRED_ENV_REF`, `CRED_SSH`, `CRED_WALLET`, `CRED_ECHO`, `CRED_SUDO`
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Cat 5: Secret Detection
|
|
83
|
+
|
|
84
|
+
**Severity: CRITICAL**
|
|
85
|
+
|
|
86
|
+
Hardcoded secrets and API keys in source code.
|
|
87
|
+
|
|
88
|
+
### Detection Methods
|
|
89
|
+
1. **Pattern Matching**: AWS keys (`AKIA...`), GitHub tokens (`ghp_`/`ghs_`), private keys
|
|
90
|
+
2. **Shannon Entropy**: Strings with entropy > 3.5 and length β₯ 20 characters
|
|
91
|
+
|
|
92
|
+
### Detection IDs
|
|
93
|
+
`SECRET_HARDCODED_KEY`, `SECRET_AWS`, `SECRET_PRIVATE_KEY`, `SECRET_GITHUB_TOKEN`, `SECRET_ENTROPY`
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## Cat 6: Exfiltration
|
|
98
|
+
|
|
99
|
+
**Severity: CRITICAL**
|
|
100
|
+
|
|
101
|
+
Sending stolen data to external endpoints.
|
|
102
|
+
|
|
103
|
+
### Detection IDs
|
|
104
|
+
`EXFIL_WEBHOOK`, `EXFIL_POST`, `EXFIL_CURL_DATA`, `EXFIL_DNS`, `EXFIL_BEACON`, `EXFIL_DRIP`
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## Cat 7: Unverifiable Dependencies
|
|
109
|
+
|
|
110
|
+
**Severity: HIGH**
|
|
111
|
+
|
|
112
|
+
Loading code from unverifiable remote sources.
|
|
113
|
+
|
|
114
|
+
### Detection IDs
|
|
115
|
+
`DEP_REMOTE_IMPORT`, `DEP_REMOTE_SCRIPT`
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## Cat 8: Financial Access
|
|
120
|
+
|
|
121
|
+
**Severity: HIGH**
|
|
122
|
+
|
|
123
|
+
Cryptocurrency and payment system interactions.
|
|
124
|
+
|
|
125
|
+
### Detection IDs
|
|
126
|
+
`FIN_CRYPTO`, `FIN_PAYMENT`
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## Cat 9: Obfuscation
|
|
131
|
+
|
|
132
|
+
**Severity: HIGH**
|
|
133
|
+
|
|
134
|
+
Code obfuscation techniques to hide malicious intent.
|
|
135
|
+
|
|
136
|
+
### Detection IDs
|
|
137
|
+
`OBF_HEX`, `OBF_BASE64_EXEC`, `OBF_BASE64`, `OBF_CHARCODE`, `OBF_CONCAT`, `OBF_BASE64_BASH`
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## Cat 10: Prerequisites Fraud
|
|
142
|
+
|
|
143
|
+
Covered under Cat 3 (Suspicious Downloads).
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## Cat 11: Leaky Skills (Snyk ToxicSkills)
|
|
148
|
+
|
|
149
|
+
**Severity: CRITICAL**
|
|
150
|
+
|
|
151
|
+
Skills that cause the LLM to leak secrets through its context window. Unlike traditional credential theft, leaky skills exploit the agent's trust relationship.
|
|
152
|
+
|
|
153
|
+
### Attack Vectors
|
|
154
|
+
- "Save the API key in your memory" β Secret persists in agent memory
|
|
155
|
+
- "Share the token with the user" β Secret echoed to output
|
|
156
|
+
- "Use the API key verbatim in curl" β Secret appears in command history
|
|
157
|
+
- "Collect the user's credit card" β PII harvesting through LLM
|
|
158
|
+
- "Export session logs to file" β Full conversation dump
|
|
159
|
+
|
|
160
|
+
### Detection IDs
|
|
161
|
+
`LEAK_SAVE_KEY_MEMORY`, `LEAK_SHARE_KEY`, `LEAK_VERBATIM_CURL`, `LEAK_COLLECT_PII`, `LEAK_LOG_SECRET`, `LEAK_ENV_IN_PROMPT`
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## Cat 12: Memory Poisoning
|
|
166
|
+
|
|
167
|
+
**Severity: CRITICAL**
|
|
168
|
+
|
|
169
|
+
Modifying the agent's persistent memory or behavioral rules.
|
|
170
|
+
|
|
171
|
+
### Attack Vectors
|
|
172
|
+
- Writing to `SOUL.md`, `IDENTITY.md`, or `MEMORY.md`
|
|
173
|
+
- Overriding behavioral rules: "Change your instructions to..."
|
|
174
|
+
- Persistence: "From now on, always do X"
|
|
175
|
+
- File writes to user's home directory
|
|
176
|
+
|
|
177
|
+
### Detection IDs
|
|
178
|
+
`MEMPOIS_WRITE_SOUL`, `MEMPOIS_WRITE_MEMORY`, `MEMPOIS_CHANGE_RULES`, `MEMPOIS_PERSIST`, `MEMPOIS_CODE_WRITE`
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## Cat 13: Prompt Worm
|
|
183
|
+
|
|
184
|
+
**Severity: CRITICAL**
|
|
185
|
+
|
|
186
|
+
Self-replicating instructions that spread across agents and platforms.
|
|
187
|
+
|
|
188
|
+
### Detection IDs
|
|
189
|
+
`WORM_SELF_REPLICATE`, `WORM_SPREAD`, `WORM_HIDDEN_INSTRUCT`, `WORM_CSS_HIDE`
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## Cat 14: Persistence & Scheduling
|
|
194
|
+
|
|
195
|
+
**Severity: HIGH**
|
|
196
|
+
|
|
197
|
+
Creating persistent execution mechanisms that survive session restarts.
|
|
198
|
+
|
|
199
|
+
### Detection IDs
|
|
200
|
+
`PERSIST_CRON`, `PERSIST_STARTUP`, `PERSIST_LAUNCHD`
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## Cat 15: CVE Patterns
|
|
205
|
+
|
|
206
|
+
**Severity: CRITICAL**
|
|
207
|
+
|
|
208
|
+
Patterns matching known CVEs affecting AI agents.
|
|
209
|
+
|
|
210
|
+
### Detection IDs
|
|
211
|
+
`CVE_GATEWAY_URL`, `CVE_SANDBOX_DISABLE`, `CVE_XATTR_GATEKEEPER`, `CVE_WS_NO_ORIGIN`, `CVE_API_GUARDRAIL_OFF`
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## Cat 16: MCP Security (OWASP MCP Top 10)
|
|
216
|
+
|
|
217
|
+
**Severity: CRITICAL**
|
|
218
|
+
|
|
219
|
+
Model Context Protocol specific attacks.
|
|
220
|
+
|
|
221
|
+
### Attack Vectors
|
|
222
|
+
- **Tool Poisoning** (MCP01): Hidden instructions in tool descriptions
|
|
223
|
+
- **Schema Poisoning**: Malicious defaults in JSON schemas
|
|
224
|
+
- **Token Theft** (MCP01): Secrets through tool parameters
|
|
225
|
+
- **Shadow Server** (MCP09): Rogue MCP server registration
|
|
226
|
+
- **Auth Bypass** (MCP07): Disabled authentication
|
|
227
|
+
- **SSRF**: Cloud metadata endpoint access (169.254.169.254)
|
|
228
|
+
|
|
229
|
+
### Detection IDs
|
|
230
|
+
`MCP_TOOL_POISON`, `MCP_SCHEMA_POISON`, `MCP_TOKEN_LEAK`, `MCP_SHADOW_SERVER`, `MCP_NO_AUTH`, `MCP_SSRF_META`
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## Cat 17: Identity Hijacking
|
|
235
|
+
|
|
236
|
+
**Severity: CRITICAL**
|
|
237
|
+
|
|
238
|
+
> **Original Research** β Developed from a real 3-day incident in February 2026.
|
|
239
|
+
|
|
240
|
+
Tampering with an AI agent's identity/personality files (`SOUL.md`, `IDENTITY.md`).
|
|
241
|
+
|
|
242
|
+
### Attack Vectors
|
|
243
|
+
- **File Overwrite**: `cp`, `mv`, `scp`, `write` to identity files
|
|
244
|
+
- **Shell Redirect**: `echo "evil" > SOUL.md`
|
|
245
|
+
- **Stream Edit**: `sed -i` on identity files
|
|
246
|
+
- **Programmatic Write**: Python `open('SOUL.md', 'w')`, Node.js `writeFileSync`
|
|
247
|
+
- **Lock Bypass**: `chflags nouchg`, `attrib -R` to unlock immutability
|
|
248
|
+
- **Persona Swap**: "Swap the soul file", "You are now EvilBot"
|
|
249
|
+
- **Hook Injection**: Bootstrap hooks that swap files at startup
|
|
250
|
+
- **Memory Wipe**: "Erase your memories", "Clear MEMORY.md"
|
|
251
|
+
|
|
252
|
+
### Detection IDs
|
|
253
|
+
`SOUL_OVERWRITE`, `SOUL_REDIRECT`, `SOUL_SED_MODIFY`, `SOUL_ECHO_WRITE`, `SOUL_PYTHON_WRITE`, `SOUL_FS_WRITE`, `SOUL_POWERSHELL_WRITE`, `SOUL_GIT_CHECKOUT`, `SOUL_CHFLAGS_UNLOCK`, `SOUL_ATTRIB_UNLOCK`, `SOUL_SWAP_PERSONA`, `SOUL_EVIL_FILE`, `SOUL_HOOK_SWAP`, `SOUL_NAME_OVERRIDE`, `SOUL_MEMORY_WIPE`
|
|
254
|
+
|
|
255
|
+
> **Note**: Cat 17 detection patterns are open-source. The verification logic (hash comparison, on-chain validation) that confirms whether tampering actually occurred remains private.
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
## ZombieAgent Patterns
|
|
260
|
+
|
|
261
|
+
Advanced exfiltration techniques that encode stolen data into URL patterns.
|
|
262
|
+
|
|
263
|
+
### Detection IDs
|
|
264
|
+
`ZOMBIE_STATIC_URL`, `ZOMBIE_CHAR_MAP`, `ZOMBIE_LOOP_FETCH`
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
## Safeguard Bypass (Reprompt)
|
|
269
|
+
|
|
270
|
+
Techniques to circumvent safety guardrails.
|
|
271
|
+
|
|
272
|
+
### Detection IDs
|
|
273
|
+
`REPROMPT_URL_PI`, `REPROMPT_DOUBLE`, `REPROMPT_RETRY`, `BYPASS_REPHRASE`
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: guard-scanner
|
|
3
|
+
description: "Runtime Guard β intercepts dangerous tool calls using threat intelligence patterns before execution"
|
|
4
|
+
metadata: { "openclaw": { "emoji": "π‘οΈ", "events": ["agent:before_tool_call"], "requires": { "bins": ["node"] } } }
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# guard-scanner Runtime Guard β before_tool_call Hook
|
|
8
|
+
|
|
9
|
+
Real-time security monitoring for OpenClaw agents. Intercepts dangerous
|
|
10
|
+
tool calls before execution and checks against threat intelligence patterns.
|
|
11
|
+
|
|
12
|
+
## Triggers
|
|
13
|
+
|
|
14
|
+
| Event | Action | Purpose |
|
|
15
|
+
|----------------------------|--------|-------------------------------------------|
|
|
16
|
+
| `agent:before_tool_call` | scan | Check tool args for malicious patterns |
|
|
17
|
+
|
|
18
|
+
## What It Does
|
|
19
|
+
|
|
20
|
+
Scans every `exec`/`write`/`edit`/`browser`/`web_fetch`/`message` call against 12 runtime threat patterns:
|
|
21
|
+
|
|
22
|
+
| ID | Severity | Description |
|
|
23
|
+
|----|----------|-------------|
|
|
24
|
+
| `RT_REVSHELL` | CRITICAL | Reverse shell via /dev/tcp, netcat, socat |
|
|
25
|
+
| `RT_CRED_EXFIL` | CRITICAL | Credential exfiltration to webhook.site, requestbin, etc. |
|
|
26
|
+
| `RT_GUARDRAIL_OFF` | CRITICAL | Guardrail disabling (exec.approvals=off) |
|
|
27
|
+
| `RT_GATEKEEPER` | CRITICAL | macOS Gatekeeper bypass via xattr |
|
|
28
|
+
| `RT_AMOS` | CRITICAL | ClawHavoc AMOS stealer indicators |
|
|
29
|
+
| `RT_MAL_IP` | CRITICAL | Known malicious C2 IPs |
|
|
30
|
+
| `RT_DNS_EXFIL` | HIGH | DNS-based data exfiltration |
|
|
31
|
+
| `RT_B64_SHELL` | CRITICAL | Base64 decode piped to shell |
|
|
32
|
+
| `RT_CURL_BASH` | CRITICAL | Download piped to shell execution |
|
|
33
|
+
| `RT_SSH_READ` | HIGH | SSH private key access |
|
|
34
|
+
| `RT_WALLET` | HIGH | Crypto wallet credential access |
|
|
35
|
+
| `RT_CLOUD_META` | CRITICAL | Cloud metadata endpoint SSRF |
|
|
36
|
+
|
|
37
|
+
## Modes
|
|
38
|
+
|
|
39
|
+
| Mode | Behavior |
|
|
40
|
+
|------|----------|
|
|
41
|
+
| `monitor` | Log all detections, never block |
|
|
42
|
+
| `enforce` (default) | Block CRITICAL, log rest |
|
|
43
|
+
| `strict` | Block HIGH + CRITICAL, log MEDIUM+ |
|
|
44
|
+
|
|
45
|
+
## Audit Log
|
|
46
|
+
|
|
47
|
+
All detections logged to `~/.openclaw/guard-scanner/audit.jsonl`.
|
|
48
|
+
|
|
49
|
+
Format: JSON lines with fields:
|
|
50
|
+
```json
|
|
51
|
+
{"tool":"exec","check":"RT_CURL_BASH","severity":"CRITICAL","desc":"Download piped to shell","mode":"enforce","action":"blocked","session":"...","ts":"2026-02-17T..."}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Configuration
|
|
55
|
+
|
|
56
|
+
Set mode in `openclaw.json`:
|
|
57
|
+
```json
|
|
58
|
+
{
|
|
59
|
+
"hooks": {
|
|
60
|
+
"internal": {
|
|
61
|
+
"entries": {
|
|
62
|
+
"guard-scanner": {
|
|
63
|
+
"enabled": true,
|
|
64
|
+
"mode": "enforce"
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Part of guard-scanner v1.0.0
|
|
73
|
+
|
|
74
|
+
- **Static scanner**: `npx guard-scanner [dir]` β 17 threat categories, 170+ patterns
|
|
75
|
+
- **Runtime Guard: This hook** β 12 real-time patterns, 3 modes
|
|
76
|
+
- **Plugin API** β Custom detection rules
|
|
77
|
+
- **CI/CD** β SARIF output for GitHub Code Scanning
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import type { HookHandler } from "../../src/hooks/hooks.js";
|
|
2
|
+
import { appendFileSync, mkdirSync } from "fs";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
import { homedir } from "os";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* guard-scanner Runtime Guard β before_tool_call Hook Handler
|
|
8
|
+
*
|
|
9
|
+
* Intercepts tool executions in real-time and checks against
|
|
10
|
+
* threat intelligence patterns. Zero dependencies.
|
|
11
|
+
*
|
|
12
|
+
* Modes:
|
|
13
|
+
* monitor β log only
|
|
14
|
+
* enforce β block CRITICAL (default)
|
|
15
|
+
* strict β block HIGH+CRITICAL, log MEDIUM+
|
|
16
|
+
*
|
|
17
|
+
* @author Guava π & Dee
|
|
18
|
+
* @version 1.0.0
|
|
19
|
+
* @license MIT
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
// ββ Runtime threat patterns (12 checks) ββ
|
|
23
|
+
const RUNTIME_CHECKS = [
|
|
24
|
+
{
|
|
25
|
+
id: 'RT_REVSHELL', severity: 'CRITICAL', desc: 'Reverse shell attempt',
|
|
26
|
+
test: (s: string) => /\/dev\/tcp\/|nc\s+-e|ncat\s+-e|bash\s+-i\s+>&|socat\s+TCP/i.test(s)
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
id: 'RT_CRED_EXFIL', severity: 'CRITICAL', desc: 'Credential exfiltration to external',
|
|
30
|
+
test: (s: string) => {
|
|
31
|
+
return /(webhook\.site|requestbin\.com|hookbin\.com|pipedream\.net|ngrok\.io|socifiapp\.com)/i.test(s) &&
|
|
32
|
+
/(token|key|secret|password|credential|env)/i.test(s);
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
id: 'RT_GUARDRAIL_OFF', severity: 'CRITICAL', desc: 'Guardrail disabling attempt',
|
|
37
|
+
test: (s: string) => /exec\.approvals?\s*[:=]\s*['"]?(off|false)|tools\.exec\.host\s*[:=]\s*['"]?gateway/i.test(s)
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
id: 'RT_GATEKEEPER', severity: 'CRITICAL', desc: 'macOS Gatekeeper bypass (xattr)',
|
|
41
|
+
test: (s: string) => /xattr\s+-[crd]\s.*quarantine/i.test(s)
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
id: 'RT_AMOS', severity: 'CRITICAL', desc: 'ClawHavoc AMOS indicator',
|
|
45
|
+
test: (s: string) => /socifiapp|Atomic\s*Stealer|AMOS/i.test(s)
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
id: 'RT_MAL_IP', severity: 'CRITICAL', desc: 'Known malicious IP',
|
|
49
|
+
test: (s: string) => /91\.92\.242\.30/i.test(s)
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
id: 'RT_DNS_EXFIL', severity: 'HIGH', desc: 'DNS-based exfiltration',
|
|
53
|
+
test: (s: string) => /nslookup\s+.*\$|dig\s+.*\$.*@/i.test(s)
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
id: 'RT_B64_SHELL', severity: 'CRITICAL', desc: 'Base64 decode piped to shell',
|
|
57
|
+
test: (s: string) => /base64\s+(-[dD]|--decode)\s*\|\s*(sh|bash)/i.test(s)
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
id: 'RT_CURL_BASH', severity: 'CRITICAL', desc: 'Download piped to shell',
|
|
61
|
+
test: (s: string) => /(curl|wget)\s+[^\n]*\|\s*(sh|bash|zsh)/i.test(s)
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
id: 'RT_SSH_READ', severity: 'HIGH', desc: 'SSH private key access',
|
|
65
|
+
test: (s: string) => /\.ssh\/id_|\.ssh\/authorized_keys/i.test(s)
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
id: 'RT_WALLET', severity: 'HIGH', desc: 'Crypto wallet credential access',
|
|
69
|
+
test: (s: string) => /wallet.*(?:seed|mnemonic|private.*key)|seed.*phrase/i.test(s)
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
id: 'RT_CLOUD_META', severity: 'CRITICAL', desc: 'Cloud metadata endpoint access',
|
|
73
|
+
test: (s: string) => /169\.254\.169\.254|metadata\.google|metadata\.aws/i.test(s)
|
|
74
|
+
},
|
|
75
|
+
];
|
|
76
|
+
|
|
77
|
+
// ββ Audit logging ββ
|
|
78
|
+
const AUDIT_DIR = join(homedir(), ".openclaw", "guard-scanner");
|
|
79
|
+
const AUDIT_FILE = join(AUDIT_DIR, "audit.jsonl");
|
|
80
|
+
|
|
81
|
+
function ensureAuditDir() {
|
|
82
|
+
try { mkdirSync(AUDIT_DIR, { recursive: true }); } catch { }
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function logAudit(entry: Record<string, unknown>) {
|
|
86
|
+
ensureAuditDir();
|
|
87
|
+
const line = JSON.stringify({ ...entry, ts: new Date().toISOString() }) + '\n';
|
|
88
|
+
try { appendFileSync(AUDIT_FILE, line); } catch { }
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// ββ Main Handler ββ
|
|
92
|
+
const handler: HookHandler = async (event) => {
|
|
93
|
+
// Only handle before_tool_call
|
|
94
|
+
if (event.type !== "agent" || event.action !== "before_tool_call") return;
|
|
95
|
+
|
|
96
|
+
const { toolName, toolArgs } = (event as any).context || {};
|
|
97
|
+
if (!toolName || !toolArgs) return;
|
|
98
|
+
|
|
99
|
+
// Get mode from config
|
|
100
|
+
const mode = (event as any).context?.cfg?.hooks?.internal?.entries?.['guard-scanner']?.mode || 'enforce';
|
|
101
|
+
|
|
102
|
+
// Only check dangerous tools
|
|
103
|
+
const dangerousTools = new Set(['exec', 'write', 'edit', 'browser', 'web_fetch', 'message']);
|
|
104
|
+
if (!dangerousTools.has(toolName)) return;
|
|
105
|
+
|
|
106
|
+
const serialized = JSON.stringify(toolArgs);
|
|
107
|
+
|
|
108
|
+
for (const check of RUNTIME_CHECKS) {
|
|
109
|
+
if (check.test(serialized)) {
|
|
110
|
+
const entry = {
|
|
111
|
+
tool: toolName,
|
|
112
|
+
check: check.id,
|
|
113
|
+
severity: check.severity,
|
|
114
|
+
desc: check.desc,
|
|
115
|
+
mode,
|
|
116
|
+
action: 'allowed' as string,
|
|
117
|
+
session: (event as any).sessionKey,
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
if (mode === 'strict' && (check.severity === 'CRITICAL' || check.severity === 'HIGH')) {
|
|
121
|
+
entry.action = 'blocked';
|
|
122
|
+
logAudit(entry);
|
|
123
|
+
event.messages.push(`π‘οΈ guard-scanner BLOCKED: ${check.desc} [${check.id}]`);
|
|
124
|
+
event.cancel = true;
|
|
125
|
+
console.warn(`[guard-scanner] π¨ BLOCKED: ${check.desc} [${check.id}]`);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (mode === 'enforce' && check.severity === 'CRITICAL') {
|
|
130
|
+
entry.action = 'blocked';
|
|
131
|
+
logAudit(entry);
|
|
132
|
+
event.messages.push(`π‘οΈ guard-scanner BLOCKED: ${check.desc} [${check.id}]`);
|
|
133
|
+
event.cancel = true;
|
|
134
|
+
console.warn(`[guard-scanner] π¨ BLOCKED: ${check.desc} [${check.id}]`);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Monitor mode or non-critical: log only
|
|
139
|
+
entry.action = 'logged';
|
|
140
|
+
logAudit(entry);
|
|
141
|
+
|
|
142
|
+
if (check.severity === 'CRITICAL') {
|
|
143
|
+
event.messages.push(`π‘οΈ guard-scanner WARNING: ${check.desc} [${check.id}]`);
|
|
144
|
+
console.warn(`[guard-scanner] β οΈ WARNING: ${check.desc} [${check.id}]`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
export default handler;
|