Back to skill

Security audit

Content Automator

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly aligned with its video-generation purpose, but it sends generated text to ElevenLabs and has a real FFmpeg title-handling flaw that merits manual review before use.

Install only if you are comfortable sending generated script text to ElevenLabs and creating publishable files that may include portfolio values. Avoid using real financial data unless you have reviewed the generated script first, and avoid untrusted or punctuation-heavy video titles until the FFmpeg drawtext handling is fixed.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/content_automator.py:136
Finding
Unescaped User-Controlled Title Enables FFmpeg Filtergraph Injection## Vulnerability Details **File Location**: `scripts/content_automator.py`, lines 136–142 **Vulnerability Type**: FFmpeg filtergraph injection **Risk Level**: Medium **Vulnerable Code**: ```python ffmpeg_cmd = [ "ffmpeg", "-y", "-f", "lavfi", "-i", f"color=c=black:s=1920x1080:d={audio_duration}", "-i", str(audio_path), "-vf", f"drawtext=text='{title}':fontsize=48:fontcolor=white:x=(w-text_w)/2:y=(h-text_h)/2", "-c:v", "libx264", "-preset", "fast", "-crf", "23", "-c:a", "aac", "-b:a", "128k", "-shortest", str(output_path) ] ``` ### Technical Analysis The `title` parameter is incorporated directly into an FFmpeg `-vf` filtergraph expression without escaping FFmpeg filtergraph metacharacters. For the `script` command, this value originates from the user-controlled `--title` argument and reaches `assemble_video()` at lines 222–223. Passing the command as an argument list correctly prevents conventional shell command injection. It does not, however, prevent injection into FFmpeg's own expression and filtergraph grammar. Characters such as single quotes, colons, commas, semicolons, and backslashes can terminate or modify the `drawtext` expression. FFmpeg expansion syntax may also cause unintended interpretation. An attacker who can control the title can therefore invalidate the graph or attempt to append additional filters supported by the installed FFmpeg build. The exact secondary effects depend on available FFmpeg filters, protocols, and operating-system permissions. ### Attack Path 1. An attacker supplies a crafted value through the `script --title` command-line argument. 2. `cmd_script()` passes `args.title` unchanged to `assemble_video()` at lines 222–223. 3. `assemble_video()` concatenates the value into the `drawtext` filter expression at line 139. 4. FFmpeg parses attacker-supplied metacharacters as filtergraph syntax rather than literal title text. 5. The crafted grap ...[truncated 901 chars]
Remediation
## Remediation Suggestions - Do not concatenate untrusted titles directly into an FFmpeg filtergraph. - Store the title in a controlled UTF-8 temporary text file and reference it through `drawtext`'s `textfile` option. - Disable text expansion with `expansion=none` where supported and suitable. - Properly escape both the text-file path and all FFmpeg filtergraph metacharacters; argument-list execution alone is insufficient. - Apply a reasonable title-length limit and reject control characters or unsupported Unicode sequences before invoking FFmpeg. - Run FFmpeg with least privilege in a sandbox or restricted container with minimal filesystem and network access. - Restrict unnecessary FFmpeg protocols and capabilities, such as through an appropriate `-protocol_whitelist`, after verifying the protocols required by the intended workflow. - Add tests using titles containing quotes, colons, commas, semicolons, brackets, percent signs, and backslashes to verify they are rendered literally rather than parsed as filter syntax.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (10)

Tp4

High
Category
MCP Tool Poisoning
Confidence
91% confidence
Finding
The SKILL.md description overstates implemented functionality and understates sensitive behavior, especially external API use and API key dependency. This misrepresentation can cause users or automated policy systems to approve a skill under false assumptions, leading to unintended data exposure when content and secrets are sent to third-party services.

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill advertises capabilities that require access to environment variables, filesystem, network, and shell execution, but it does not declare an explicit tool/permission scope. This creates an authorization and review gap: operators cannot reliably constrain what the skill may access, and dangerous capabilities like network egress and subprocess execution may be granted implicitly.

External Transmission

Medium
Category
Data Exfiltration
Content
import requests

# Constants
ELEVENLABS_API = "https://api.elevenlabs.io/v1"
DEFAULT_VOICE = "pNInz6obpgDQGcFmaJgB"  # Crusty's configured voice
TEMPLATES_DIR = Path(__file__).parent.parent / "data" / "templates"
ASSETS_DIR = Path(__file__).parent.parent / "assets"
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
The code explicitly sets the ElevenLabs model to "eleven_monolingual_v1", which imposes a single-language behavior on all generated audio. There is no argument, configuration, or documented opt-in allowing users to choose a different language or locale, which creates a language-policy concern.

External Transmission

Medium
Category
Data Exfiltration
Content
}
    
    try:
        response = requests.post(url, json=data, headers=headers, timeout=60)
        response.raise_for_status()
        
        output_path.parent.mkdir(parents=True, exist_ok=True)
Confidence
93% confidence
Finding
The tool sends full script content to the ElevenLabs API, which may include locally sourced portfolio or other sensitive information. In this skill's context, that external transmission is significant because users may not realize their local financial data is being uploaded to a third-party service during TTS generation.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
"-of", "default=noprint_wrappers=1:nokey=1", str(audio_path)
    ]
    try:
        result = subprocess.run(probe_cmd, capture_output=True, text=True, check=True)
        audio_duration = float(result.stdout.strip())
    except Exception:
        audio_duration = duration
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
]
    
    try:
        subprocess.run(ffmpeg_cmd, capture_output=True, check=True)
        return True
    except subprocess.CalledProcessError as e:
        print(f"ffmpeg error: {e}")
Confidence
87% confidence
Finding
Although ffmpeg is launched without a shell, the drawtext filter embeds the untrusted title directly into the ffmpeg filter expression. A crafted title containing quotes, colons, backslashes, or filter syntax can break the expression, cause unexpected ffmpeg behavior, or potentially trigger dangerous ffmpeg protocol/filter features depending on build and environment.

Description-Behavior Mismatch

Medium
Confidence
90% confidence
Finding
Trading mode reads a local dashboard file that may contain sensitive financial information and incorporates account values into generated script text, metadata, audio, and video output. In this skill context, that is more dangerous because the tool is explicitly meant to create publishable content, increasing the chance of accidental disclosure of personal portfolio data.

Tainted flow: 'script' from pathlib.Path.read_text (line 221, file read) → pathlib.Path.write_text (file write)

Medium
Category
Data Flow
Content
# Generate script
    script = generate_trading_script(data)
    script_path = output_dir / f"trading_update_{datetime.now():%Y%m%d}.txt"
    script_path.write_text(script)
    print(f"Script saved: {script_path}")
    
    # Generate TTS
Confidence
65% confidence
Finding
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Context-Inappropriate Capability

Low
Confidence
76% confidence
Finding
The manifest mentions conversion to speech via ElevenLabs TTS, so networked TTS is expected, but it does not mention retrieving credentials from the environment to authorize third-party API access. Accessing environment-held secrets is a separate capability with security implications and is not explicitly justified by the stated description alone.