Back to skill

Security audit

ClawCast

Security checks for vulnerabilities and agentic risk

Overview

This OBS automation skill is mostly purpose-aligned, but it needs Review because it can alter OBS scenes, start streaming, write an external config database, and expose more files over the local network than its docs suggest.

Install only if you are comfortable with an agent controlling OBS. Use it first against a test OBS profile, back up scenes and the agentic-obs database, do not run the streaming dry-run unless you intend to go live, keep the HTTP and OBS WebSocket ports off public networks, and avoid placing private files under the skill folder until the server is narrowed to assets/overlays or localhost.

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 (2)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/obs_target_switch.sh:7
Finding
SQL Injection in OBS Target Configuration Update## Vulnerability Details **File Location**: `scripts/obs_target_switch.sh`, lines 7-30 **Vulnerability Type**: SQL injection through unvalidated command-line arguments **Risk Level**: High **Vulnerable Code**: ```bash HOST="${1:-}" PORT="${2:-4455}" DB="${3:-}" ACK="${4:-}" if [[ -z "$HOST" || -z "$DB" ]]; then echo "Usage: ./scripts/obs_target_switch.sh <obs-host> [obs-port] <agentic-obs-db-path> --allow-cross-component-write" echo "Example: ./scripts/obs_target_switch.sh 192.168.1.50 4455 \"$HOME/.agentic-obs/db.sqlite\" --allow-cross-component-write" exit 1 fi if [[ ! -f "$DB" ]]; then echo "ERROR: DB file not found: $DB" exit 1 fi if [[ "$ACK" != "--allow-cross-component-write" ]]; then echo "ERROR: This script writes to an external agentic-obs DB." echo "Add explicit acknowledgement flag: --allow-cross-component-write" exit 1 fi sqlite3 "$DB" "update config set value='$HOST', updated_at=datetime('now') where key='obs_host';" sqlite3 "$DB" "update config set value='$PORT', updated_at=datetime('now') where key='obs_port';" ``` ### Technical Analysis The `HOST` and `PORT` command-line arguments are inserted directly into SQL string literals. Neither value is validated nor escaped before being passed to the SQLite command-line client. Shell quoting does not prevent this vulnerability because the injection occurs in the generated SQL statement rather than at the shell parsing layer. A value containing a single quote can terminate the intended SQL literal and append additional SQLite statements. For example, a malicious host shaped like: ```text x'; DELETE FROM config; -- ``` can transform the first update into multiple statements, including an attacker-supplied operation. The explicit `--allow-cross-component-write` acknowledgement controls whether the script proceeds, but it does not ensure that the resulting database operation is limited to the intended conf ...[truncated 1477 chars]
Remediation
## Remediation Suggestions 1. Replace SQL string interpolation with parameterized queries. A small Python helper using the standard `sqlite3` module can bind values safely: ```python import sqlite3 with sqlite3.connect(database_path) as connection: connection.execute( "UPDATE config SET value=?, updated_at=datetime('now') WHERE key=?", (host, "obs_host"), ) connection.execute( "UPDATE config SET value=?, updated_at=datetime('now') WHERE key=?", (str(port), "obs_port"), ) ``` 2. Validate `PORT` as an integer from 1 through 65535 before accessing the database. 3. Validate `HOST` as an IPv4 address, IPv6 address, or hostname using a strict parser. Reject quotes, control characters, whitespace, SQL metacharacters, and unexpected URL components. 4. Resolve the database path to a canonical path and, where practical, restrict it to the expected agentic-obs configuration location. 5. Verify the expected database schema and confirm that the `config` table and target keys exist before making changes. 6. Execute both updates within one transaction and roll back if either update fails. 7. Retain the acknowledgement flag as a defense against accidental cross-component writes, but do not treat it as an input-sanitization control.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/start_overlay_server.sh:4
Finding
LAN-Accessible HTTP Server Exposes the Entire Skill Directory## Vulnerability Details **File Location**: `scripts/start_overlay_server.sh`, lines 4-22 **Vulnerability Type**: Unnecessary file exposure and overly broad network binding **Risk Level**: Medium **Vulnerable Code**: ```bash SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SKILL_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" OVERLAY_ROOT="$SKILL_ROOT/assets/overlays" PORT="${OVERLAY_PORT:-8787}" LOG_DIR="$SKILL_ROOT/.runtime" LOG="$LOG_DIR/http-server.log" if [[ ! -d "$OVERLAY_ROOT" ]]; then echo "ERROR: overlay directory not found: $OVERLAY_ROOT" exit 1 fi mkdir -p "$LOG_DIR" if ss -ltn | grep -q ":$PORT "; then echo "Overlay server already listening on :$PORT" else # Security scope: serve skill-local overlays only (not workspace root). nohup python3 -m http.server "$PORT" --directory "$SKILL_ROOT" > "$LOG" 2>&1 & ``` ### Technical Analysis The script calculates the intended overlay directory in `OVERLAY_ROOT`, but starts the HTTP server with `SKILL_ROOT` as its document root. Consequently, the server exposes the complete skill package rather than only `assets/overlays`. Python's standard `http.server` binds to all available interfaces by default when no `--bind` argument is supplied. It also provides directory listings. Any host that can reach the configured port can therefore enumerate and download files under the skill root, including shell scripts, documentation, examples, assets, and files under `.runtime`. This behavior contradicts the source comment and documentation stating that only skill-local overlays are served. Although the audited package does not contain bundled credentials, future customization, additional files, or runtime logs could contain sensitive information. ### Attack Path 1. A user follows the documented workflow and runs `start_overlay_server.sh`. 2. The script launches a background HTTP server on port 8787, or the configured `OV ...[truncated 1151 chars]
Remediation
## Remediation Suggestions 1. Serve only the required overlay directory: ```bash python3 -m http.server "$PORT" \ --directory "$OVERLAY_ROOT" ``` 2. Bind explicitly to the minimum required interface. Use loopback when OBS runs locally: ```bash python3 -m http.server "$PORT" \ --bind 127.0.0.1 \ --directory "$OVERLAY_ROOT" ``` 3. For remote OBS, require an explicit bind address representing the trusted LAN or VPN interface instead of listening on every interface. 4. Enforce host firewall rules so that only the intended OBS host can access the overlay port. 5. Store runtime logs outside every served directory and ensure they use restrictive filesystem permissions. 6. Replace the development-oriented `http.server` with a narrowly configured static-file server if directory-listing prevention, authentication, TLS, or stronger access controls are needed. 7. Validate `OVERLAY_PORT` as an integer from 1 through 65535 and verify that an existing listener on that port is actually the expected overlay service rather than assuming any listener is safe.
Vulnerability Patterns
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (14)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The declared description presents a broader OBS automation skill centered on scene creation, optional cross-component configuration writes, and smoke testing. This code chunk only launches a local HTTP server and exposes LAN URLs for assets. While serving overlay/media content could be a supporting part of wiring browser sources over HTTP, the actual behavior shown is much narrower and does not implement the primary declared capabilities. Additionally, despite the comment claiming to serve only skill-local overlays, the server root is set to the entire skill root, which is broader than the overlay directory.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The page automatically polls a local screenshot service every 5 seconds without any user-facing notice or consent gate, causing continuous access to a monitor-capture endpoint on localhost. In the context of an OBS/control-panel overlay skill, this can expose sensitive on-screen content unexpectedly and normalize silent local monitoring, especially if the page is opened in a browser or embedded environment users assume is only a static UI.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
This script unconditionally deletes a fixed set of OBS scenes and recreates them, with no interactive confirmation, dry-run mode, or guardrail beyond switching away from one safe scene. In the context of an automation skill that directly manages OBS, this is a real safety issue because an agent or user invoking the script on the wrong instance can silently destroy existing scene configuration and disrupt ongoing production workflows.

Intent-Code Divergence

Medium
Confidence
98% confidence
Finding
The comment states the server is restricted to overlay assets, but the actual command serves the entire skill root via Python's HTTP server. This discrepancy can mislead reviewers and operators, causing unintended exposure of scripts, runtime artifacts, or other files under the skill directory over the LAN.

Session Persistence

Medium
Category
Rogue Agent
Content
echo "Overlay server already listening on :$PORT"
else
  # Security scope: serve skill-local overlays only (not workspace root).
  nohup python3 -m http.server "$PORT" --directory "$SKILL_ROOT" > "$LOG" 2>&1 &
  sleep 1
  echo "Started overlay server on :$PORT (root=$SKILL_ROOT)"
fi
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.

Description-Behavior Mismatch

Medium
Confidence
99% confidence
Finding
The script launches an HTTP server rooted at the full skill directory rather than the overlay assets directory. In this skill context, the server advertises a LAN-accessible URL, so any host on the local network may be able to browse and retrieve non-overlay files such as scripts, logs, or packaged configuration material, expanding the attack surface beyond the skill's stated purpose.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
This script initiates live streaming and switches scenes immediately without any interactive confirmation, explicit dry-run safety gate, or environment check to ensure it is targeting a non-production OBS instance. In the context of a reusable automation skill for local or remote OBS control, this can cause unintended public broadcasts, scene exposure, or disruption of a currently running production setup if invoked against the wrong host.

Natural-Language Policy Violations

Low
Confidence
86% confidence
Finding
The page declares `lang="en"` and later renders time with `toLocaleTimeString()` while presenting an English-only interface. This creates a natural-language/locale constraint without offering users a language or locale option or documenting why English is required.

Natural-Language Policy Violations

Low
Confidence
92% confidence
Finding
The document sets `lang="en"`, which imposes an English-language locale in the file without any visible opt-in or explanation. Under the policy rule, locale/language constraints should either offer user choice or be clearly justified as region-specific.

Intent-Code Divergence

Low
Confidence
95% confidence
Finding
The comments at L136-L138 state this is a static control panel with placeholder behavior for actual control. However, the page loads a real image from http://127.0.0.1:8765/screenshot/stream_monitor and auto-refreshes it every 5 seconds, which is active runtime interaction with a backend service rather than purely static placeholder UX.

Natural-Language Policy Violations

Low
Confidence
94% confidence
Finding
The document declares `lang="en"`, which hard-codes English as the content language. Under the policy criteria, forcing a specific language without user opt-in or a documented justification is a natural-language policy concern.

Natural-Language Policy Violations

Low
Confidence
89% confidence
Finding
The document declares `lang="en"`, which hard-codes English as the page language. Under the stated policy, forcing a specific language without user opt-in or a documented region-specific justification is a natural-language policy violation.

Natural-Language Policy Violations

Low
Confidence
89% confidence
Finding
The document declares `lang="en"`, which hard-codes English as the language/locale for the skill content. Under the policy criteria, forcing a specific language without user opt-in or a documented justification is a natural-language policy issue.

Natural-Language Policy Violations

Low
Confidence
83% confidence
Finding
The call to toLocaleTimeString() relies on the runtime's implicit locale, which bakes locale-dependent formatting into the skill without any explicit user opt-in or documented choice. Under the stated policy, locale behavior should either be user-selectable or clearly justified.

Static analysis

No suspicious patterns detected.