Back to skill

Security audit

Clawket

Security checks for vulnerabilities and agentic risk

Overview

This skill does what it claims, but it handles a live gateway login token too loosely and includes a script injection flaw that should be reviewed before installation.

Install only if you are comfortable with a skill reading your OpenClaw Gateway auth token. Treat any generated QR image or terminal QR as a password, avoid running it in logged or shared terminals, delete ~/.openclaw/media/clawket-qr.png after pairing, and rotate the Gateway token if the payload has been exposed. The script should be fixed to avoid printing the token, set restrictive file permissions, clean up the QR, and pass config values to Python as data rather than source code.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (3)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/gateway-qr.sh:81
Finding
Arbitrary Python Code Execution Through Unescaped Configuration Values<![CDATA[ ## Vulnerability Details **File Location**: `scripts/gateway-qr.sh`, lines 22-31 and 81-89 **Vulnerability Type**: Python source injection through unsafe shell interpolation **Risk Level**: High ### Vulnerable Code ```bash TOKEN=$(python3 -c " import json, sys try: c = json.load(open('$CONFIG')) print(c['gateway']['auth']['token']) except Exception as e: print(f'Error: {e}', file=sys.stderr) sys.exit(1) ") PORT=$(python3 -c " import json c = json.load(open('$CONFIG')) print(c.get('gateway', {}).get('port', 18789)) ") ``` ```bash PAYLOAD=$(python3 -c " import json print(json.dumps({ 'host': '$LAN_IP', 'port': int('$PORT'), 'token': '$TOKEN', 'tls': False }, separators=(',', ':'))) ") ``` ### Technical Analysis The script constructs executable Python source by directly interpolating shell variables into a `python3 -c` program. In particular, `TOKEN` and `PORT` originate from `~/.openclaw/openclaw.json` and are embedded inside single-quoted Python string literals without escaping. A token containing quote characters and a valid Python expression can terminate or alter the intended literal. For example, a value shaped like: ```text ' + str(__import__("os").system("COMMAND")) + ' ``` would cause the generated Python program to evaluate `os.system("COMMAND")` while constructing the dictionary. The exact payload must be represented using valid JSON escaping in the configuration file. The configuration path is also interpolated into Python source at `open('$CONFIG')`. Consequently, a specially crafted `HOME` value containing Python syntax presents an additional injection surface if the resulting configuration path can be created. This is source-code injection rather than ordinary malformed-input handling: attacker-controlled data changes the Python program executed by `python3 -c`. ### Attack Path 1. An attacker, compromised integration, or less-trusted process gains the ability to modify `~/.openclaw/openclaw.json` ...[truncated 1192 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Never insert shell-expanded values into executable Python source. - Load the configuration and construct the payload in a single statically quoted Python program. - Pass the configuration path through `sys.argv` or an environment variable instead of embedding it in source. - Validate the port as an integer from `1` through `65535`. - Validate the detected host with Python's `ipaddress.ip_address()` before using it. - Treat the token exclusively as data and let `json.dumps()` perform all required JSON escaping. A safer pattern is: ```bash PAYLOAD=$( python3 - "$CONFIG" "$LAN_IP" <<'PY' import ipaddress import json import sys config_path, host = sys.argv[1], sys.argv[2] with open(config_path, encoding="utf-8") as config_file: config = json.load(config_file) token = config["gateway"]["auth"]["token"] port = int(config.get("gateway", {}).get("port", 18789)) if not isinstance(token, str) or not token: raise ValueError("Gateway token must be a non-empty string") if not 1 <= port <= 65535: raise ValueError("Gateway port is outside the valid range") ipaddress.ip_address(host) print(json.dumps({ "host": host, "port": port, "token": token, "tls": False, }, separators=(",", ":"))) PY ) ``` This keeps configuration values outside the Python grammar and prevents them from becoming executable code. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/gateway-qr.sh:91
Finding
Gateway Authentication Token Disclosed Through Terminal Output<![CDATA[ ## Vulnerability Details **File Location**: `scripts/gateway-qr.sh`, lines 91-93 and 110-112 **Vulnerability Type**: Plaintext sensitive-data exposure **Risk Level**: Medium ### Vulnerable Code ```bash echo "Gateway: ws://$LAN_IP:$PORT" echo "Payload: $PAYLOAD" echo "" ``` ```bash # ASCII to terminal qrencode -t UTF8 -m 1 "$PAYLOAD" ``` ### Technical Analysis `PAYLOAD` contains the Gateway authentication token: ```json { "host": "192.168.1.100", "port": 18789, "token": "...", "tls": false } ``` The script prints this complete payload directly to standard output. It then renders the same token-bearing payload as an ASCII QR code. Both actions expose a bearer credential beyond what is necessary to create the PNG. Terminal output may be retained in shell scrollback, AI Agent execution transcripts, CI logs, remote-session recordings, support bundles, or other command-capture systems. The ASCII QR also permits token recovery by anyone who can view or capture the terminal. ### Attack Path 1. A user or Agent invokes the QR-generation script in a shared, recorded, or logged terminal environment. 2. The script writes the complete token-bearing JSON payload and its scannable ASCII QR representation to standard output. 3. Another user, log reader, session observer, or process with access to captured command output obtains the payload. 4. The observer reads the token directly or decodes it from the QR. 5. If the Gateway is reachable, the observer uses the token to authenticate as the legitimate user. ### Impact Assessment Disclosure can permit unauthorized authentication to the local OpenClaw Gateway for as long as the exposed token remains valid. The resulting scope depends on the permissions associated with the Gateway token and the Gateway's network reachability. This issue does not itself grant operating-system privileges, but it can expose all Gateway operations authorized by the bearer token. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions - Remove `echo "Payload: $PAYLOAD"` entirely. - Do not render an ASCII QR by default. - If terminal rendering is required, place it behind an explicit option such as `--show-terminal-qr` and display a warning that the QR contains a bearer credential. - Ensure diagnostics only display non-sensitive values such as the host, port, and output path. - Avoid executing the pairing workflow in shared terminals, CI systems, or recorded sessions. - Rotate the Gateway token if it has already appeared in logs or transcripts. - Prefer a short-lived, single-use pairing token instead of embedding the persistent Gateway authentication token. For example: ```bash echo "Gateway: ws://$LAN_IP:$PORT" echo "QR code saved to: $OUT_FILE" if [[ "${SHOW_TERMINAL_QR:-0}" == "1" ]]; then echo "Warning: This QR contains an authentication credential." >&2 qrencode -t UTF8 -m 1 "$PAYLOAD" fi ``` ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/gateway-qr.sh:7
Finding
Persistent Token-Bearing QR File Created Without Explicit Access Controls<![CDATA[ ## Vulnerability Details **File Location**: `scripts/gateway-qr.sh`, lines 7-11 and 106-107; delivery behavior documented in `SKILL.md`, lines 20-25 **Vulnerability Type**: Insecure storage and transmission of authentication material **Risk Level**: Medium ### Vulnerable Code ```bash CONFIG="$HOME/.openclaw/openclaw.json" OUT_DIR="$HOME/.openclaw/media" OUT_FILE="$OUT_DIR/clawket-qr.png" mkdir -p "$OUT_DIR" ``` ```bash # PNG file qrencode -o "$OUT_FILE" -s 10 -m 2 -l M "$PAYLOAD" echo "QR code saved to: $OUT_FILE" ``` The corresponding Skill instructions state: ```markdown 3. Generate a QR code as a PNG image at `~/.openclaw/media/clawket-qr.png` 4. Also print an ASCII QR code to the terminal Send the PNG to the user via the `message` tool (`filePath: ~/.openclaw/media/clawket-qr.png`). ``` ### Technical Analysis The generated PNG encodes the Gateway bearer token and should therefore receive the same protection as a plaintext credential. The script creates the output directory and file without setting an explicit restrictive `umask` or enforcing directory and file modes. Actual permissions consequently depend on the caller's environment and `qrencode` behavior. Under a permissive umask, other local accounts or processes may be able to read the token-bearing image. The image also persists at a predictable path after pairing and may be collected by backups, indexing services, support tools, or later processes. In addition, the Skill directs the Agent to send this sensitive file through the `message` tool without documenting recipient confirmation, expiration, cleanup, or token rotation. ### Attack Path 1. The Skill runs under an environment with permissive file-creation settings, or the QR remains at its predictable path after use. 2. The bearer-token QR is written to `~/.openclaw/media/clawket-qr.png`. 3. Another local account, unintended process, backup system, or indexing service obtains the file; alternatively, the file is sent to the wr ...[truncated 720 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Set a restrictive umask before creating the directory or image: ```bash umask 077 mkdir -p "$OUT_DIR" chmod 700 "$OUT_DIR" ``` - After QR generation, explicitly enforce owner-only access: ```bash chmod 600 "$OUT_FILE" ``` - Confirm the intended recipient before sending the image through any messaging tool. - Remove the image immediately after successful delivery or after a short timeout. - Add cleanup handling for normal exit and interruption where operationally appropriate. - Avoid storing the QR at a long-lived predictable path; use an owner-only temporary directory. - Prefer a short-lived, single-use pairing credential that expires automatically and cannot be reused as the persistent Gateway token. - Document that the QR is sensitive authentication material and must not be forwarded, archived, or included in support bundles. - Rotate or revoke the token if the image is accidentally disclosed. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (5)

Missing User Warnings

Medium
Confidence
97% confidence
Finding
This skill explicitly generates and sends a QR code containing a live Gateway auth token, but it provides no warning that the PNG and terminal-rendered QR are effectively bearer credentials. A user could forward, screenshot, store, or display the code insecurely, allowing anyone who scans it to authenticate to the local OpenClaw Gateway.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
## Troubleshooting

- If `qrencode` is not installed: `brew install qrencode` (macOS) / `sudo apt install qrencode` (Linux) / `choco install qrencode` (Windows)
- If the LAN IP detection fails, the script falls back to `127.0.0.1`
- The token is read directly from the JSON config file (not via `openclaw config get` which redacts it)
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
## Troubleshooting

- If `qrencode` is not installed: `brew install qrencode` (macOS) / `sudo apt install qrencode` (Linux) / `choco install qrencode` (Windows)
- If the LAN IP detection fails, the script falls back to `127.0.0.1`
- The token is read directly from the JSON config file (not via `openclaw config get` which redacts it)
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Context-Inappropriate Capability

Medium
Confidence
98% confidence
Finding
The script prints the full QR payload to the terminal, and that payload contains the gateway authentication token. Anyone with terminal visibility, shell history capture, screen recording, logging, or shoulder-surfing access can recover the token and authenticate to the local gateway, which exceeds the stated need of simply generating a QR code.

Missing User Warnings

Medium
Confidence
98% confidence
Finding
The terminal output discloses a sensitive bearer-style token without warning or minimization, creating an unnecessary secret exposure channel. In practice, terminals are often logged, copied into support chats, or visible to other local users, so disclosure can lead to unauthorized mobile pairing or gateway access.

Static analysis

No suspicious patterns detected.