Ae1
- Category
- analysis-evasion
- Confidence
- 100% confidence
- Finding
Referenced artifact was not completely inspected
- Content
md bash tests/test_overseer.sh
Security audit
Security checks for vulnerabilities and agentic risk
This is a disclosed local sub-agent monitoring daemon; its main risk is that it records local filename metadata unless users opt out.
Install only if you want a local background monitor for OpenClaw sub-agents. Use a narrow --workdir, consider --no-filenames for sensitive work, avoid --voice-files in shared spaces, and use --stop or --cleanup when monitoring is no longer needed.
Referenced artifact was not completely inspected
bash tests/test_overseer.sh
Tool calls are chained to bypass individual safety checks or escalate capabilities beyond what any single tool call would allow.
WDIR=""
teardown() {
[ -n "$SDIR" ] && bash "$OVERSEER" --status-dir "$SDIR" --cleanup >/dev/null 2>&1
[ -n "$WDIR" ] && rm -rf "$WDIR"
SDIR=""; WDIR=""
}
trap teardown EXIT
Tool calls are chained to bypass individual safety checks or escalate capabilities beyond what any single tool call would allow.
WDIR=""
teardown() {
[ -n "$SDIR" ] && bash "$OVERSEER" --status-dir "$SDIR" --cleanup >/dev/null 2>&1
[ -n "$WDIR" ] && rm -rf "$WDIR"
SDIR=""; WDIR=""
}
trap teardown EXIT
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).
echo "== an unsafe status directory is refused, not silently chmod-ed"
BASE="$(mktemp -d)"
mkdir -m 777 "$BASE/open"
chmod 777 "$BASE/open"
bash "$OVERSEER" --status-dir "$BASE/open" --status-path >/dev/null 2>&1
check "$?" "1" "a group/world-accessible status dir is refused"
check "$(stat -c '%a' "$BASE/open")" "777" "and its mode was left alone"
The skill clearly instructs use of shell capabilities (setsid, background daemon management, reading /proc, file operations), but it does not declare any tool scope or allowed-tools metadata. That mismatch weakens policy enforcement and review because an agent may execute shell actions the manifest does not explicitly authorize, increasing the chance of unintended process control or filesystem access.
The skill intentionally launches a detached background process with setsid ... &, creating persistence beyond the immediate agent action. Even though the document describes stop/cleanup controls, persistent daemons are inherently riskier because they can continue monitoring processes and filesystem activity after the initiating context ends, and users may forget they are running.
setsid scripts/overseer.sh \
--workdir /path/to/repo \
--interval 180 \
--max-stale 4 \
The manifest description presents the skill as limited to OS-level process checks without polling, but the implementation repeatedly loops (while true) and, on each cycle, calls openclaw sessions list and scans the workdir with find to track file changes. Those behaviors go beyond simple process existence checks and contradict the advertised narrow monitoring model.
The help text states “Writes only inside the status directory,” which implies a narrowly scoped local-state behavior, but the script actively inspects WORKDIR via find, reads process metadata from /proc, and queries openclaw sessions list. While the claim is literally about writes, in context it understates the script’s actual operational scope and conflicts with the surrounding intent description of a minimal monitor.
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
return 1
fi
if (( (8#$mode & 8#077) != 0 )); then
echo "Refusing status dir $STATUS_DIR: mode $mode allows other users in (chmod 700 it, or pick another --status-dir)." >&2
return 1
fi
return 0
When --voice-files is enabled, the script reads recent filenames from the watched workdir and speaks them aloud via jarvis in a detached process. This can expose sensitive project names, customer identifiers, incident names, or other confidential metadata to anyone nearby, and the detached invocation makes the disclosure occur asynchronously outside the immediate command flow.
# announcing what you are working on is a different consent decision
# from a status file on your own disk.
if [[ "$VOICE_FILES" == "true" && -n "$RECENT" ]]; then
setsid jarvis "$SUBAGENT_COUNT agents active. $CHANGED files changed: $RECENT." 200>&- &>/dev/null &
else
setsid jarvis "$SUBAGENT_COUNT agents active. $CHANGED files changed." 200>&- &>/dev/null &
fi
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.
# Start the daemon and wait for the first status file. Interval is long enough
# that it is still alive when the lifecycle assertions run.
start_daemon() {
setsid bash "$OVERSEER" --status-dir "$SDIR" --workdir "$WDIR" \
--interval 5 "$@" >/dev/null 2>&1 &
for _ in $(seq 1 60); do
[ -s "$SDIR/status.json" ] && return 0
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.
# Start the daemon and wait for the first status file. Interval is long enough
# that it is still alive when the lifecycle assertions run.
start_daemon() {
setsid bash "$OVERSEER" --status-dir "$SDIR" --workdir "$WDIR" \
--interval 5 "$@" >/dev/null 2>&1 &
for _ in $(seq 1 60); do
[ -s "$SDIR/status.json" ] && return 0
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.
# Start the daemon and wait for the first status file. Interval is long enough
# that it is still alive when the lifecycle assertions run.
start_daemon() {
setsid bash "$OVERSEER" --status-dir "$SDIR" --workdir "$WDIR" \
--interval 5 "$@" >/dev/null 2>&1 &
for _ in $(seq 1 60); do
[ -s "$SDIR/status.json" ] && return 0
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.
# Start the daemon and wait for the first status file. Interval is long enough
# that it is still alive when the lifecycle assertions run.
start_daemon() {
setsid bash "$OVERSEER" --status-dir "$SDIR" --workdir "$WDIR" \
--interval 5 "$@" >/dev/null 2>&1 &
for _ in $(seq 1 60); do
[ -s "$SDIR/status.json" ] && return 0
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.
# Start the daemon and wait for the first status file. Interval is long enough
# that it is still alive when the lifecycle assertions run.
start_daemon() {
setsid bash "$OVERSEER" --status-dir "$SDIR" --workdir "$WDIR" \
--interval 5 "$@" >/dev/null 2>&1 &
for _ in $(seq 1 60); do
[ -s "$SDIR/status.json" ] && return 0
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.
# Start the daemon and wait for the first status file. Interval is long enough
# that it is still alive when the lifecycle assertions run.
start_daemon() {
setsid bash "$OVERSEER" --status-dir "$SDIR" --workdir "$WDIR" \
--interval 5 "$@" >/dev/null 2>&1 &
for _ in $(seq 1 60); do
[ -s "$SDIR/status.json" ] && return 0
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
echo "== an unsafe status directory is refused, not silently chmod-ed"
BASE="$(mktemp -d)"
mkdir -m 777 "$BASE/open"
chmod 777 "$BASE/open"
bash "$OVERSEER" --status-dir "$BASE/open" --status-path >/dev/null 2>&1
check "$?" "1" "a group/world-accessible status dir is refused"
check "$(stat -c '%a' "$BASE/open")" "777" "and its mode was left alone"
No suspicious patterns detected.