Back to skill

Security audit

TinkerClaw Subagent Overseer

Security checks for vulnerabilities and agentic risk

Overview

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.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (17)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 161)May include surrounding context.

md
bash tests/test_overseer.sh

Chaining Abuse

High
Category
Tool Misuse
Confidence
75% confidence
Finding

Tool calls are chained to bypass individual safety checks or escalate capabilities beyond what any single tool call would allow.

Content

Scanner excerpt · scripts/overseer.sh (reported line 258)May include surrounding context.

sh
WDIR=""
teardown() {
    [ -n "$SDIR" ] && bash "$OVERSEER" --status-dir "$SDIR" --cleanup >/dev/null 2>&1
    [ -n "$WDIR" ] && rm -rf "$WDIR"
    SDIR=""; WDIR=""
}
trap teardown EXIT

Chaining Abuse

High
Category
Tool Misuse
Confidence
75% confidence
Finding

Tool calls are chained to bypass individual safety checks or escalate capabilities beyond what any single tool call would allow.

Content

Scanner excerpt · tests/test_overseer.sh (reported line 25)May include surrounding context.

sh
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 Parameter Abuse

High
Category
Tool Misuse
Confidence
90% confidence
Finding

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).

Content

Scanner excerpt · tests/test_overseer.sh (reported line 140)May include surrounding context.

sh
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"

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding

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.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
84% confidence
Finding

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.

Content

Scanner excerpt · SKILL.md (reported line 57)May include surrounding context.

1. Start the overseer when spawning sub-agents

bash
setsid scripts/overseer.sh \
  --workdir /path/to/repo \
  --interval 180 \
  --max-stale 4 \

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

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.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

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.

Content

No source excerpt is available for this finding.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · scripts/overseer.sh (reported line 144)May include surrounding context.

sh
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

Session Persistence

Medium
Category
Rogue Agent
Confidence
84% confidence
Finding

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.

Content

Scanner excerpt · scripts/overseer.sh (reported line 435)May include surrounding context.

sh
# 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

Session Persistence

Medium
Category
Rogue Agent
Confidence
65% confidence
Finding

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.

Content

Scanner excerpt · scripts/overseer.sh (reported line 428)May include surrounding context.

sh
# 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

Session Persistence

Medium
Category
Rogue Agent
Confidence
65% confidence
Finding

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.

Content

Scanner excerpt · scripts/overseer.sh (reported line 437)May include surrounding context.

sh
# 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

Session Persistence

Medium
Category
Rogue Agent
Confidence
65% confidence
Finding

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.

Content

Scanner excerpt · scripts/overseer.sh (reported line 443)May include surrounding context.

sh
# 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

Session Persistence

Medium
Category
Rogue Agent
Confidence
65% confidence
Finding

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.

Content

Scanner excerpt · tests/test_overseer.sh (reported line 39)May include surrounding context.

sh
# 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

Session Persistence

Medium
Category
Rogue Agent
Confidence
65% confidence
Finding

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.

Content

Scanner excerpt · tests/test_overseer.sh (reported line 169)May include surrounding context.

sh
# 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

Session Persistence

Medium
Category
Rogue Agent
Confidence
65% confidence
Finding

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.

Content

Scanner excerpt · tests/test_overseer.sh (reported line 190)May include surrounding context.

sh
# 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

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · tests/test_overseer.sh (reported line 140)May include surrounding context.

sh
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"

Static analysis

No suspicious patterns detected.