mohuclaw 1.0.1
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 +64 -0
- package/bin/mohu-tui.js +73 -0
- package/bin/mohu-webui.js +67 -0
- package/dist/tui/tui.js +38733 -0
- package/dist/webui/index.html +1551 -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 +46 -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 +1551 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# CHECK 4 (origin 35): Exec safeBins Validation Bypass
|
|
3
|
+
# Usage: ./check_4.sh
|
|
4
|
+
|
|
5
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
6
|
+
source "$SCRIPT_DIR/_common.sh"
|
|
7
|
+
|
|
8
|
+
# Guidance
|
|
9
|
+
cat <<EOF
|
|
10
|
+
RECOMMENDED ACTIONS:
|
|
11
|
+
1. Update OpenClaw immediately:
|
|
12
|
+
openclaw update
|
|
13
|
+
|
|
14
|
+
2. Audit safeBins configuration:
|
|
15
|
+
openclaw config get tools.exec.safeBins
|
|
16
|
+
|
|
17
|
+
3. Consider removing 'sort' from safeBins until patched:
|
|
18
|
+
openclaw config set tools.exec.safeBins <updated-list>
|
|
19
|
+
|
|
20
|
+
EOF
|
|
21
|
+
|
|
22
|
+
exit 0
|
|
23
|
+
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# CHECK 5 (origin 37): PATH Hijacking / Command Hijacking
|
|
3
|
+
# Usage: ./check_5.sh
|
|
4
|
+
|
|
5
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
6
|
+
source "$SCRIPT_DIR/_common.sh"
|
|
7
|
+
|
|
8
|
+
# Guidance
|
|
9
|
+
cat <<EOF
|
|
10
|
+
RECOMMENDED ACTIONS:
|
|
11
|
+
1. Review and remove suspicious executables flagged above (check logs for exact paths)
|
|
12
|
+
|
|
13
|
+
2. Verify which binary is actually being used:
|
|
14
|
+
which -a node python3 bash curl git openclaw
|
|
15
|
+
|
|
16
|
+
3. Check for planted executables in workspace:
|
|
17
|
+
find $WORKSPACE_DIR -maxdepth 3 -type f -executable -name "node" -o -name "python3" -o -name "bash" -o -name "curl" -o -name "git"
|
|
18
|
+
|
|
19
|
+
4. Ensure user-writable directories appear AFTER system directories in PATH:
|
|
20
|
+
echo \$PATH
|
|
21
|
+
# /usr/local/bin and /usr/bin should come before ~/bin etc.
|
|
22
|
+
|
|
23
|
+
5. Remove or investigate any non-whitelisted writable directories from PATH:
|
|
24
|
+
export PATH="/usr/local/bin:/usr/bin:/bin"
|
|
25
|
+
|
|
26
|
+
EOF
|
|
27
|
+
|
|
28
|
+
exit 0
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# CHECK 6 (origin 43): Exec-Approvals Shell Expansion Bypass
|
|
3
|
+
# Usage: ./check_6.sh
|
|
4
|
+
|
|
5
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
6
|
+
source "$SCRIPT_DIR/_common.sh"
|
|
7
|
+
|
|
8
|
+
# Guidance
|
|
9
|
+
cat <<EOF
|
|
10
|
+
RECOMMENDED ACTIONS:
|
|
11
|
+
1. Update OpenClaw immediately:
|
|
12
|
+
openclaw update
|
|
13
|
+
|
|
14
|
+
EOF
|
|
15
|
+
|
|
16
|
+
exit 0
|
|
17
|
+
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# CHECK 7 (origin 44): Approval Field Injection / Exec Gating Bypass
|
|
3
|
+
# Usage: ./check_7.sh
|
|
4
|
+
|
|
5
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
6
|
+
source "$SCRIPT_DIR/_common.sh"
|
|
7
|
+
|
|
8
|
+
# Guidance
|
|
9
|
+
cat <<EOF
|
|
10
|
+
RECOMMENDED ACTIONS:
|
|
11
|
+
1. Update OpenClaw immediately:
|
|
12
|
+
openclaw update
|
|
13
|
+
|
|
14
|
+
EOF
|
|
15
|
+
|
|
16
|
+
exit 0
|
|
17
|
+
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# CHECK 8 (origin 42): Browser Control API Path Traversal
|
|
3
|
+
# Usage: ./check_8.sh
|
|
4
|
+
|
|
5
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
6
|
+
source "$SCRIPT_DIR/_common.sh"
|
|
7
|
+
|
|
8
|
+
# Guidance
|
|
9
|
+
cat <<EOF
|
|
10
|
+
RECOMMENDED ACTIONS:
|
|
11
|
+
1. Update OpenClaw immediately:
|
|
12
|
+
openclaw update
|
|
13
|
+
|
|
14
|
+
EOF
|
|
15
|
+
|
|
16
|
+
exit 0
|
|
17
|
+
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# CHECK 9 (origin 47): TAR Archive Path Traversal
|
|
3
|
+
# Usage: ./check_9.sh
|
|
4
|
+
|
|
5
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
6
|
+
source "$SCRIPT_DIR/_common.sh"
|
|
7
|
+
|
|
8
|
+
# Guidance
|
|
9
|
+
cat <<EOF
|
|
10
|
+
RECOMMENDED ACTIONS:
|
|
11
|
+
1. Update OpenClaw immediately:
|
|
12
|
+
openclaw update
|
|
13
|
+
|
|
14
|
+
EOF
|
|
15
|
+
|
|
16
|
+
exit 0
|
|
17
|
+
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
Auto-fix complete: 0 fixed, 0 failed
|
|
2
|
+
Auto-fix complete: 0 fixed, 0 failed
|
|
3
|
+
Auto-fix complete: 0 fixed, 0 failed
|
|
4
|
+
Auto-fix complete: 0 fixed, 0 failed
|
|
5
|
+
Auto-fix complete: 0 fixed, 0 failed
|
|
6
|
+
Auto-fix complete: 0 fixed, 0 failed
|
|
7
|
+
Auto-fix complete: 0 fixed, 0 failed
|
|
8
|
+
Auto-fix complete: 0 fixed, 0 failed
|
|
9
|
+
Auto-fix complete: 0 fixed, 0 failed
|
|
10
|
+
Auto-fix complete: 0 fixed, 0 failed
|
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Exit codes: 0=SECURE, 1=WARNINGS, 2=COMPROMISED
|
|
3
|
+
|
|
4
|
+
set -uo pipefail
|
|
5
|
+
|
|
6
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
7
|
+
# PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
|
8
|
+
# IOC_DIR="$PROJECT_DIR/ioc"
|
|
9
|
+
PROJECT_DIR="$(cd "$SCRIPT_DIR/../../.." && pwd)"
|
|
10
|
+
IOC_DIR="$PROJECT_DIR/ioc"
|
|
11
|
+
SELF_DIR_NAME="$(basename "$PROJECT_DIR")"
|
|
12
|
+
|
|
13
|
+
# Default OpenClaw paths
|
|
14
|
+
# OPENCLAW_DIR="${OPENCLAW_HOME:-$HOME/.openclaw}"
|
|
15
|
+
OPENCLAW_DIR="${OPENCLAW_HOME:-$HOME/test/openclaw-1}"
|
|
16
|
+
SKILLS_DIR="$OPENCLAW_DIR/workspace/skills"
|
|
17
|
+
WORKSPACE_DIR="$OPENCLAW_DIR/workspace"
|
|
18
|
+
# LOG_DIR="$OPENCLAW_DIR/logs"
|
|
19
|
+
LOG_DIR="logs"
|
|
20
|
+
LOG_FILE="$LOG_DIR/security-scan.log"
|
|
21
|
+
TIMESTAMP="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
|
|
22
|
+
|
|
23
|
+
export PATH="$HOME/.local/bin:/opt/homebrew/opt/node@22/bin:/opt/homebrew/bin:/usr/local/bin:$PATH"
|
|
24
|
+
|
|
25
|
+
# Overall counters
|
|
26
|
+
CRITICAL=0
|
|
27
|
+
WARNINGS=0
|
|
28
|
+
CLEAN=0
|
|
29
|
+
|
|
30
|
+
# Per-category counters
|
|
31
|
+
CATEGORY_NAME=""
|
|
32
|
+
CATEGORY_TOTAL_CHECKS=0
|
|
33
|
+
CATEGORY_CRITICAL=0
|
|
34
|
+
CATEGORY_WARNINGS=0
|
|
35
|
+
CATEGORY_CLEAN=0
|
|
36
|
+
|
|
37
|
+
mkdir -p "$LOG_DIR"
|
|
38
|
+
|
|
39
|
+
log() {
|
|
40
|
+
echo "$1" | tee -a "$LOG_FILE"
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
header() {
|
|
44
|
+
# Usage: header <new_index> <message>
|
|
45
|
+
log ""
|
|
46
|
+
log "[$1/$CATEGORY_TOTAL_CHECKS] $2"
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
result_clean() {
|
|
50
|
+
log "CLEAN: $1"
|
|
51
|
+
CLEAN=$((CLEAN + 1))
|
|
52
|
+
CATEGORY_CLEAN=$((CATEGORY_CLEAN + 1))
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
result_warn() {
|
|
56
|
+
log "WARNING: $1"
|
|
57
|
+
WARNINGS=$((WARNINGS + 1))
|
|
58
|
+
CATEGORY_WARNINGS=$((CATEGORY_WARNINGS + 1))
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
result_critical() {
|
|
62
|
+
log "CRITICAL: $1"
|
|
63
|
+
CRITICAL=$((CRITICAL + 1))
|
|
64
|
+
CATEGORY_CRITICAL=$((CATEGORY_CRITICAL + 1))
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
category_start() {
|
|
68
|
+
# Usage: category_start <name> <total_checks>
|
|
69
|
+
CATEGORY_NAME="$1"
|
|
70
|
+
CATEGORY_TOTAL_CHECKS="$2"
|
|
71
|
+
CATEGORY_CRITICAL=0
|
|
72
|
+
CATEGORY_WARNINGS=0
|
|
73
|
+
CATEGORY_CLEAN=0
|
|
74
|
+
|
|
75
|
+
log ""
|
|
76
|
+
log "----------------------------------------"
|
|
77
|
+
log "CATEGORY START: $CATEGORY_NAME ($CATEGORY_TOTAL_CHECKS checks)"
|
|
78
|
+
log "----------------------------------------"
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
category_end() {
|
|
82
|
+
log ""
|
|
83
|
+
log "CATEGORY SUMMARY: $CATEGORY_NAME"
|
|
84
|
+
log " critical: $CATEGORY_CRITICAL"
|
|
85
|
+
log " warning : $CATEGORY_WARNINGS"
|
|
86
|
+
log " clean : $CATEGORY_CLEAN"
|
|
87
|
+
log "----------------------------------------"
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
# Use timeout if available (macOS may only have gtimeout via coreutils)
|
|
91
|
+
TIMEOUT_BIN=""
|
|
92
|
+
if command -v timeout >/dev/null 2>&1; then
|
|
93
|
+
TIMEOUT_BIN="timeout"
|
|
94
|
+
elif command -v gtimeout >/dev/null 2>&1; then
|
|
95
|
+
TIMEOUT_BIN="gtimeout"
|
|
96
|
+
fi
|
|
97
|
+
|
|
98
|
+
run_with_timeout() {
|
|
99
|
+
local secs="$1"
|
|
100
|
+
shift
|
|
101
|
+
|
|
102
|
+
if [ -n "$TIMEOUT_BIN" ]; then
|
|
103
|
+
"$TIMEOUT_BIN" "$secs" "$@"
|
|
104
|
+
elif command -v python3 >/dev/null 2>&1; then
|
|
105
|
+
python3 - "$secs" "$@" <<'PY'
|
|
106
|
+
import subprocess
|
|
107
|
+
import sys
|
|
108
|
+
|
|
109
|
+
def main():
|
|
110
|
+
try:
|
|
111
|
+
secs = float(sys.argv[1])
|
|
112
|
+
except Exception:
|
|
113
|
+
secs = 0
|
|
114
|
+
|
|
115
|
+
cmd = sys.argv[2:]
|
|
116
|
+
if not cmd:
|
|
117
|
+
sys.exit(1)
|
|
118
|
+
|
|
119
|
+
try:
|
|
120
|
+
proc = subprocess.Popen(cmd)
|
|
121
|
+
try:
|
|
122
|
+
proc.wait(timeout=secs if secs > 0 else None)
|
|
123
|
+
except subprocess.TimeoutExpired:
|
|
124
|
+
proc.kill()
|
|
125
|
+
proc.wait()
|
|
126
|
+
sys.exit(124)
|
|
127
|
+
sys.exit(proc.returncode if proc.returncode is not None else 0)
|
|
128
|
+
except FileNotFoundError:
|
|
129
|
+
sys.exit(127)
|
|
130
|
+
|
|
131
|
+
if __name__ == "__main__":
|
|
132
|
+
main()
|
|
133
|
+
PY
|
|
134
|
+
else
|
|
135
|
+
"$@"
|
|
136
|
+
fi
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
# Load IOC data
|
|
140
|
+
load_ips() {
|
|
141
|
+
if [ -f "$IOC_DIR/c2-ips.txt" ]; then
|
|
142
|
+
grep -v '^#' "$IOC_DIR/c2-ips.txt" | grep -v '^$' | cut -d'|' -f1
|
|
143
|
+
else
|
|
144
|
+
echo "91.92.242"
|
|
145
|
+
fi
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
load_domains() {
|
|
149
|
+
if [ -f "$IOC_DIR/malicious-domains.txt" ]; then
|
|
150
|
+
grep -v '^#' "$IOC_DIR/malicious-domains.txt" | grep -v '^$' | cut -d'|' -f1
|
|
151
|
+
else
|
|
152
|
+
echo "webhook.site"
|
|
153
|
+
fi
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
sha256_file() {
|
|
157
|
+
# Cross-platform SHA-256 for a file
|
|
158
|
+
local target="$1"
|
|
159
|
+
[ -f "$target" ] || return 1
|
|
160
|
+
|
|
161
|
+
if command -v sha256sum >/dev/null 2>&1; then
|
|
162
|
+
sha256sum "$target" 2>/dev/null | awk '{print tolower($1)}'
|
|
163
|
+
elif command -v shasum >/dev/null 2>&1; then
|
|
164
|
+
shasum -a 256 "$target" 2>/dev/null | awk '{print tolower($1)}'
|
|
165
|
+
elif command -v openssl >/dev/null 2>&1; then
|
|
166
|
+
openssl dgst -sha256 "$target" 2>/dev/null | sed -E 's/^.*= //' | tr '[:upper:]' '[:lower:]'
|
|
167
|
+
else
|
|
168
|
+
return 1
|
|
169
|
+
fi
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
load_hash_iocs() {
|
|
173
|
+
# Expected format: <sha256>|<campaign>
|
|
174
|
+
# Similar to c2-ips.txt storage style
|
|
175
|
+
if [ -f "$IOC_DIR/malicious-hashes.txt" ]; then
|
|
176
|
+
grep -v '^#' "$IOC_DIR/malicious-hashes.txt" | grep -v '^$' || true
|
|
177
|
+
fi
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
lookup_malicious_hash_campaign() {
|
|
181
|
+
local needle
|
|
182
|
+
needle="$(printf "%s" "${1:-}" | tr '[:upper:]' '[:lower:]')"
|
|
183
|
+
[ -n "$needle" ] || return 1
|
|
184
|
+
|
|
185
|
+
while IFS='|' read -r hash_val campaign rest; do
|
|
186
|
+
hash_val="$(printf "%s" "$hash_val" | tr '[:upper:]' '[:lower:]')"
|
|
187
|
+
if [ "$hash_val" = "$needle" ]; then
|
|
188
|
+
printf "%s\n" "${campaign:-unknown}"
|
|
189
|
+
return 0
|
|
190
|
+
fi
|
|
191
|
+
done < <(load_hash_iocs) # ← 进程替换,不产生子shell
|
|
192
|
+
|
|
193
|
+
return 1
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
extract_github_account_age_days() {
|
|
197
|
+
# Best-effort local metadata extraction only.
|
|
198
|
+
# We cannot reliably infer GitHub account age from filesystem alone unless
|
|
199
|
+
# the skill metadata explicitly records it.
|
|
200
|
+
local skill_dir="$1"
|
|
201
|
+
local val=""
|
|
202
|
+
|
|
203
|
+
for meta in "$skill_dir/package.json" "$skill_dir/config.json" "$skill_dir/SKILL.md"; do
|
|
204
|
+
[ -f "$meta" ] || continue
|
|
205
|
+
|
|
206
|
+
# JSON-ish keys
|
|
207
|
+
val="$(grep -iEo '"(githubAccountAge|github_account_age|accountAgeDays|githubAccountAgeDays)"[[:space:]]*:[[:space:]]*[0-9]+' "$meta" 2>/dev/null | head -1 | grep -oE '[0-9]+' || true)"
|
|
208
|
+
if [ -n "$val" ]; then
|
|
209
|
+
printf "%s\n" "$val"
|
|
210
|
+
return 0
|
|
211
|
+
fi
|
|
212
|
+
|
|
213
|
+
# YAML / markdown frontmatter-ish keys
|
|
214
|
+
val="$(grep -iE '^(githubAccountAge|github_account_age|accountAgeDays|githubAccountAgeDays)[[:space:]]*:[[:space:]]*[0-9]+' "$meta" 2>/dev/null | head -1 | grep -oE '[0-9]+' || true)"
|
|
215
|
+
if [ -n "$val" ]; then
|
|
216
|
+
printf "%s\n" "$val"
|
|
217
|
+
return 0
|
|
218
|
+
fi
|
|
219
|
+
done
|
|
220
|
+
|
|
221
|
+
return 1
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
OPENCLAW_PRESENT=false
|
|
226
|
+
if command -v openclaw >/dev/null 2>&1; then
|
|
227
|
+
OPENCLAW_PRESENT=true
|
|
228
|
+
fi
|
|
229
|
+
|
|
230
|
+
has_pcre_grep() {
|
|
231
|
+
echo 'test' | grep -P 't.st' >/dev/null 2>&1
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
get_oc_config() {
|
|
235
|
+
# Usage: get_oc_config <key> <default>
|
|
236
|
+
local key="$1"
|
|
237
|
+
local default_val="${2:-}"
|
|
238
|
+
if [ "$OPENCLAW_PRESENT" = true ]; then
|
|
239
|
+
run_with_timeout 10 openclaw config get "$key" 2>/dev/null || echo "$default_val"
|
|
240
|
+
else
|
|
241
|
+
echo "$default_val"
|
|
242
|
+
fi
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
normalize_config_val() {
|
|
246
|
+
local val="${1:-}"
|
|
247
|
+
case "$val" in
|
|
248
|
+
null|undefined|"")
|
|
249
|
+
echo ""
|
|
250
|
+
;;
|
|
251
|
+
*)
|
|
252
|
+
echo "$val"
|
|
253
|
+
;;
|
|
254
|
+
esac
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
get_perm() {
|
|
258
|
+
local target="$1"
|
|
259
|
+
|
|
260
|
+
[ -e "$target" ] || {
|
|
261
|
+
echo "unknown"
|
|
262
|
+
return
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
case "$(uname -s)" in
|
|
266
|
+
Darwin|FreeBSD|OpenBSD|NetBSD)
|
|
267
|
+
stat -f '%Lp' "$target" 2>/dev/null || echo "unknown"
|
|
268
|
+
;;
|
|
269
|
+
Linux)
|
|
270
|
+
stat -c '%a' "$target" 2>/dev/null || echo "unknown"
|
|
271
|
+
;;
|
|
272
|
+
*)
|
|
273
|
+
stat -c '%a' "$target" 2>/dev/null || stat -f '%Lp' "$target" 2>/dev/null || echo "unknown"
|
|
274
|
+
;;
|
|
275
|
+
esac
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
list_memory_files() {
|
|
279
|
+
# Enumerate workspace-level and agent-level memory files
|
|
280
|
+
local f
|
|
281
|
+
for f in \
|
|
282
|
+
"$WORKSPACE_DIR/SOUL.md" \
|
|
283
|
+
"$WORKSPACE_DIR/MEMORY.md" \
|
|
284
|
+
"$WORKSPACE_DIR/IDENTITY.md"
|
|
285
|
+
do
|
|
286
|
+
[ -f "$f" ] && echo "$f"
|
|
287
|
+
done
|
|
288
|
+
|
|
289
|
+
if [ -d "$OPENCLAW_DIR/agents" ]; then
|
|
290
|
+
find "$OPENCLAW_DIR/agents" -mindepth 2 -maxdepth 2 -type f \
|
|
291
|
+
\( -name 'soul.md' -o -name 'SOUL.md' -o -name 'MEMORY.md' -o -name 'IDENTITY.md' \) \
|
|
292
|
+
2>/dev/null || true
|
|
293
|
+
fi
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
extract_allowed_domains() {
|
|
297
|
+
# Build allowlist from config + defaults
|
|
298
|
+
# Defaults follow the TS snippet.
|
|
299
|
+
local cfg raw_domains
|
|
300
|
+
cfg="$(normalize_config_val "$(get_oc_config "secureclaw.network.egressAllowlist" "")")"
|
|
301
|
+
|
|
302
|
+
{
|
|
303
|
+
echo "api.anthropic.com"
|
|
304
|
+
echo "api.openai.com"
|
|
305
|
+
echo "generativelanguage.googleapis.com"
|
|
306
|
+
if [ -n "$cfg" ]; then
|
|
307
|
+
echo "$cfg" | grep -oE '[A-Za-z0-9.-]+\.[A-Za-z]{2,}' || true
|
|
308
|
+
fi
|
|
309
|
+
} | awk 'NF' | sort -u
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
url_host_allowed() {
|
|
313
|
+
# Usage: url_host_allowed <hostname>
|
|
314
|
+
local host="${1:-}"
|
|
315
|
+
local allowed
|
|
316
|
+
[ -n "$host" ] || return 1
|
|
317
|
+
|
|
318
|
+
while IFS= read -r allowed; do
|
|
319
|
+
[ -z "$allowed" ] && continue
|
|
320
|
+
if [ "$host" = "$allowed" ]; then
|
|
321
|
+
return 0
|
|
322
|
+
fi
|
|
323
|
+
case "$host" in
|
|
324
|
+
*."$allowed")
|
|
325
|
+
return 0
|
|
326
|
+
;;
|
|
327
|
+
esac
|
|
328
|
+
done <<EOF
|
|
329
|
+
$ALLOWED_DOMAINS
|
|
330
|
+
EOF
|
|
331
|
+
|
|
332
|
+
return 1
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
# Precompute allowed domains once
|
|
336
|
+
ALLOWED_DOMAINS="$(extract_allowed_domains)"
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# CHECK 1 (origin 10 + expanded patterns): Memory Poisoning Detection
|
|
3
|
+
# Usage: ./check_1.sh
|
|
4
|
+
|
|
5
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
6
|
+
source "$SCRIPT_DIR/_common.sh"
|
|
7
|
+
|
|
8
|
+
MEMORY_POISON=0
|
|
9
|
+
MEMORY_FILES_FOUND=0
|
|
10
|
+
FOUND_FILES=()
|
|
11
|
+
|
|
12
|
+
while IFS= read -r memfile; do
|
|
13
|
+
[ -z "$memfile" ] && continue
|
|
14
|
+
[ -f "$memfile" ] || continue
|
|
15
|
+
|
|
16
|
+
MEMORY_FILES_FOUND=$((MEMORY_FILES_FOUND + 1))
|
|
17
|
+
|
|
18
|
+
POISON_HITS="$(grep -inE \
|
|
19
|
+
'ignore[[:space:]]+previous[[:space:]]+instructions|ignore[[:space:]]+all[[:space:]]+previous|disregard[[:space:]]+(all[[:space:]]+)?previous|override.*instruction|new[[:space:]]+system[[:space:]]+prompt|system[[:space:]]+prompt|forget.*previous|you[[:space:]]+are[[:space:]]+now|act[[:space:]]+as[[:space:]]+if|pretend[[:space:]]+to[[:space:]]+be|from[[:space:]]+now[[:space:]]+on.*ignore|forward[[:space:]]+to|send[[:space:]]+to|exfiltrat(e|ion)|leak[[:space:]]+(the[[:space:]]+)?(secret|token|credential|key)|reveal[[:space:]]+(the[[:space:]]+)?(system[[:space:]]+prompt|secret|token|credential|key)|post[[:space:]]+to[[:space:]]+https?://|upload[[:space:]]+to[[:space:]]+https?://' \
|
|
20
|
+
"$memfile" 2>/dev/null || true)"
|
|
21
|
+
|
|
22
|
+
if [ -n "$POISON_HITS" ]; then
|
|
23
|
+
MEMORY_POISON=$((MEMORY_POISON + 1))
|
|
24
|
+
FOUND_FILES+=("$memfile")
|
|
25
|
+
fi
|
|
26
|
+
done <<EOF
|
|
27
|
+
$(list_memory_files)
|
|
28
|
+
EOF
|
|
29
|
+
|
|
30
|
+
# 生成文件路径列表
|
|
31
|
+
FILE_LIST=""
|
|
32
|
+
for f in "${FOUND_FILES[@]}"; do
|
|
33
|
+
FILE_LIST="${FILE_LIST} $f\n"
|
|
34
|
+
done
|
|
35
|
+
|
|
36
|
+
# Guidance
|
|
37
|
+
cat <<EOF
|
|
38
|
+
RECOMMENDED ACTIONS:
|
|
39
|
+
1. Inspect the flagged memory files:
|
|
40
|
+
$(printf "%b" "$FILE_LIST")
|
|
41
|
+
|
|
42
|
+
2. Remove any lines containing prompt injection patterns
|
|
43
|
+
|
|
44
|
+
3. If the file has been heavily tampered with, restore from a known-good backup or recreate it from scratch
|
|
45
|
+
|
|
46
|
+
4. Clear Agent memory if compromise is suspected:
|
|
47
|
+
openclaw memory clear
|
|
48
|
+
|
|
49
|
+
EOF
|
|
50
|
+
|
|
51
|
+
exit 0
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# CHECK 2 (origin 40): Log Poisoning / WebSocket Header Injection
|
|
3
|
+
# Usage: ./check_2.sh
|
|
4
|
+
|
|
5
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
6
|
+
source "$SCRIPT_DIR/_common.sh"
|
|
7
|
+
|
|
8
|
+
# Guidance
|
|
9
|
+
cat <<EOF
|
|
10
|
+
RECOMMENDED ACTIONS:
|
|
11
|
+
1. Enable WebSocket header redaction:
|
|
12
|
+
openclaw config set logging.redactHeaders true
|
|
13
|
+
|
|
14
|
+
2. Strip ANSI escape sequences from logs:
|
|
15
|
+
sed -i 's/\x1b\[[0-9;]*[a-zA-Z]//g' $LOG_DIR/*.log
|
|
16
|
+
|
|
17
|
+
3. Strip control characters from logs:
|
|
18
|
+
for f in $LOG_DIR/*.log; do tr -d '\000-\010\016-\037' < "\$f" > "\$f.clean" && mv "\$f.clean" "\$f"; done
|
|
19
|
+
|
|
20
|
+
4. Restart OpenClaw to apply config changes:
|
|
21
|
+
openclaw restart
|
|
22
|
+
|
|
23
|
+
EOF
|
|
24
|
+
|
|
25
|
+
exit 0
|
|
26
|
+
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# CHECK 3 (new / MEM-003): Base64 encoded blocks in memory
|
|
3
|
+
# Usage: ./check_3.sh
|
|
4
|
+
|
|
5
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
6
|
+
source "$SCRIPT_DIR/_common.sh"
|
|
7
|
+
|
|
8
|
+
# Guidance
|
|
9
|
+
cat <<EOF
|
|
10
|
+
RECOMMENDED ACTIONS:
|
|
11
|
+
1. Inspect the flagged memory files and decode suspicious blocks manually:
|
|
12
|
+
base64 -d <<< "<paste-base64-string>"
|
|
13
|
+
|
|
14
|
+
2. If the decoded content contains suspicious instructions (API calls, exfiltration), delete the memory file immediately
|
|
15
|
+
|
|
16
|
+
3. Review which skill or conversation created this memory entry.
|
|
17
|
+
|
|
18
|
+
4. Consider clearing all memory and starting fresh if compromise is suspected:
|
|
19
|
+
openclaw memory clear
|
|
20
|
+
|
|
21
|
+
EOF
|
|
22
|
+
|
|
23
|
+
exit 0
|
|
24
|
+
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# CHECK 4 (new / MEM-004): Non-whitelisted URLs in memory
|
|
3
|
+
# Usage: ./check_4.sh
|
|
4
|
+
|
|
5
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
6
|
+
source "$SCRIPT_DIR/_common.sh"
|
|
7
|
+
|
|
8
|
+
# Guidance
|
|
9
|
+
cat <<EOF
|
|
10
|
+
RECOMMENDED ACTIONS:
|
|
11
|
+
1. Review the flagged memory files and inspect the suspicious URLs (check logs above)
|
|
12
|
+
|
|
13
|
+
2. If the URL is malicious, delete the memory entry:
|
|
14
|
+
openclaw memory clear
|
|
15
|
+
|
|
16
|
+
3. If the domain is legitimate and should be allowed, add it to the egress allowlist:
|
|
17
|
+
openclaw config set egress.allowlist '["api.openai.com","api.anthropic.com","<your-domain>"]'
|
|
18
|
+
|
|
19
|
+
4. Review which skill or conversation introduced this URL into memory.
|
|
20
|
+
|
|
21
|
+
5. Check network logs for any outbound connections to the flagged domain:
|
|
22
|
+
grep "<suspicious-domain>" ~/.openclaw/logs/*.log
|
|
23
|
+
|
|
24
|
+
EOF
|
|
25
|
+
|
|
26
|
+
exit 0
|
|
27
|
+
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# CHECK 5 (new / MEM-005): Memory file permissions
|
|
3
|
+
# Usage: ./check_5.sh
|
|
4
|
+
|
|
5
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
6
|
+
source "$SCRIPT_DIR/_common.sh"
|
|
7
|
+
|
|
8
|
+
# Guidance
|
|
9
|
+
cat <<EOF
|
|
10
|
+
RECOMMENDED ACTIONS:
|
|
11
|
+
1. Fix memory file permissions:
|
|
12
|
+
chmod 600 <memory-file-path>
|
|
13
|
+
|
|
14
|
+
2. Or fix all memory files at once:
|
|
15
|
+
find ~/.openclaw/workspace/memory -type f -exec chmod 600 {} \;
|
|
16
|
+
|
|
17
|
+
EOF
|
|
18
|
+
|
|
19
|
+
exit 0
|
|
20
|
+
|