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,330 @@
|
|
|
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
|
+
export PATH="$HOME/.local/bin:/opt/homebrew/opt/node@22/bin:/opt/homebrew/bin:/usr/local/bin:$PATH"
|
|
226
|
+
|
|
227
|
+
# ------------------------------------------------------------
|
|
228
|
+
# Shared helpers
|
|
229
|
+
# ------------------------------------------------------------
|
|
230
|
+
|
|
231
|
+
OPENCLAW_PRESENT=false
|
|
232
|
+
if command -v openclaw >/dev/null 2>&1; then
|
|
233
|
+
OPENCLAW_PRESENT=true
|
|
234
|
+
fi
|
|
235
|
+
|
|
236
|
+
OC_VERSION="unknown"
|
|
237
|
+
PARSED_OC_VERSION=""
|
|
238
|
+
OC_MAJOR=""
|
|
239
|
+
OC_MINOR=""
|
|
240
|
+
OC_PATCH=""
|
|
241
|
+
|
|
242
|
+
if [ "$OPENCLAW_PRESENT" = true ]; then
|
|
243
|
+
OC_VERSION="$(run_with_timeout 5 openclaw --version 2>/dev/null || echo "unknown")"
|
|
244
|
+
PARSED_OC_VERSION="$(echo "$OC_VERSION" | grep -oE '[0-9]{4}\.[0-9]+\.[0-9]+' | head -1 || true)"
|
|
245
|
+
if [ -n "$PARSED_OC_VERSION" ]; then
|
|
246
|
+
OC_MAJOR="$(echo "$PARSED_OC_VERSION" | cut -d'.' -f1)"
|
|
247
|
+
OC_MINOR="$(echo "$PARSED_OC_VERSION" | cut -d'.' -f2)"
|
|
248
|
+
OC_PATCH="$(echo "$PARSED_OC_VERSION" | cut -d'.' -f3)"
|
|
249
|
+
fi
|
|
250
|
+
fi
|
|
251
|
+
|
|
252
|
+
get_oc_config() {
|
|
253
|
+
# Usage: get_oc_config <key> <default>
|
|
254
|
+
local key="$1"
|
|
255
|
+
local default_val="${2:-}"
|
|
256
|
+
if [ "$OPENCLAW_PRESENT" = true ]; then
|
|
257
|
+
run_with_timeout 10 openclaw config get "$key" 2>/dev/null || echo "$default_val"
|
|
258
|
+
else
|
|
259
|
+
echo "$default_val"
|
|
260
|
+
fi
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
normalize_config_val() {
|
|
264
|
+
# Normalize null/undefined-ish values to empty string
|
|
265
|
+
local val="${1:-}"
|
|
266
|
+
case "$val" in
|
|
267
|
+
null|undefined|"")
|
|
268
|
+
echo ""
|
|
269
|
+
;;
|
|
270
|
+
*)
|
|
271
|
+
echo "$val"
|
|
272
|
+
;;
|
|
273
|
+
esac
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
version_ge() {
|
|
277
|
+
# Usage: version_ge <major> <minor> <patch>
|
|
278
|
+
# returns 0 if OC_VERSION >= target, else 1
|
|
279
|
+
local t_major="$1"
|
|
280
|
+
local t_minor="$2"
|
|
281
|
+
local t_patch="$3"
|
|
282
|
+
|
|
283
|
+
if [ -z "$PARSED_OC_VERSION" ]; then
|
|
284
|
+
return 1
|
|
285
|
+
fi
|
|
286
|
+
|
|
287
|
+
if [ "$OC_MAJOR" -gt "$t_major" ] 2>/dev/null; then
|
|
288
|
+
return 0
|
|
289
|
+
fi
|
|
290
|
+
if [ "$OC_MAJOR" -lt "$t_major" ] 2>/dev/null; then
|
|
291
|
+
return 1
|
|
292
|
+
fi
|
|
293
|
+
|
|
294
|
+
if [ "$OC_MINOR" -gt "$t_minor" ] 2>/dev/null; then
|
|
295
|
+
return 0
|
|
296
|
+
fi
|
|
297
|
+
if [ "$OC_MINOR" -lt "$t_minor" ] 2>/dev/null; then
|
|
298
|
+
return 1
|
|
299
|
+
fi
|
|
300
|
+
|
|
301
|
+
if [ "$OC_PATCH" -ge "$t_patch" ] 2>/dev/null; then
|
|
302
|
+
return 0
|
|
303
|
+
fi
|
|
304
|
+
|
|
305
|
+
return 1
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
version_lt() {
|
|
309
|
+
# Usage: version_lt <major> <minor> <patch>
|
|
310
|
+
# returns 0 if OC_VERSION < target, else 1
|
|
311
|
+
if [ -z "$PARSED_OC_VERSION" ]; then
|
|
312
|
+
return 1
|
|
313
|
+
fi
|
|
314
|
+
if version_ge "$1" "$2" "$3"; then
|
|
315
|
+
return 1
|
|
316
|
+
fi
|
|
317
|
+
return 0
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
detect_gateway_port() {
|
|
321
|
+
local raw
|
|
322
|
+
raw="$(get_oc_config "gateway.port" "18789")"
|
|
323
|
+
raw="$(echo "$raw" | grep -oE '[0-9]+' | head -1 || true)"
|
|
324
|
+
if [ -z "$raw" ]; then
|
|
325
|
+
raw="18789"
|
|
326
|
+
fi
|
|
327
|
+
echo "$raw"
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
GW_PORT="$(detect_gateway_port)"
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# CHECK 1 (origin 13): Gateway Security Configuration
|
|
3
|
+
|
|
4
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
5
|
+
source "$SCRIPT_DIR/_common.sh"
|
|
6
|
+
|
|
7
|
+
# Environment vars (set by caller / _common.sh sourced before this):
|
|
8
|
+
# AUTO_FIX — if "1", automatically remove the offending skill
|
|
9
|
+
# Example: AUTO_FIX=1 ./check_1.sh
|
|
10
|
+
|
|
11
|
+
GW_ISSUES=0
|
|
12
|
+
BIND="unknown"
|
|
13
|
+
AUTH_MODE="unknown"
|
|
14
|
+
|
|
15
|
+
if [ "$OPENCLAW_PRESENT" = true ]; then
|
|
16
|
+
log " OpenClaw version: $OC_VERSION"
|
|
17
|
+
|
|
18
|
+
BIND="$(get_oc_config "gateway.bind" "unknown")"
|
|
19
|
+
if [ "$BIND" = "lan" ] || [ "$BIND" = "0.0.0.0" ]; then
|
|
20
|
+
GW_ISSUES=$((GW_ISSUES + 1))
|
|
21
|
+
fi
|
|
22
|
+
|
|
23
|
+
AUTH_MODE="$(get_oc_config "gateway.auth.mode" "unknown")"
|
|
24
|
+
if [ "$AUTH_MODE" = "none" ] || [ "$AUTH_MODE" = "off" ]; then
|
|
25
|
+
GW_ISSUES=$((GW_ISSUES + 1))
|
|
26
|
+
fi
|
|
27
|
+
else
|
|
28
|
+
log " openclaw command not found"
|
|
29
|
+
fi
|
|
30
|
+
|
|
31
|
+
# Auto-fix
|
|
32
|
+
if [ "${AUTO_FIX:-0}" = "1" ]; then
|
|
33
|
+
FIXED=0
|
|
34
|
+
FAILED=0
|
|
35
|
+
|
|
36
|
+
if [ "$BIND" = "lan" ] || [ "$BIND" = "0.0.0.0" ]; then
|
|
37
|
+
log "AUTO-FIX: Setting gateway.bind to localhost..."
|
|
38
|
+
if openclaw config set gateway.bind localhost >> "$LOG_FILE" 2>&1; then
|
|
39
|
+
log "SUCCESS: gateway.bind set to localhost"
|
|
40
|
+
FIXED=$((FIXED + 1))
|
|
41
|
+
else
|
|
42
|
+
log "ERROR: Failed to set gateway.bind"
|
|
43
|
+
FAILED=$((FAILED + 1))
|
|
44
|
+
fi
|
|
45
|
+
fi
|
|
46
|
+
|
|
47
|
+
if [ "$AUTH_MODE" = "none" ] || [ "$AUTH_MODE" = "off" ]; then
|
|
48
|
+
log "AUTO-FIX: Setting gateway.auth.mode to token..."
|
|
49
|
+
if openclaw config set gateway.auth.mode token >> "$LOG_FILE" 2>&1; then
|
|
50
|
+
log "SUCCESS: gateway.auth.mode set to token"
|
|
51
|
+
FIXED=$((FIXED + 1))
|
|
52
|
+
else
|
|
53
|
+
log "ERROR: Failed to set gateway.auth.mode"
|
|
54
|
+
FAILED=$((FAILED + 1))
|
|
55
|
+
fi
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
log "Auto-fix complete: $FIXED fixed, $FAILED failed"
|
|
59
|
+
if [ $FIXED -gt 0 ]; then
|
|
60
|
+
log "NOTE: Restart OpenClaw for changes to take effect: openclaw restart"
|
|
61
|
+
fi
|
|
62
|
+
exit 0
|
|
63
|
+
fi
|
|
64
|
+
|
|
65
|
+
# Guidance
|
|
66
|
+
cat <<EOF
|
|
67
|
+
Found $GW_ISSUES gateway configuration issue(s).
|
|
68
|
+
An exposed or unauthenticated gateway allows anyone on the network to access OpenClaw.
|
|
69
|
+
|
|
70
|
+
RECOMMENDED ACTIONS:
|
|
71
|
+
1. Bind gateway to localhost only (current: $BIND)
|
|
72
|
+
openclaw config set gateway.bind localhost
|
|
73
|
+
|
|
74
|
+
2. Enable gateway authentication (current: $AUTH_MODE)
|
|
75
|
+
openclaw config set gateway.auth.mode token
|
|
76
|
+
|
|
77
|
+
3. Restart OpenClaw to apply changes
|
|
78
|
+
openclaw restart
|
|
79
|
+
|
|
80
|
+
4. Verify current gateway config
|
|
81
|
+
openclaw config get gateway
|
|
82
|
+
|
|
83
|
+
auto-fix
|
|
84
|
+
EOF
|
|
85
|
+
|
|
86
|
+
exit 1
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# CHECK 10 (origin 39/45): Deep Link + Sandbox Browser Bridge
|
|
3
|
+
# Usage: ./check_10.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:
|
|
12
|
+
openclaw update
|
|
13
|
+
|
|
14
|
+
EOF
|
|
15
|
+
|
|
16
|
+
exit 0
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# CHECK 11 (new / GW-003): Weak gateway auth token/password
|
|
3
|
+
# Usage: ./check_11.sh
|
|
4
|
+
|
|
5
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
6
|
+
source "$SCRIPT_DIR/_common.sh"
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# Guidance
|
|
10
|
+
cat <<EOF
|
|
11
|
+
RECOMMENDED ACTIONS:
|
|
12
|
+
1. Generate a strong random token:
|
|
13
|
+
openssl rand -hex 16
|
|
14
|
+
|
|
15
|
+
2. Set the new token:
|
|
16
|
+
openclaw config set gateway.auth.password <new-token>
|
|
17
|
+
|
|
18
|
+
3. Or set token mode and update:
|
|
19
|
+
openclaw config set gateway.auth.mode token
|
|
20
|
+
openclaw config set gateway.auth.token <new-token>
|
|
21
|
+
|
|
22
|
+
4. Verify the new token length:
|
|
23
|
+
openclaw config get gateway.auth.password | wc -c
|
|
24
|
+
# Should be 32 or more
|
|
25
|
+
|
|
26
|
+
5. Restart OpenClaw to apply changes:
|
|
27
|
+
openclaw restart
|
|
28
|
+
|
|
29
|
+
EOF
|
|
30
|
+
|
|
31
|
+
exit 0
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# CHECK 12 (new / GW-006): Gateway TLS enabled
|
|
3
|
+
# Usage: ./check_12.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 TLS on the gateway:
|
|
12
|
+
openclaw config set gateway.tls.enabled true
|
|
13
|
+
|
|
14
|
+
2. Provide your TLS certificate and key via OpenClaw config:
|
|
15
|
+
openclaw config set gateway.tls.certFile /path/to/cert.pem
|
|
16
|
+
openclaw config set gateway.tls.keyFile /path/to/key.pem
|
|
17
|
+
|
|
18
|
+
3. Restart OpenClaw to apply changes:
|
|
19
|
+
openclaw restart
|
|
20
|
+
|
|
21
|
+
4. Consult OpenClaw documentation for TLS configuration details.
|
|
22
|
+
EOF
|
|
23
|
+
|
|
24
|
+
exit 0
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# CHECK 2 (origin 14): WebSocket Origin Validation
|
|
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. Update OpenClaw immediately:
|
|
12
|
+
openclaw update
|
|
13
|
+
|
|
14
|
+
2. Enable gateway authentication as an additional mitigation:
|
|
15
|
+
openclaw config set gateway.auth.mode token
|
|
16
|
+
openclaw config set gateway.auth.token \$(openssl rand -hex 16)
|
|
17
|
+
|
|
18
|
+
3. Bind gateway to localhost only:
|
|
19
|
+
openclaw config set gateway.bind localhost
|
|
20
|
+
|
|
21
|
+
4. Restart OpenClaw to apply changes:
|
|
22
|
+
openclaw restart
|
|
23
|
+
|
|
24
|
+
EOF
|
|
25
|
+
|
|
26
|
+
exit 0
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# CHECK 3 (origin 25): Reverse Proxy / Localhost Trust Bypass
|
|
3
|
+
# Usage: ./check_3.sh
|
|
4
|
+
|
|
5
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
6
|
+
source "$SCRIPT_DIR/_common.sh"
|
|
7
|
+
|
|
8
|
+
# Environment vars (set by caller / _common.sh sourced before this):
|
|
9
|
+
# AUTO_FIX — if "1", automatically remove the offending skill
|
|
10
|
+
# Example: AUTO_FIX=1 ./check_3.sh
|
|
11
|
+
|
|
12
|
+
# Auto-fix
|
|
13
|
+
if [ "${AUTO_FIX:-0}" = "1" ]; then
|
|
14
|
+
if [ "$DISABLE_DEVICE_AUTH" = "true" ]; then
|
|
15
|
+
log "AUTO-FIX: Re-enabling device authentication..."
|
|
16
|
+
if openclaw config set gateway.dangerouslyDisableDeviceAuth false >> "$LOG_FILE" 2>&1; then
|
|
17
|
+
log "SUCCESS: Device authentication re-enabled"
|
|
18
|
+
else
|
|
19
|
+
log "ERROR: Failed to re-enable device authentication"
|
|
20
|
+
fi
|
|
21
|
+
fi
|
|
22
|
+
exit 0
|
|
23
|
+
fi
|
|
24
|
+
|
|
25
|
+
# Guidance
|
|
26
|
+
cat <<EOF
|
|
27
|
+
RECOMMENDED ACTIONS:
|
|
28
|
+
1. Re-enable device authentication:
|
|
29
|
+
openclaw config set gateway.dangerouslyDisableDeviceAuth false
|
|
30
|
+
|
|
31
|
+
2. Bind gateway to localhost instead of LAN:
|
|
32
|
+
openclaw config set gateway.bind localhost
|
|
33
|
+
|
|
34
|
+
3. If reverse proxy is needed, configure trusted proxies explicitly:
|
|
35
|
+
openclaw config set gateway.trustedProxies '["127.0.0.1"]'
|
|
36
|
+
|
|
37
|
+
4. Restart OpenClaw to apply changes:
|
|
38
|
+
openclaw restart
|
|
39
|
+
|
|
40
|
+
auto-fix
|
|
41
|
+
EOF
|
|
42
|
+
|
|
43
|
+
exit 0
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# CHECK 4 (origin 33): ClawJacked Brute-Force Protection
|
|
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. Set a strong gateway password (if not already set):
|
|
15
|
+
openclaw config set gateway.auth.mode token
|
|
16
|
+
openclaw config set gateway.auth.token <strong-random-token>
|
|
17
|
+
|
|
18
|
+
3. Verify rate limiting is enabled after update:
|
|
19
|
+
openclaw config get gateway.auth.rateLimit
|
|
20
|
+
|
|
21
|
+
EOF
|
|
22
|
+
|
|
23
|
+
exit 0
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# CHECK 5 (origin 41): Browser Relay CDP Unauthenticated Access
|
|
3
|
+
# Usage: ./check_5.sh
|
|
4
|
+
|
|
5
|
+
# Guidance
|
|
6
|
+
cat << EOF
|
|
7
|
+
RECOMMENDED ACTIONS:
|
|
8
|
+
1. Update OpenClaw immediately:
|
|
9
|
+
openclaw update
|
|
10
|
+
|
|
11
|
+
2. Disable Browser Relay until patched:
|
|
12
|
+
openclaw config set browser.relay.enabled false
|
|
13
|
+
|
|
14
|
+
EOF
|
|
15
|
+
|
|
16
|
+
exit 0
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# CHECK 6 (origin 31): Internet Exposure Detection
|
|
3
|
+
# Usage: ./check_6.sh
|
|
4
|
+
|
|
5
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
6
|
+
source "$SCRIPT_DIR/_common.sh"
|
|
7
|
+
|
|
8
|
+
OC_PORT="$(openclaw config get gateway.port 2>/dev/null || echo "3000")"
|
|
9
|
+
|
|
10
|
+
if command -v firewall-cmd &>/dev/null && firewall-cmd --state &>/dev/null 2>&1; then
|
|
11
|
+
FW_TYPE="firewalld"
|
|
12
|
+
elif command -v ufw &>/dev/null; then
|
|
13
|
+
FW_TYPE="ufw"
|
|
14
|
+
else
|
|
15
|
+
FW_TYPE="iptables"
|
|
16
|
+
fi
|
|
17
|
+
|
|
18
|
+
case "$FW_TYPE" in
|
|
19
|
+
firewalld)
|
|
20
|
+
cat <<EOF
|
|
21
|
+
RECOMMENDED ACTIONS:
|
|
22
|
+
1. Block OpenClaw port from external access:
|
|
23
|
+
sudo firewall-cmd --permanent --remove-port=$OC_PORT/tcp
|
|
24
|
+
sudo firewall-cmd --reload
|
|
25
|
+
|
|
26
|
+
2. Allow only localhost access (if needed):
|
|
27
|
+
sudo firewall-cmd --permanent --zone=trusted --add-source=127.0.0.1
|
|
28
|
+
sudo firewall-cmd --permanent --zone=trusted --add-port=$OC_PORT/tcp
|
|
29
|
+
sudo firewall-cmd --reload
|
|
30
|
+
|
|
31
|
+
3. Verify rules:
|
|
32
|
+
sudo firewall-cmd --list-all
|
|
33
|
+
|
|
34
|
+
4. Check status:
|
|
35
|
+
sudo firewall-cmd --state
|
|
36
|
+
|
|
37
|
+
EOF
|
|
38
|
+
;;
|
|
39
|
+
ufw)
|
|
40
|
+
cat <<EOF
|
|
41
|
+
==========================================
|
|
42
|
+
GUIDANCE: Manual Review Required
|
|
43
|
+
==========================================
|
|
44
|
+
Linux Firewall Configuration (ufw)
|
|
45
|
+
|
|
46
|
+
RECOMMENDED ACTIONS:
|
|
47
|
+
1. Enable ufw if not already enabled:
|
|
48
|
+
sudo ufw enable
|
|
49
|
+
|
|
50
|
+
2. Deny OpenClaw port by default:
|
|
51
|
+
sudo ufw deny $OC_PORT/tcp
|
|
52
|
+
|
|
53
|
+
3. Allow only localhost access:
|
|
54
|
+
sudo ufw allow from 127.0.0.1 to any port $OC_PORT proto tcp
|
|
55
|
+
|
|
56
|
+
4. Verify rules:
|
|
57
|
+
sudo ufw status verbose
|
|
58
|
+
|
|
59
|
+
5. Check numbered rules:
|
|
60
|
+
sudo ufw status numbered
|
|
61
|
+
|
|
62
|
+
EOF
|
|
63
|
+
;;
|
|
64
|
+
iptables)
|
|
65
|
+
cat <<EOF
|
|
66
|
+
==========================================
|
|
67
|
+
GUIDANCE: Manual Review Required
|
|
68
|
+
==========================================
|
|
69
|
+
Linux Firewall Configuration (iptables)
|
|
70
|
+
|
|
71
|
+
RECOMMENDED ACTIONS:
|
|
72
|
+
1. Allow localhost access only:
|
|
73
|
+
sudo iptables -A INPUT -p tcp --dport $OC_PORT -s 127.0.0.1 -j ACCEPT
|
|
74
|
+
sudo iptables -A INPUT -p tcp --dport $OC_PORT -j DROP
|
|
75
|
+
|
|
76
|
+
2. For IPv6:
|
|
77
|
+
sudo ip6tables -A INPUT -p tcp --dport $OC_PORT -s ::1 -j ACCEPT
|
|
78
|
+
sudo ip6tables -A INPUT -p tcp --dport $OC_PORT -j DROP
|
|
79
|
+
|
|
80
|
+
3. Save rules (Debian/Ubuntu):
|
|
81
|
+
sudo apt-get install iptables-persistent
|
|
82
|
+
sudo netfilter-persistent save
|
|
83
|
+
|
|
84
|
+
4. Save rules (RHEL/CentOS):
|
|
85
|
+
sudo service iptables save
|
|
86
|
+
|
|
87
|
+
5. Verify rules:
|
|
88
|
+
sudo iptables -L -n -v
|
|
89
|
+
|
|
90
|
+
6. Make persistent across reboots:
|
|
91
|
+
sudo systemctl enable iptables
|
|
92
|
+
sudo systemctl enable ip6tables
|
|
93
|
+
|
|
94
|
+
EOF
|
|
95
|
+
;;
|
|
96
|
+
esac
|
|
97
|
+
|
|
98
|
+
exit 0
|