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

Content
View full analysis

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
View 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

Content
View full analysis

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

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

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/start_overlay_server.sh (reported line 22)May include surrounding context.

sh
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

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.