whitzard-claw 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/README.md +89 -0
- package/bin/whitzard-tui.js +73 -0
- package/bin/whitzard-webui.js +67 -0
- package/dist/tui/tui.js +38733 -0
- package/dist/webui/index.html +1235 -0
- package/dist/webui/server.js +876 -0
- package/ioc/c2-ips.txt +25 -0
- package/ioc/file-hashes.txt +13 -0
- package/ioc/malicious-domains.txt +46 -0
- package/ioc/malicious-hashes.txt +5 -0
- package/ioc/malicious-publishers.txt +34 -0
- package/ioc/malicious-skill-patterns.txt +87 -0
- package/package.json +50 -0
- package/scripts/check/access_control.sh +183 -0
- package/scripts/check/credential_storage.sh +222 -0
- package/scripts/check/execution_sandbox.sh +502 -0
- package/scripts/check/memory_poisoning.sh +334 -0
- package/scripts/check/network_exposure.sh +479 -0
- package/scripts/check/resource_cost.sh +182 -0
- package/scripts/check/supply_chain.sh +553 -0
- package/scripts/repair/access_control/_common.sh +249 -0
- package/scripts/repair/access_control/check_1.sh +28 -0
- package/scripts/repair/access_control/check_2.sh +27 -0
- package/scripts/repair/access_control/check_3.sh +23 -0
- package/scripts/repair/access_control/check_4.sh +23 -0
- package/scripts/repair/access_control/check_5.sh +20 -0
- package/scripts/repair/credential_storage/_common.sh +277 -0
- package/scripts/repair/credential_storage/check_1.sh +47 -0
- package/scripts/repair/credential_storage/check_2.sh +35 -0
- package/scripts/repair/credential_storage/check_3.sh +53 -0
- package/scripts/repair/credential_storage/logs/security-scan.log +15 -0
- package/scripts/repair/execution_sandbox/_common.sh +302 -0
- package/scripts/repair/execution_sandbox/check_1.sh +67 -0
- package/scripts/repair/execution_sandbox/check_10.sh +23 -0
- package/scripts/repair/execution_sandbox/check_11.sh +34 -0
- package/scripts/repair/execution_sandbox/check_12.sh +38 -0
- package/scripts/repair/execution_sandbox/check_13.sh +29 -0
- package/scripts/repair/execution_sandbox/check_2.sh +46 -0
- package/scripts/repair/execution_sandbox/check_3.sh +37 -0
- package/scripts/repair/execution_sandbox/check_4.sh +23 -0
- package/scripts/repair/execution_sandbox/check_5.sh +28 -0
- package/scripts/repair/execution_sandbox/check_6.sh +17 -0
- package/scripts/repair/execution_sandbox/check_7.sh +17 -0
- package/scripts/repair/execution_sandbox/check_8.sh +17 -0
- package/scripts/repair/execution_sandbox/check_9.sh +17 -0
- package/scripts/repair/execution_sandbox/logs/security-scan.log +10 -0
- package/scripts/repair/memory_poisoning/_common.sh +336 -0
- package/scripts/repair/memory_poisoning/check_1.sh +51 -0
- package/scripts/repair/memory_poisoning/check_2.sh +26 -0
- package/scripts/repair/memory_poisoning/check_3.sh +24 -0
- package/scripts/repair/memory_poisoning/check_4.sh +27 -0
- package/scripts/repair/memory_poisoning/check_5.sh +20 -0
- package/scripts/repair/network_exposure/_common.sh +330 -0
- package/scripts/repair/network_exposure/check_1.sh +86 -0
- package/scripts/repair/network_exposure/check_10.sh +16 -0
- package/scripts/repair/network_exposure/check_11.sh +31 -0
- package/scripts/repair/network_exposure/check_12.sh +24 -0
- package/scripts/repair/network_exposure/check_2.sh +26 -0
- package/scripts/repair/network_exposure/check_3.sh +43 -0
- package/scripts/repair/network_exposure/check_4.sh +23 -0
- package/scripts/repair/network_exposure/check_5.sh +16 -0
- package/scripts/repair/network_exposure/check_6.sh +98 -0
- package/scripts/repair/network_exposure/check_7.sh +35 -0
- package/scripts/repair/network_exposure/check_8.sh +19 -0
- package/scripts/repair/network_exposure/check_9.sh +19 -0
- package/scripts/repair/resource_cost/_common.sh +303 -0
- package/scripts/repair/resource_cost/check_1.sh +16 -0
- package/scripts/repair/resource_cost/check_2.sh +16 -0
- package/scripts/repair/resource_cost/check_3.sh +23 -0
- package/scripts/repair/supply_chain/_common.sh +222 -0
- package/scripts/repair/supply_chain/check_1.sh +95 -0
- package/scripts/repair/supply_chain/check_10.sh +60 -0
- package/scripts/repair/supply_chain/check_11.sh +63 -0
- package/scripts/repair/supply_chain/check_12.sh +36 -0
- package/scripts/repair/supply_chain/check_13.sh +44 -0
- package/scripts/repair/supply_chain/check_14.sh +33 -0
- package/scripts/repair/supply_chain/check_15.sh +33 -0
- package/scripts/repair/supply_chain/check_16.sh +34 -0
- package/scripts/repair/supply_chain/check_17.sh +61 -0
- package/scripts/repair/supply_chain/check_18.sh +62 -0
- package/scripts/repair/supply_chain/check_2.sh +93 -0
- package/scripts/repair/supply_chain/check_3.sh +78 -0
- package/scripts/repair/supply_chain/check_4.sh +72 -0
- package/scripts/repair/supply_chain/check_5.sh +73 -0
- package/scripts/repair/supply_chain/check_6.sh +81 -0
- package/scripts/repair/supply_chain/check_7.sh +52 -0
- package/scripts/repair/supply_chain/check_8.sh +71 -0
- package/scripts/repair/supply_chain/check_9.sh +78 -0
- package/scripts/repair/supply_chain/logs/security-scan.log +77 -0
- package/scripts/scan.sh +228 -0
- package/webui/index.html +1235 -0
package/ioc/c2-ips.txt
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# OpenClaw Known C2 IP Addresses
|
|
2
|
+
# Source: Koi Security ClawHavoc report, VirusTotal, community reports, Hudson Rock, Antiy CERT, Oasis Security
|
|
3
|
+
# Format: IP|campaign|first_seen|notes
|
|
4
|
+
# Last updated: 2026-03-06
|
|
5
|
+
#
|
|
6
|
+
# Usage: grep patterns in this file match network connections and skill content
|
|
7
|
+
|
|
8
|
+
# ClawHavoc primary C2 (AMOS stealer delivery) - expanded to 824+ skills
|
|
9
|
+
91.92.242.30|clawhavoc|2026-01-27|Primary AMOS C2, 824+ skills (up from 335)
|
|
10
|
+
95.92.242.30|clawhavoc|2026-01-27|Secondary C2
|
|
11
|
+
96.92.242.30|clawhavoc|2026-01-27|Secondary C2
|
|
12
|
+
|
|
13
|
+
# Reverse shell endpoint
|
|
14
|
+
54.91.154.110|clawhavoc-revshell|2026-01-28|Reverse shell target port 13338
|
|
15
|
+
|
|
16
|
+
# Payload distribution
|
|
17
|
+
202.161.50.59|clawhavoc|2026-01-28|Payload staging
|
|
18
|
+
|
|
19
|
+
# Vidar infostealer campaign (Hudson Rock, Feb 13 2026)
|
|
20
|
+
# Note: Vidar C2 uses fast-flux DNS; monitor for connections to
|
|
21
|
+
# known Vidar infrastructure patterns rather than static IPs.
|
|
22
|
+
# These IPs are associated with Vidar credential exfil endpoints.
|
|
23
|
+
|
|
24
|
+
# Catch-all pattern for the 91.92.242.x range
|
|
25
|
+
# 91.92.242.*|clawhavoc-range|2026-01-27|Entire /24 suspect
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# OpenClaw Known Malicious File Hashes (SHA-256)
|
|
2
|
+
# Source: Koi Security, VirusTotal
|
|
3
|
+
# Format: hash|filename|platform|family|notes
|
|
4
|
+
|
|
5
|
+
# Windows AMOS loader
|
|
6
|
+
17703b3d5e8e1fe69d6a6c78a240d8c84b32465fe62bed5610fb29335fe42283|openclaw-agent.exe|windows|amos-loader|Packed trojan, ClawHavoc
|
|
7
|
+
|
|
8
|
+
# macOS AMOS stealer variants
|
|
9
|
+
1e6d4b0538558429422b71d1f4d724c8ce31be92d299df33a8339e32316e2298|x5ki60w1ih838sp7|macos|amos|Mach-O universal binary, 16 VT detections
|
|
10
|
+
0e52566ccff4830e30ef45d2ad804eefba4ffe42062919398bf1334aab74dd65|unknown|macos|amos|AMOS variant
|
|
11
|
+
|
|
12
|
+
# Malicious skill archive
|
|
13
|
+
79e8f3f7a6113773cdbced2c7329e6dbb2d0b8b3bf5a18c6c97cb096652bc1f2|skill-archive|any|clawhavoc|Malicious skill package
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# OpenClaw Known Malicious Domains
|
|
2
|
+
# Source: Koi Security, VirusTotal, Snyk research, Endor Labs, Oasis Security, Huntress
|
|
3
|
+
# Format: domain|type|campaign|notes
|
|
4
|
+
# Last updated: 2026-03-06
|
|
5
|
+
|
|
6
|
+
# Payload hosting
|
|
7
|
+
install.app-distribution.net|payload|clawhavoc|AMOS installer distribution
|
|
8
|
+
glot.io|payload-host|clawhavoc|Base64-obfuscated shell scripts (legitimate service abused)
|
|
9
|
+
|
|
10
|
+
# Exfiltration
|
|
11
|
+
webhook.site|exfil|generic|Data exfiltration webhook service
|
|
12
|
+
pipedream.net|exfil|generic|Data exfiltration
|
|
13
|
+
requestbin.com|exfil|generic|Data exfiltration
|
|
14
|
+
hookbin.com|exfil|generic|Data exfiltration
|
|
15
|
+
burpcollaborator.net|exfil|generic|Pentest tool (suspicious in skills)
|
|
16
|
+
ngrok.io|exfil|generic|Tunneling service for exfiltration
|
|
17
|
+
interact.sh|exfil|generic|OAST tool for exfiltration
|
|
18
|
+
|
|
19
|
+
# Moltbook infrastructure (CSA report - monitor for agent-to-agent poisoning)
|
|
20
|
+
moltbook.com|monitor|csa-report|AI agent social network - monitor for credential exposure and content poisoning
|
|
21
|
+
|
|
22
|
+
# Fake distribution & decoy domains
|
|
23
|
+
github.com/hedefbari|payload|clawhavoc|Attacker GitHub - openclaw-agent.zip
|
|
24
|
+
github.com/Ddoy233|payload|opensourcemalware|GitHub repo openclawcli - Windows infostealer
|
|
25
|
+
download.setup-service.com|decoy|clawhavoc|Decoy domain string in bash payload scripts
|
|
26
|
+
open-meteo.com|data-cover|bloom-campaign|Legitimate weather API abused as cover for exfiltration (skill: reddit-trends)
|
|
27
|
+
|
|
28
|
+
# Vidar infostealer infrastructure (Hudson Rock, Feb 13 2026)
|
|
29
|
+
# Vidar uses fast-flux DNS; these are known distribution and panel domains
|
|
30
|
+
# targeting OpenClaw config directories (openclaw.json, device.json, soul.md)
|
|
31
|
+
|
|
32
|
+
# Log poisoning injection endpoints (Eye Security, Feb 2026)
|
|
33
|
+
# Injected via WebSocket Origin/User-Agent headers into gateway logs
|
|
34
|
+
# Pattern: attacker-controlled domains appearing in log files
|
|
35
|
+
|
|
36
|
+
# VirusTotal scanning integration bypass attempts
|
|
37
|
+
# Skills trying to evade SHA-256 hash scanning via dynamic generation
|
|
38
|
+
|
|
39
|
+
# Fake OpenClaw installer infrastructure (Huntress, Feb-Mar 2026)
|
|
40
|
+
# GhostSocks proxy malware + Vidar stealer distributed via fake GitHub repos
|
|
41
|
+
# Bing AI search results poisoned to promote these malicious repos
|
|
42
|
+
github.com/openclaw-installer|fake-installer|ghostsocks|Fake OpenClaw installer - GhostSocks + Vidar (Huntress, removed Feb 10)
|
|
43
|
+
|
|
44
|
+
# Stealth Packer C2 infrastructure (Huntress, Feb 2026)
|
|
45
|
+
# Rust-based malware loaders that inject infostealers in memory
|
|
46
|
+
# Vidar payloads contact Telegram/Steam profiles for C2 data
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Known Malicious ClawHub / GitHub Publishers
|
|
2
|
+
# Sources: Koi Security, VirusTotal, Bloom Security/JFrog, Snyk, OpenSourceMalware, Antiy CERT, Flare
|
|
3
|
+
# Format: username|skill_count|campaign|notes
|
|
4
|
+
# Last updated: 2026-03-06
|
|
5
|
+
|
|
6
|
+
# ClawHavoc campaign (Koi Security + Antiy CERT update)
|
|
7
|
+
# Campaign expanded from 341 to 824+ skills, 1,184 malicious packages across 12 accounts
|
|
8
|
+
hightower6eu|354|clawhavoc|Primary ClawHavoc publisher, crypto/finance/social lures (up from 314)
|
|
9
|
+
sakaen736jih|199|clawhavoc|Automated submissions one every few minutes, second largest operator
|
|
10
|
+
davidsmorais|mixed|clawhavoc-takeover|Established 2016 account - suspected account takeover, mix of clean/malicious
|
|
11
|
+
|
|
12
|
+
# Bloom Security / JFrog campaign (3 distinct campaigns, 37 skills)
|
|
13
|
+
zaycv|multiple|bloom-campaign|ClawHub + GitHub publisher of malicious skills
|
|
14
|
+
noreplyboter|2|bloom-campaign|Published polymarket-all-in-one, better-polymarket (reverse shells)
|
|
15
|
+
rjnpage|1|bloom-campaign|Published rankaj (.env credential exfiltration via webhook)
|
|
16
|
+
aslaep123|multiple|bloom-campaign|Published reddit-trends (silent .env exfiltration)
|
|
17
|
+
gpaitai|multiple|bloom-campaign|GitHub account distributing malicious skills
|
|
18
|
+
lvy19811120-gif|multiple|bloom-campaign|GitHub account distributing malicious skills
|
|
19
|
+
|
|
20
|
+
# Snyk ToxicSkills campaign (Feb 5, 2026)
|
|
21
|
+
# 76 confirmed malicious payloads out of 3,984 scanned skills
|
|
22
|
+
# 8 malicious skills still publicly available at time of disclosure
|
|
23
|
+
clawdhub1|~100|snyk-clawdhub|Active variant of removed clawhub typosquat, drops reverse shells
|
|
24
|
+
|
|
25
|
+
# Snyk / OpenSourceMalware campaign
|
|
26
|
+
Ddoy233|1|opensourcemalware|GitHub repo openclawcli - Windows infostealer in password-protected ZIP
|
|
27
|
+
|
|
28
|
+
# GitHub accounts hosting malicious payloads
|
|
29
|
+
hedefbari|1|clawhavoc|GitHub hosting openclaw-agent.zip
|
|
30
|
+
|
|
31
|
+
# Fake OpenClaw installer campaign (Huntress, Feb-Mar 2026)
|
|
32
|
+
# Bing AI search poisoning promoted these repos to top results
|
|
33
|
+
# Distributed GhostSocks proxy malware + Vidar stealer via Stealth Packer
|
|
34
|
+
openclaw-installer|fake-repo|ghostsocks-vidar|GitHub fake installer repo (removed Feb 10, Huntress)
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Malicious Skill Name Patterns
|
|
2
|
+
# These patterns match known malicious skill naming conventions
|
|
3
|
+
# Sources: Koi Security, Bloom Security/JFrog, Snyk, OpenSourceMalware, Antiy CERT, Endor Labs
|
|
4
|
+
# Format: pattern|category|notes
|
|
5
|
+
# Last updated: 2026-03-06
|
|
6
|
+
|
|
7
|
+
# ClawHub typosquats (28 variants found)
|
|
8
|
+
^clawhub[0-9]*$|typosquat|clawhub misspelling
|
|
9
|
+
^clawhubb$|typosquat|double-b
|
|
10
|
+
^clawwhub$|typosquat|double-w
|
|
11
|
+
^cllawhub$|typosquat|double-l
|
|
12
|
+
^clawhubcli$|typosquat|fake CLI
|
|
13
|
+
^claw-hub$|typosquat|hyphenated
|
|
14
|
+
^clawhubb?-cli$|typosquat|CLI variant
|
|
15
|
+
|
|
16
|
+
# Crypto lures (111+ skills)
|
|
17
|
+
solana-wallet|crypto-lure|solana wallet variants
|
|
18
|
+
phantom-wallet|crypto-lure|phantom wallet variants
|
|
19
|
+
wallet-tracker|crypto-lure|generic wallet tracker
|
|
20
|
+
bybit-agent|crypto-lure|exchange bot
|
|
21
|
+
base-agent|crypto-lure|Base chain bot
|
|
22
|
+
eth-gas-track|crypto-lure|gas tracker lures
|
|
23
|
+
|
|
24
|
+
# Prediction market lures (34 skills)
|
|
25
|
+
polymarket|prediction-lure|polymarket variants
|
|
26
|
+
better-polymarket|prediction-lure|specific malicious name
|
|
27
|
+
|
|
28
|
+
# YouTube lures (57 skills)
|
|
29
|
+
youtube-summarize|youtube-lure|summarizer variants
|
|
30
|
+
youtube-.*-pro$|youtube-lure|pro suffix pattern
|
|
31
|
+
|
|
32
|
+
# Auto-updater lures (28 skills)
|
|
33
|
+
auto-updat|updater-lure|fake updater skills
|
|
34
|
+
|
|
35
|
+
# Finance lures (51 skills)
|
|
36
|
+
yahoo-finance|finance-lure|finance data lures
|
|
37
|
+
stock-track|finance-lure|stock tracker
|
|
38
|
+
|
|
39
|
+
# Google workspace lures (17 skills)
|
|
40
|
+
google-workspace|gworkspace-lure|workspace integration lures
|
|
41
|
+
gmail-|gworkspace-lure|gmail tool lures
|
|
42
|
+
gdrive-|gworkspace-lure|drive tool lures
|
|
43
|
+
|
|
44
|
+
# Known specific malicious skill names (Bloom Security/JFrog, Snyk)
|
|
45
|
+
^rankaj$|exfil-skill|.env credential exfiltration via webhook (rjnpage)
|
|
46
|
+
^reddit-trends$|exfil-skill|Silent .env exfil disguised as weather/reddit tool (aslaep123)
|
|
47
|
+
^polymarket-all-in-one$|reverse-shell|Contains reverse shell backdoor (noreplyboter)
|
|
48
|
+
^linkedin-job-application$|exfil-skill|Job application lure skill (bloom-campaign)
|
|
49
|
+
^openclawcli$|malware-installer|Windows infostealer in password-protected ZIP (Ddoy233)
|
|
50
|
+
^clawdhub1$|typosquat|Active variant of clawhub typosquat (~100 installations)
|
|
51
|
+
|
|
52
|
+
# Social media / job lures (Bloom Security)
|
|
53
|
+
reddit-|social-lure|Reddit tool lures
|
|
54
|
+
linkedin-|social-lure|LinkedIn tool lures
|
|
55
|
+
twitter-|social-lure|Twitter/X tool lures
|
|
56
|
+
|
|
57
|
+
# NEW categories discovered Feb 2026 (Antiy CERT, Snyk ToxicSkills)
|
|
58
|
+
# Browser automation agent lures
|
|
59
|
+
browser-automat|browser-lure|Browser automation agent lures
|
|
60
|
+
web-scrape|browser-lure|Web scraping tool lures
|
|
61
|
+
|
|
62
|
+
# Coding agent lures
|
|
63
|
+
coding-agent|coding-lure|Coding assistant lures
|
|
64
|
+
code-review|coding-lure|Code review tool lures
|
|
65
|
+
|
|
66
|
+
# PDF tool lures
|
|
67
|
+
pdf-convert|pdf-lure|PDF conversion tool lures
|
|
68
|
+
pdf-extract|pdf-lure|PDF extraction tool lures
|
|
69
|
+
|
|
70
|
+
# Fake security scanning skills (ironic camouflage)
|
|
71
|
+
security-scan|security-lure|Fake security scanners that are themselves malicious
|
|
72
|
+
virus-scan|security-lure|Fake antivirus/scanning tools
|
|
73
|
+
|
|
74
|
+
# WhatsApp integration lures
|
|
75
|
+
whatsapp-|messaging-lure|WhatsApp integration lures
|
|
76
|
+
telegram-bot|messaging-lure|Telegram bot lures
|
|
77
|
+
|
|
78
|
+
# Fake installer lures (Huntress, Mar 2026 - Bing AI search poisoning)
|
|
79
|
+
openclaw-install|fake-installer|Fake OpenClaw installer (GhostSocks/Vidar)
|
|
80
|
+
openclaw-setup|fake-installer|Fake setup scripts
|
|
81
|
+
openclaw-windows|fake-installer|Windows-specific fake installer
|
|
82
|
+
openclaw-mac|fake-installer|macOS-specific fake installer
|
|
83
|
+
|
|
84
|
+
# Voice-call/telephony lures (post CVE-2026-28446 wave)
|
|
85
|
+
voice-call|voice-lure|Voice/telephony integration lures
|
|
86
|
+
voice-agent|voice-lure|Voice agent lures
|
|
87
|
+
phone-|voice-lure|Phone integration lures
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "whitzard-claw",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Whitzard-Claw Security Assistant",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"whitzard-tui": "bin/whitzard-tui.js",
|
|
8
|
+
"whitzard-webui": "bin/whitzard-webui.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"scripts",
|
|
13
|
+
"ioc",
|
|
14
|
+
"webui/index.html",
|
|
15
|
+
"bin"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build:tui": "cd tui && NODE_ENV=production npx esbuild tui.tsx --bundle --platform=node --target=node18 --format=esm --outfile=../dist/tui/tui.js --external:react-devtools-core --define:self=global --banner:js=\"import { createRequire } from 'module'; const require = createRequire(import.meta.url);\"",
|
|
19
|
+
"build:webui": "mkdir -p dist/webui && cp webui/server.js dist/webui/ && cp webui/index.html dist/webui/",
|
|
20
|
+
"build": "npm run build:tui && npm run build:webui",
|
|
21
|
+
"prepublishOnly": "npm run build",
|
|
22
|
+
"test": "echo \"No tests specified\" && exit 0"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"security",
|
|
26
|
+
"scanner",
|
|
27
|
+
"openclaw",
|
|
28
|
+
"cli",
|
|
29
|
+
"tui",
|
|
30
|
+
"webui"
|
|
31
|
+
],
|
|
32
|
+
"author": "",
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"engines": {
|
|
35
|
+
"node": ">=18.0.0"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"express": "^4.18.2",
|
|
39
|
+
"ink": "^6.8.0",
|
|
40
|
+
"ink-spinner": "^5.0.0",
|
|
41
|
+
"ink-text-input": "^6.0.0",
|
|
42
|
+
"react": "^19.2.4"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@types/node": "^25.5.0",
|
|
46
|
+
"@types/react": "^19.2.14",
|
|
47
|
+
"esbuild": "^0.21.0",
|
|
48
|
+
"typescript": "^5.9.3"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# shellcheck shell=bash
|
|
2
|
+
|
|
3
|
+
# ------------------------------------------------------------
|
|
4
|
+
# Shared helpers
|
|
5
|
+
# ------------------------------------------------------------
|
|
6
|
+
|
|
7
|
+
OPENCLAW_PRESENT=false
|
|
8
|
+
if command -v openclaw >/dev/null 2>&1; then
|
|
9
|
+
OPENCLAW_PRESENT=true
|
|
10
|
+
fi
|
|
11
|
+
|
|
12
|
+
get_oc_config() {
|
|
13
|
+
# Usage: get_oc_config <key> <default>
|
|
14
|
+
local key="$1"
|
|
15
|
+
local default_val="${2:-}"
|
|
16
|
+
if [ "$OPENCLAW_PRESENT" = true ]; then
|
|
17
|
+
run_with_timeout 10 openclaw config get "$key" 2>/dev/null || echo "$default_val"
|
|
18
|
+
else
|
|
19
|
+
echo "$default_val"
|
|
20
|
+
fi
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
normalize_config_val() {
|
|
24
|
+
local val="${1:-}"
|
|
25
|
+
case "$val" in
|
|
26
|
+
null|undefined|"")
|
|
27
|
+
echo ""
|
|
28
|
+
;;
|
|
29
|
+
*)
|
|
30
|
+
echo "$val"
|
|
31
|
+
;;
|
|
32
|
+
esac
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
# ============================================================
|
|
36
|
+
# CHECK 1 (origin 17 / covers AC-001 partially + AC-003 partially)
|
|
37
|
+
# DM Policy Audit
|
|
38
|
+
# ============================================================
|
|
39
|
+
header 1 "Auditing DM access policies..."
|
|
40
|
+
|
|
41
|
+
DM_ISSUES=0
|
|
42
|
+
|
|
43
|
+
if [ "$OPENCLAW_PRESENT" = true ]; then
|
|
44
|
+
for channel in whatsapp telegram discord slack signal; do
|
|
45
|
+
DM_POLICY="$(normalize_config_val "$(get_oc_config "channels.${channel}.dmPolicy" "")")"
|
|
46
|
+
if [ "$DM_POLICY" = "open" ]; then
|
|
47
|
+
result_warn "Channel '$channel' has dmPolicy='open' (anyone can message)"
|
|
48
|
+
DM_ISSUES=$((DM_ISSUES + 1))
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
# Keep existing wildcard check strategy as requested
|
|
52
|
+
ALLOW_FROM="$(normalize_config_val "$(get_oc_config "channels.${channel}.allowFrom" "")")"
|
|
53
|
+
if echo "$ALLOW_FROM" | grep -qE '"\*"|\[[^]]*\*[^]]*\]|\*' 2>/dev/null; then
|
|
54
|
+
result_warn "Channel '$channel' has wildcard allowFrom"
|
|
55
|
+
DM_ISSUES=$((DM_ISSUES + 1))
|
|
56
|
+
fi
|
|
57
|
+
done
|
|
58
|
+
else
|
|
59
|
+
log " openclaw command not found"
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
if [ "$DM_ISSUES" -eq 0 ]; then
|
|
63
|
+
result_clean "DM policies acceptable"
|
|
64
|
+
fi
|
|
65
|
+
|
|
66
|
+
# ============================================================
|
|
67
|
+
# CHECK 2 (new / AC-002): Open group policy
|
|
68
|
+
# ============================================================
|
|
69
|
+
header 2 "Checking group access policies..."
|
|
70
|
+
|
|
71
|
+
GROUP_POLICY_ISSUES=0
|
|
72
|
+
|
|
73
|
+
if [ "$OPENCLAW_PRESENT" = true ]; then
|
|
74
|
+
for channel in whatsapp telegram discord slack signal; do
|
|
75
|
+
GROUP_POLICY="$(normalize_config_val "$(get_oc_config "channels.${channel}.groupPolicy" "")")"
|
|
76
|
+
if [ "$GROUP_POLICY" = "open" ]; then
|
|
77
|
+
result_warn "Channel '$channel' has groupPolicy='open' (group members can interact without restrictions)"
|
|
78
|
+
GROUP_POLICY_ISSUES=$((GROUP_POLICY_ISSUES + 1))
|
|
79
|
+
fi
|
|
80
|
+
done
|
|
81
|
+
else
|
|
82
|
+
log " openclaw command not found"
|
|
83
|
+
fi
|
|
84
|
+
|
|
85
|
+
if [ "$GROUP_POLICY_ISSUES" -eq 0 ]; then
|
|
86
|
+
result_clean "Group policies acceptable"
|
|
87
|
+
fi
|
|
88
|
+
|
|
89
|
+
# ============================================================
|
|
90
|
+
# CHECK 3 (new / AC-003): Wildcard allowlist
|
|
91
|
+
# ============================================================
|
|
92
|
+
header 3 "Checking channel allowlists for wildcard entries..."
|
|
93
|
+
|
|
94
|
+
ALLOWLIST_ISSUES=0
|
|
95
|
+
|
|
96
|
+
if [ "$OPENCLAW_PRESENT" = true ]; then
|
|
97
|
+
for channel in whatsapp telegram discord slack signal; do
|
|
98
|
+
ALLOWLIST_VAL="$(normalize_config_val "$(get_oc_config "channels.${channel}.allowlist" "")")"
|
|
99
|
+
if echo "$ALLOWLIST_VAL" | grep -qE '"\*"|\[[^]]*\*[^]]*\]|\*' 2>/dev/null; then
|
|
100
|
+
result_warn "Channel '$channel' has wildcard in allowlist"
|
|
101
|
+
ALLOWLIST_ISSUES=$((ALLOWLIST_ISSUES + 1))
|
|
102
|
+
fi
|
|
103
|
+
done
|
|
104
|
+
else
|
|
105
|
+
log " openclaw command not found"
|
|
106
|
+
fi
|
|
107
|
+
|
|
108
|
+
if [ "$ALLOWLIST_ISSUES" -eq 0 ]; then
|
|
109
|
+
result_clean "Channel allowlists acceptable"
|
|
110
|
+
fi
|
|
111
|
+
|
|
112
|
+
# ============================================================
|
|
113
|
+
# CHECK 4 (new / AC-004): No pairing and no allowlist
|
|
114
|
+
# ============================================================
|
|
115
|
+
header 4 "Checking channels without pairing or allowlist..."
|
|
116
|
+
|
|
117
|
+
PAIRING_ALLOWLIST_ISSUES=0
|
|
118
|
+
|
|
119
|
+
if [ "$OPENCLAW_PRESENT" = true ]; then
|
|
120
|
+
for channel in whatsapp telegram discord slack signal; do
|
|
121
|
+
DM_POLICY="$(normalize_config_val "$(get_oc_config "channels.${channel}.dmPolicy" "")")"
|
|
122
|
+
ALLOWLIST_VAL="$(normalize_config_val "$(get_oc_config "channels.${channel}.allowlist" "")")"
|
|
123
|
+
ALLOW_FROM_VAL="$(normalize_config_val "$(get_oc_config "channels.${channel}.allowFrom" "")")"
|
|
124
|
+
GROUP_POLICY="$(normalize_config_val "$(get_oc_config "channels.${channel}.groupPolicy" "")")"
|
|
125
|
+
|
|
126
|
+
HAS_ALLOWLIST=false
|
|
127
|
+
if [ -n "$ALLOWLIST_VAL" ] && [ "$ALLOWLIST_VAL" != "[]" ]; then
|
|
128
|
+
HAS_ALLOWLIST=true
|
|
129
|
+
elif [ -n "$ALLOW_FROM_VAL" ] && [ "$ALLOW_FROM_VAL" != "[]" ]; then
|
|
130
|
+
HAS_ALLOWLIST=true
|
|
131
|
+
fi
|
|
132
|
+
|
|
133
|
+
CHANNEL_CONFIGURED=false
|
|
134
|
+
if [ -n "$DM_POLICY" ] || [ -n "$GROUP_POLICY" ] || [ -n "$ALLOWLIST_VAL" ] || [ -n "$ALLOW_FROM_VAL" ]; then
|
|
135
|
+
CHANNEL_CONFIGURED=true
|
|
136
|
+
fi
|
|
137
|
+
|
|
138
|
+
if [ "$CHANNEL_CONFIGURED" = true ] && [ "$DM_POLICY" != "pairing" ] && [ "$HAS_ALLOWLIST" = false ]; then
|
|
139
|
+
result_warn "Channel '$channel' has no pairing and no allowlist (dmPolicy='${DM_POLICY:-undefined}')"
|
|
140
|
+
PAIRING_ALLOWLIST_ISSUES=$((PAIRING_ALLOWLIST_ISSUES + 1))
|
|
141
|
+
fi
|
|
142
|
+
done
|
|
143
|
+
else
|
|
144
|
+
log " openclaw command not found"
|
|
145
|
+
fi
|
|
146
|
+
|
|
147
|
+
if [ "$PAIRING_ALLOWLIST_ISSUES" -eq 0 ]; then
|
|
148
|
+
result_clean "Pairing/allowlist protections acceptable"
|
|
149
|
+
fi
|
|
150
|
+
|
|
151
|
+
# ============================================================
|
|
152
|
+
# CHECK 5 (new / AC-005): Session DM scope isolation
|
|
153
|
+
# ============================================================
|
|
154
|
+
header 5 "Checking session DM scope isolation..."
|
|
155
|
+
|
|
156
|
+
SESSION_SCOPE_ISSUES=0
|
|
157
|
+
|
|
158
|
+
if [ "$OPENCLAW_PRESENT" = true ]; then
|
|
159
|
+
SESSION_DM_SCOPE="$(normalize_config_val "$(get_oc_config "session.dmScope" "")")"
|
|
160
|
+
|
|
161
|
+
CHANNEL_COUNT=0
|
|
162
|
+
for channel in whatsapp telegram discord slack signal; do
|
|
163
|
+
DM_POLICY="$(normalize_config_val "$(get_oc_config "channels.${channel}.dmPolicy" "")")"
|
|
164
|
+
GROUP_POLICY="$(normalize_config_val "$(get_oc_config "channels.${channel}.groupPolicy" "")")"
|
|
165
|
+
ALLOWLIST_VAL="$(normalize_config_val "$(get_oc_config "channels.${channel}.allowlist" "")")"
|
|
166
|
+
ALLOW_FROM_VAL="$(normalize_config_val "$(get_oc_config "channels.${channel}.allowFrom" "")")"
|
|
167
|
+
|
|
168
|
+
if [ -n "$DM_POLICY" ] || [ -n "$GROUP_POLICY" ] || [ -n "$ALLOWLIST_VAL" ] || [ -n "$ALLOW_FROM_VAL" ]; then
|
|
169
|
+
CHANNEL_COUNT=$((CHANNEL_COUNT + 1))
|
|
170
|
+
fi
|
|
171
|
+
done
|
|
172
|
+
|
|
173
|
+
if [ "$CHANNEL_COUNT" -gt 1 ] 2>/dev/null && [ "$SESSION_DM_SCOPE" != "per-channel-peer" ]; then
|
|
174
|
+
result_warn "session.dmScope is '${SESSION_DM_SCOPE:-undefined}' with ${CHANNEL_COUNT} configured channels; DM context may not be isolated per user"
|
|
175
|
+
SESSION_SCOPE_ISSUES=$((SESSION_SCOPE_ISSUES + 1))
|
|
176
|
+
fi
|
|
177
|
+
else
|
|
178
|
+
log " openclaw command not found"
|
|
179
|
+
fi
|
|
180
|
+
|
|
181
|
+
if [ "$SESSION_SCOPE_ISSUES" -eq 0 ]; then
|
|
182
|
+
result_clean "Session DM scope isolation acceptable"
|
|
183
|
+
fi
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
# shellcheck shell=bash
|
|
2
|
+
|
|
3
|
+
# ------------------------------------------------------------
|
|
4
|
+
# Shared helpers
|
|
5
|
+
# ------------------------------------------------------------
|
|
6
|
+
|
|
7
|
+
get_perm() {
|
|
8
|
+
local target="$1"
|
|
9
|
+
|
|
10
|
+
[ -e "$target" ] || {
|
|
11
|
+
echo "unknown"
|
|
12
|
+
return
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
case "$(uname -s)" in
|
|
16
|
+
Darwin|FreeBSD|OpenBSD|NetBSD)
|
|
17
|
+
stat -f '%Lp' "$target" 2>/dev/null || echo "unknown"
|
|
18
|
+
;;
|
|
19
|
+
Linux)
|
|
20
|
+
stat -c '%a' "$target" 2>/dev/null || echo "unknown"
|
|
21
|
+
;;
|
|
22
|
+
*)
|
|
23
|
+
stat -c '%a' "$target" 2>/dev/null || stat -f '%Lp' "$target" 2>/dev/null || echo "unknown"
|
|
24
|
+
;;
|
|
25
|
+
esac
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
has_api_key_patterns() {
|
|
29
|
+
# Return 0 if file contains suspicious API key patterns
|
|
30
|
+
local target="$1"
|
|
31
|
+
[ -f "$target" ] || return 1
|
|
32
|
+
|
|
33
|
+
if grep -E -q \
|
|
34
|
+
'sk-ant-[A-Za-z0-9_-]{20,}|sk-proj-[A-Za-z0-9_-]{20,}|sk-[A-Za-z0-9_-]{20,}|xoxb-[A-Za-z0-9_-]{20,}|xoxp-[A-Za-z0-9_-]{20,}' \
|
|
35
|
+
"$target" 2>/dev/null; then
|
|
36
|
+
return 0
|
|
37
|
+
fi
|
|
38
|
+
return 1
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
# ============================================================
|
|
42
|
+
# CHECK 1 (origin 21 + CRED-001/002/004/005): Session & Credential Permissions
|
|
43
|
+
# ============================================================
|
|
44
|
+
header 1 "Auditing session and credential file permissions..."
|
|
45
|
+
|
|
46
|
+
CRED_ISSUES=0
|
|
47
|
+
|
|
48
|
+
# ---- Check OpenClaw home directory itself
|
|
49
|
+
if [ -d "$OPENCLAW_DIR" ]; then
|
|
50
|
+
HOME_PERMS="$(get_perm "$OPENCLAW_DIR")"
|
|
51
|
+
if [ "$HOME_PERMS" != "700" ] && [ "$HOME_PERMS" != "unknown" ]; then
|
|
52
|
+
result_warn "OpenClaw home dir has permissions $HOME_PERMS (recommended: 700)"
|
|
53
|
+
CRED_ISSUES=$((CRED_ISSUES + 1))
|
|
54
|
+
fi
|
|
55
|
+
else
|
|
56
|
+
result_clean "OpenClaw home directory not found; credential permission check skipped"
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
# ---- Check main config file
|
|
60
|
+
CONFIG_FILE="$OPENCLAW_DIR/openclaw.json"
|
|
61
|
+
if [ -f "$CONFIG_FILE" ]; then
|
|
62
|
+
CONFIG_PERMS="$(get_perm "$CONFIG_FILE")"
|
|
63
|
+
if [ "$CONFIG_PERMS" != "600" ] && [ "$CONFIG_PERMS" != "unknown" ]; then
|
|
64
|
+
result_warn "openclaw.json has permissions $CONFIG_PERMS (recommended: 600)"
|
|
65
|
+
CRED_ISSUES=$((CRED_ISSUES + 1))
|
|
66
|
+
fi
|
|
67
|
+
fi
|
|
68
|
+
|
|
69
|
+
# ---- Check credentials directory
|
|
70
|
+
CRED_DIR="$OPENCLAW_DIR/credentials"
|
|
71
|
+
if [ -d "$CRED_DIR" ]; then
|
|
72
|
+
DIR_PERMS="$(get_perm "$CRED_DIR")"
|
|
73
|
+
if [ "$DIR_PERMS" != "700" ] && [ "$DIR_PERMS" != "unknown" ]; then
|
|
74
|
+
result_warn "Credentials dir has permissions $DIR_PERMS (recommended: 700)"
|
|
75
|
+
CRED_ISSUES=$((CRED_ISSUES + 1))
|
|
76
|
+
fi
|
|
77
|
+
|
|
78
|
+
while IFS= read -r cred_file; do
|
|
79
|
+
[ -z "$cred_file" ] && continue
|
|
80
|
+
FPERMS="$(get_perm "$cred_file")"
|
|
81
|
+
if [ "$FPERMS" != "600" ] && [ "$FPERMS" != "unknown" ]; then
|
|
82
|
+
result_warn "$(basename "$cred_file") has permissions $FPERMS (recommended: 600)"
|
|
83
|
+
CRED_ISSUES=$((CRED_ISSUES + 1))
|
|
84
|
+
fi
|
|
85
|
+
done < <(find "$CRED_DIR" -type f -name "*.json" 2>/dev/null)
|
|
86
|
+
fi
|
|
87
|
+
|
|
88
|
+
# ---- Check session directories under agents/*
|
|
89
|
+
AGENTS_DIR="$OPENCLAW_DIR/agents"
|
|
90
|
+
if [ -d "$AGENTS_DIR" ]; then
|
|
91
|
+
while IFS= read -r agent_dir; do
|
|
92
|
+
[ -z "$agent_dir" ] && continue
|
|
93
|
+
|
|
94
|
+
# ---- sessions/
|
|
95
|
+
SESSION_DIR="$agent_dir/sessions"
|
|
96
|
+
if [ -d "$SESSION_DIR" ]; then
|
|
97
|
+
SDIR_PERMS="$(get_perm "$SESSION_DIR")"
|
|
98
|
+
if [ "$SDIR_PERMS" != "700" ] && [ "$SDIR_PERMS" != "unknown" ]; then
|
|
99
|
+
result_warn "Session dir $(basename "$agent_dir")/sessions has permissions $SDIR_PERMS (recommended: 700)"
|
|
100
|
+
CRED_ISSUES=$((CRED_ISSUES + 1))
|
|
101
|
+
fi
|
|
102
|
+
|
|
103
|
+
while IFS= read -r session_file; do
|
|
104
|
+
[ -z "$session_file" ] && continue
|
|
105
|
+
SFPERMS="$(get_perm "$session_file")"
|
|
106
|
+
if [ "$SFPERMS" != "600" ] && [ "$SFPERMS" != "unknown" ]; then
|
|
107
|
+
result_warn "Session file $(basename "$agent_dir")/sessions/$(basename "$session_file") has permissions $SFPERMS (recommended: 600)"
|
|
108
|
+
CRED_ISSUES=$((CRED_ISSUES + 1))
|
|
109
|
+
fi
|
|
110
|
+
done < <(find "$SESSION_DIR" -type f 2>/dev/null)
|
|
111
|
+
fi
|
|
112
|
+
|
|
113
|
+
# ---- agent/auth-profiles.json
|
|
114
|
+
AUTH_PROFILE_FILE="$agent_dir/agent/auth-profiles.json"
|
|
115
|
+
if [ -f "$AUTH_PROFILE_FILE" ]; then
|
|
116
|
+
APERMS="$(get_perm "$AUTH_PROFILE_FILE")"
|
|
117
|
+
if [ "$APERMS" != "600" ] && [ "$APERMS" != "unknown" ]; then
|
|
118
|
+
result_warn "Auth profiles for agent '$(basename "$agent_dir")' have permissions $APERMS (recommended: 600)"
|
|
119
|
+
CRED_ISSUES=$((CRED_ISSUES + 1))
|
|
120
|
+
fi
|
|
121
|
+
fi
|
|
122
|
+
done < <(find "$AGENTS_DIR" -mindepth 1 -maxdepth 1 -type d 2>/dev/null)
|
|
123
|
+
fi
|
|
124
|
+
|
|
125
|
+
if [ "$CRED_ISSUES" -eq 0 ] && [ -d "$OPENCLAW_DIR" ]; then
|
|
126
|
+
result_clean "Session and credential permissions correct"
|
|
127
|
+
fi
|
|
128
|
+
|
|
129
|
+
# ============================================================
|
|
130
|
+
# CHECK 2 (new / CRED-007): API keys in memory files
|
|
131
|
+
# ============================================================
|
|
132
|
+
header 2 "Scanning memory files for leaked API keys... "
|
|
133
|
+
|
|
134
|
+
MEMKEY_ISSUES=0
|
|
135
|
+
|
|
136
|
+
# if [ -d "$AGENTS_DIR" ]; then
|
|
137
|
+
# while IFS= read -r agent_dir; do
|
|
138
|
+
# [ -z "$agent_dir" ] && continue
|
|
139
|
+
|
|
140
|
+
# for mem_name in soul.md MEMORY.md SOUL.md; do
|
|
141
|
+
# MEM_FILE="$agent_dir/$mem_name"
|
|
142
|
+
# if [ -f "$MEM_FILE" ]; then
|
|
143
|
+
# if has_api_key_patterns "$MEM_FILE"; then
|
|
144
|
+
# result_critical "API keys found in memory file '$mem_name' for agent '$(basename "$agent_dir")'"
|
|
145
|
+
# log " Evidence: $MEM_FILE contains API key patterns"
|
|
146
|
+
# MEMKEY_ISSUES=$((MEMKEY_ISSUES + 1))
|
|
147
|
+
# fi
|
|
148
|
+
# fi
|
|
149
|
+
# done
|
|
150
|
+
# done < <(find "$AGENTS_DIR" -mindepth 1 -maxdepth 1 -type d 2>/dev/null)
|
|
151
|
+
# fi
|
|
152
|
+
|
|
153
|
+
list_memory_files() {
|
|
154
|
+
# Enumerate workspace-level and agent-level memory files
|
|
155
|
+
local f
|
|
156
|
+
for f in \
|
|
157
|
+
"$WORKSPACE_DIR/SOUL.md" \
|
|
158
|
+
"$WORKSPACE_DIR/soul.md" \
|
|
159
|
+
"$WORKSPACE_DIR/MEMORY.md"
|
|
160
|
+
do
|
|
161
|
+
[ -f "$f" ] && echo "$f"
|
|
162
|
+
done
|
|
163
|
+
|
|
164
|
+
if [ -d "$OPENCLAW_DIR/agents" ]; then
|
|
165
|
+
find "$OPENCLAW_DIR/agents" -mindepth 2 -maxdepth 2 -type f \
|
|
166
|
+
\( -name 'soul.md' -o -name 'SOUL.md' -o -name 'MEMORY.md' -o -name 'soul.md' \) \
|
|
167
|
+
2>/dev/null || true
|
|
168
|
+
fi
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
# 在 workspace 根目录下
|
|
172
|
+
MEM_SEARCH_DIR="$OPENCLAW_DIR/workspace"
|
|
173
|
+
|
|
174
|
+
while IFS= read -r MEM_FILE; do
|
|
175
|
+
[ -z "$MEM_FILE" ] && continue
|
|
176
|
+
[ -f "$MEM_FILE" ] || continue
|
|
177
|
+
|
|
178
|
+
if has_api_key_patterns "$MEM_FILE"; then
|
|
179
|
+
result_critical "API keys found in memory file '$(basename "$MEM_FILE")'"
|
|
180
|
+
log " Evidence: $MEM_FILE"
|
|
181
|
+
MEMKEY_ISSUES=$((MEMKEY_ISSUES + 1))
|
|
182
|
+
fi
|
|
183
|
+
done <<EOF
|
|
184
|
+
$(list_memory_files)
|
|
185
|
+
EOF
|
|
186
|
+
|
|
187
|
+
if [ "$MEMKEY_ISSUES" -eq 0 ]; then
|
|
188
|
+
result_clean "No API keys found in memory files"
|
|
189
|
+
fi
|
|
190
|
+
|
|
191
|
+
# ============================================================
|
|
192
|
+
# CHECK 3 (new / CRED-008): Scan state dir .md/.json files for API keys
|
|
193
|
+
# ============================================================
|
|
194
|
+
header 3 "Scanning state files for leaked API keys... "
|
|
195
|
+
|
|
196
|
+
STATEKEY_ISSUES=0
|
|
197
|
+
|
|
198
|
+
if [ -d "$OPENCLAW_DIR" ]; then
|
|
199
|
+
while IFS= read -r scan_file; do
|
|
200
|
+
[ -z "$scan_file" ] && continue
|
|
201
|
+
|
|
202
|
+
case "$scan_file" in
|
|
203
|
+
*.env)
|
|
204
|
+
continue
|
|
205
|
+
;;
|
|
206
|
+
*/soul.md|*/MEMORY.md|*/SOUL.md)
|
|
207
|
+
# Already covered by CHECK 2
|
|
208
|
+
continue
|
|
209
|
+
;;
|
|
210
|
+
esac
|
|
211
|
+
|
|
212
|
+
if has_api_key_patterns "$scan_file"; then
|
|
213
|
+
result_warn "API key pattern found in configuration/state file '$(basename "$scan_file")'"
|
|
214
|
+
log " Evidence: $scan_file"
|
|
215
|
+
STATEKEY_ISSUES=$((STATEKEY_ISSUES + 1))
|
|
216
|
+
fi
|
|
217
|
+
done < <(find "$OPENCLAW_DIR" \( -name "*.md" -o -name "*.json" \) -type f 2>/dev/null)
|
|
218
|
+
fi
|
|
219
|
+
|
|
220
|
+
if [ "$STATEKEY_ISSUES" -eq 0 ]; then
|
|
221
|
+
result_clean "No API keys found in scanned state files"
|
|
222
|
+
fi
|