Back to skill

Security audit

Mission Control

Security checks for vulnerabilities and agentic risk

Overview

This monitoring skill mostly does what it says, but it gives an agent broad host inspection and sudo-backed service restart ability without strong built-in limits.

Install only if you are comfortable with the agent seeing local process, port, cron, service, and recent journal information. Do not allow automated or ambiguous prompts to run `restart`; restrict use to trusted operators, prefer OpenClaw-specific service names, and review sudo policy before enabling this skill.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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
Findings (2)

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/mctl.sh:225
Finding
Unrestricted Systemd Unit Selection Enables Unauthorized Log Access and Service Restart Attempts<![CDATA[ ## Vulnerability Details **File Location**: `scripts/mctl.sh:225-248` **Vulnerability Type**: Missing authorization and allowlist validation for systemd unit names **Risk Level**: Medium ### Vulnerable Code ```bash show_logs() { local name="${EXTRA_ARG:-openclaw-daemon}" if systemctl is-active "$name" >/dev/null 2>&1 || systemctl is-failed "$name" >/dev/null 2>&1; then journalctl -u "$name" --no-pager -n 50 --since "1 hour ago" 2>/dev/null || \ echo "No journalctl logs for $name" else # Try openclaw logs if command -v openclaw >/dev/null 2>&1; then openclaw logs --tail 50 2>/dev/null || echo "No logs found for $name" else echo "Service '$name' not found and openclaw CLI not available" fi fi } do_restart() { local name="${EXTRA_ARG:-}" if [ -z "$name" ]; then echo "Usage: mctl restart <service-name>" exit 1 fi echo -e "${YELLOW}Restarting $name...${RESET}" sudo systemctl restart "$name" 2>/dev/null && \ echo -e "${GREEN}Restarted $name${RESET}" || \ echo -e "${RED}Failed to restart $name${RESET}" } ``` ### Technical Analysis The `logs` and `restart` commands accept an arbitrary value from `EXTRA_ARG` and forward it to `systemctl`, `journalctl`, or `sudo systemctl` without restricting the value to services within the skill's stated OpenClaw scope. Shell metacharacter injection is mitigated because `"$name"` is quoted. However, quoting does not provide authorization: any valid systemd unit name remains selectable. Consequently, the skill may inspect unrelated service journals or request restarts of security-critical services. The documentation states that restart operations require user confirmation, but the implementation contains no confirmation prompt or explicit confirmation flag. It immediately executes `sudo systemctl restart` after checking only that the argument is nonempty. Actual success remains constrained by the invoking account's journal permissions and sudo poli ...[truncated 1886 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Restrict service names to an explicit allowlist: ```bash validate_service() { case "$1" in openclaw-daemon|openclaw-gateway) return 0 ;; *) printf 'Unsupported service: %s\n' "$1" >&2 return 1 ;; esac } ``` 2. Call the validator before every `systemctl` and `journalctl` operation: ```bash validate_service "$name" || exit 1 ``` 3. Reject option-like arguments beginning with `-`, even when commands currently quote the argument: ```bash [[ "$name" != -* ]] || { echo "Invalid service name" >&2 exit 1 } ``` 4. Require explicit confirmation before restart. For interactive use, read an exact confirmation response from a terminal. For automation, require a deliberate flag such as: ```bash mctl restart --confirm openclaw-daemon ``` 5. Avoid invoking unrestricted `sudo`. Configure a narrowly scoped sudoers rule permitting only the exact required actions and unit names. 6. Where feasible, run the monitoring commands under a dedicated low-privilege account with access only to OpenClaw service information. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/mctl.sh:74
Finding
Process Metadata Is Emitted Without Safe JSON or Terminal Encoding<![CDATA[ ## Vulnerability Details **File Location**: `scripts/mctl.sh:74-94` **Vulnerability Type**: Improper output encoding and terminal control-sequence injection **Risk Level**: Medium ### Vulnerable Code ```bash # Node/python agents (generic detection - skip kernel threads and this script) while IFS= read -r line; do local pid name uptime_info pid=$(echo "$line" | awk '{print $1}') name=$(echo "$line" | awk '{for(i=2;i<=NF;i++) printf $i" "; print ""}' | sed 's/ *$//' | head -c 60) # Skip kernel threads (enclosed in brackets) and self [[ "$name" =~ ^\[ ]] && continue [[ "$name" =~ mctl\.sh ]] && continue uptime_info=$(ps -p "$pid" -o etime= 2>/dev/null | xargs) agents+=("{\"name\":\"$(echo "$name" | sed 's/"/\\"/g')\",\"pid\":$pid,\"uptime\":\"$uptime_info\",\"status\":\"running\"}") done < <(pgrep -af "(agent|daemon|worker|aoms)" 2>/dev/null | grep -v "grep\|mctl\|pgrep" | head -20 || true) if $JSON_MODE; then echo "[$(IFS=,; echo "${agents[*]:-}")]}]" | sed 's/\]}]/]/' else if [ ${#agents[@]} -eq 0 ]; then echo -e " ${YELLOW}No agent processes detected${RESET}" else for a in "${agents[@]}"; do local name pid uptime_val name=$(echo "$a" | grep -oP '"name":"[^"]*"' | cut -d'"' -f4) pid=$(echo "$a" | grep -oP '"pid":[0-9]*' | cut -d: -f2) uptime_val=$(echo "$a" | grep -oP '"uptime":"[^"]*"' | cut -d'"' -f4) echo -e " ${GREEN}*${RESET} ${BOLD}$name${RESET} PID=$pid uptime=$uptime_val" done fi fi ``` ### Technical Analysis The collector obtains process command lines through `pgrep -af`. Process names and arguments are controlled by the local user who launches each process and must therefore be treated as untrusted data. For JSON output, the code escapes only double quotation marks: ```bash sed 's/"/\\"/g' ``` Correct JSON string encoding must also handle backslashes, control characters, newlines, tabs, carriage returns, and other ...[truncated 2447 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Stop constructing JSON through shell string concatenation. Pass process records to a serializer such as Python's `json` module or `jq`. 2. Represent process information as structured fields before serialization. For example, provide values to Python through arguments or a safely delimited stream and use: ```python json.dumps({ "name": name, "pid": pid, "uptime": uptime, "status": "running" }) ``` 3. Do not parse generated JSON using `grep`, `cut`, or regular expressions. Retain the original shell fields for text output, or parse JSON with a genuine JSON parser. 4. Replace `echo -e` when rendering untrusted data with `printf`: ```bash printf ' %s PID=%s uptime=%s\n' "$safe_name" "$pid" "$uptime_info" ``` 5. Remove or visibly encode non-printable terminal control characters before display. For example, permit a defined printable character set or render unsafe bytes using escaped notation. 6. Validate that PIDs are numeric and keep command-line data separate from control or formatting strings. 7. Add tests covering quotation marks, backslashes, tabs, newlines, carriage returns, Unicode, and ANSI escape sequences. Verify generated output with a strict JSON parser. ]]>
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (7)

Description-Behavior Mismatch

High
Confidence
96% confidence
Finding
The manifest describes a status/health aggregation tool for querying processes, resources, cron jobs, and services. However, the documented CLI includes a restart command, and the implementation later invokes privileged service modification rather than only inspection, which expands the behavior beyond aggregation/monitoring.

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
The script performs a state-changing administrative action by restarting arbitrary systemd services via sudo, which exceeds a read-only health aggregation role. In an autonomous-agent context, this can be triggered without adequate human confirmation and may disrupt critical services or be abused to interfere with system availability.

Lp3

Medium
Category
MCP Least Privilege
Confidence
86% confidence
Finding
The skill exposes operational shell commands and clearly relies on environment/system access, but it does not declare any explicit tool scope or permissions boundary. In an agent ecosystem, this can cause the skill to run with broader-than-expected host visibility, increasing the chance of unintended access to process lists, service metadata, ports, logs, and other sensitive system information.

Vague Triggers

Medium
Confidence
92% confidence
Finding
The description contains broad trigger language such as 'system status,' 'agent health,' 'resource monitoring,' and 'inspect autonomous systems,' which can match many normal user requests. This raises the risk of unintended activation, causing the agent to invoke a powerful system-inspection skill in contexts where the user did not explicitly ask for host-level enumeration.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The restart flow executes a privileged, system-level change without explicit confirmation, policy checks, or guardrails. In an agent-driven environment, a user prompt or upstream tool misuse could cause unintended restarts, service interruption, or repeated availability impacts.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
exit 1
  fi
  echo -e "${YELLOW}Restarting $name...${RESET}"
  sudo systemctl restart "$name" 2>/dev/null && \
    echo -e "${GREEN}Restarted $name${RESET}" || \
    echo -e "${RED}Failed to restart $name${RESET}"
}
Confidence
92% confidence
Finding
Invoking sudo from within the skill introduces a privileged execution path. Even though the service name is quoted and command injection risk is reduced, granting an agent-accessible tool sudo-backed restart ability can materially increase blast radius if the tool is misused or integrated into automated workflows.

Vague Triggers

Low
Confidence
89% confidence
Finding
The example guidance uses everyday phrases like 'what's running?' and 'system status' as direct triggers for executing the full status command. While operationally convenient, these vague examples can over-broaden routing and lead to unnecessary collection of system details when a user may only be asking a high-level or conceptual question.

Static analysis

No suspicious patterns detected.