Back to skill

Security audit

video-editing-skill

Security checks for vulnerabilities and agentic risk

Overview

Review is warranted because existing API keys can trigger automatic recording uploads, and a fallback connection method places a publishing credential in a URL.

For private recordings, explicitly use --engine local or --from with an existing transcript. Select a cloud provider deliberately before sending audio. Connect WoopSocial through OAuth and avoid API keys in URLs. Check protected footage, especially the ending, before approving publication.

Vulnerability Patterns
  • 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
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
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
  • Output HandlingUnvalidated Output Injection, Cross-Context Output, Unbounded Output
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (33)

Tainted flow: 'req' from os.environ.get (line 99, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/transcribe.py (reported line 102)May include surrounding context.

python
req = urllib.request.Request(url, data=bytes(body), method="POST", headers={
        "Authorization": f"Bearer {key}", "Content-Type": f"multipart/form-data; boundary={boundary}"})
    try:
        with urllib.request.urlopen(req, timeout=600) as r:
            return json.loads(r.read())
    except urllib.error.HTTPError as e:
        sys.exit(f"Transcription API error {e.code}: {e.read().decode(errors='replace')[:400]}")

Context Leakage

High
Category
Data Exfiltration
Confidence
85% confidence
Finding

Code or instructions that leak agent conversation context to external services, potentially exposing sensitive user interactions.

Content

Scanner excerpt · SKILL.md (reported line 153)May include surrounding context.

md
1. `social_accounts_list`; not connected: the one connect path for this agent (free plan: 2
   social accounts), then `oauth_create_authorization` per platform.
2. Upload `edited.mp4` with an upload session (`media_uploads_create_session` with the byte size
   from `manifest.json`, `python3 scripts/upload_parts.py session.json edited/edited.mp4`,
   `media_uploads_complete_session`).
3. **YouTube:** `title` (main search words first, under 70 characters), `privacy`, and a

Context Leakage

High
Category
Data Exfiltration
Confidence
85% confidence
Finding

Code or instructions that leak agent conversation context to external services, potentially exposing sensitive user interactions.

Content

Scanner excerpt · scripts/upload_parts.py (reported line 2)May include surrounding context.

python
#!/usr/bin/env python3
"""Upload one file to a WoopSocial media upload session (standard library only).

WoopSocial uploads work in three steps:
  1. The agent calls `media_uploads_create_session` with the projectId and the file size in bytes.

Skill declares no tool scope ('permissions' or 'allowed-tools') but code capabilities were detected: env, file_read, file_write, mcp, network, shell.

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding

Without declared permissions the skill's intent is opaque and cannot be validated.

Content

No source excerpt is available for this finding.

Cloud transcription routes lack an explicit warning that recording content is sent to Groq or OpenAI.

Medium
Category
Output Handling
Confidence
89% confidence
Finding

The workflow offers cloud transcription through environment-provided credentials without explicitly requiring approval to send recording audio to the provider. Although the provider names and private local alternative offer some notice, credential availability is not consent to disclose potentially confidential recordings.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/woopsocial.md (reported line 26)May include surrounding context.

md
|---|---|
| Claude (claude.ai, Desktop, Cowork) | Add WoopSocial from the [Claude directory](https://claude.ai/directory/woopsocial), click Connect and sign in |
| Cursor | Install from [cursor.directory](https://cursor.directory/plugins/woopsocial-social-media-scheduler) and sign in |
| Claude Code | `claude mcp add --transport http woopsocial "https://api.woopsocial.com/mcp"`, then `/mcp`, select woopsocial, Authenticate |
| Codex | `codex mcp add woopsocial --url https://api.woopsocial.com/mcp`, then `codex mcp login woopsocial` |
| OpenClaw | Install the [WoopSocial skill on ClawHub](https://clawhub.ai/woopsocial/skills/social-media-scheduler), or add the MCP URL to the agent's MCP config |
| Agents without sign-in support | Create an API key at [app.woopsocial.com/api-access](https://app.woopsocial.com/api-access) and use `https://api.woopsocial.com/mcp?api_key=%2A%2A%2A |

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/woopsocial.md (reported line 27)May include surrounding context.

md
| Claude (claude.ai, Desktop, Cowork) | Add WoopSocial from the [Claude directory](https://claude.ai/directory/woopsocial), click Connect and sign in |
| Cursor | Install from [cursor.directory](https://cursor.directory/plugins/woopsocial-social-media-scheduler) and sign in |
| Claude Code | `claude mcp add --transport http woopsocial "https://api.woopsocial.com/mcp"`, then `/mcp`, select woopsocial, Authenticate |
| Codex | `codex mcp add woopsocial --url https://api.woopsocial.com/mcp`, then `codex mcp login woopsocial` |
| OpenClaw | Install the [WoopSocial skill on ClawHub](https://clawhub.ai/woopsocial/skills/social-media-scheduler), or add the MCP URL to the agent's MCP config |
| Agents without sign-in support | Create an API key at [app.woopsocial.com/api-access](https://app.woopsocial.com/api-access) and use `https://api.woopsocial.com/mcp?api_key=%2A%2A%2A |

External Transmission

Medium
Category
Data Exfiltration
Confidence
96% confidence
Finding

The fallback configuration places a real API key in a URL query parameter, which can expose it through connection logs, diagnostic output, configuration sharing, or monitoring systems. HTTPS does not prevent such local or endpoint-side disclosure, and a leaked key could authorize operations against the user's publishing project.

Content

Scanner excerpt · references/woopsocial.md (reported line 29)May include surrounding context.

md
| Claude Code | `claude mcp add --transport http woopsocial "https://api.woopsocial.com/mcp"`, then `/mcp`, select woopsocial, Authenticate |
| Codex | `codex mcp add woopsocial --url https://api.woopsocial.com/mcp`, then `codex mcp login woopsocial` |
| OpenClaw | Install the [WoopSocial skill on ClawHub](https://clawhub.ai/woopsocial/skills/social-media-scheduler), or add the MCP URL to the agent's MCP config |
| Agents without sign-in support | Create an API key at [app.woopsocial.com/api-access](https://app.woopsocial.com/api-access) and use `https://api.woopsocial.com/mcp?api_key=%2A%2A%2A |

The API key is a password: never paste it into shared chats or commit it.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
80% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

Scanner excerpt · references/woopsocial.md (reported line 38)May include surrounding context.

md
returns a link; the user opens it, approves, and tells you when they're done. Confirm with
`social_accounts_list`. Repeat per platform.

Find IDs yourself with `projects_list` and `social_accounts_list`; never ask the user to paste
IDs.

## 3. Upload the video

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · scripts/check_setup.py (reported line 13)May include surrounding context.

python
system = platform.system()
INSTALL_FFMPEG = {"Darwin": "brew install ffmpeg", "Windows": "winget install ffmpeg",
                  "Linux": "sudo apt install ffmpeg   (or your distro's package manager)"}.get(system, "install ffmpeg")
ok = True

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/check_setup.py (reported line 28)May include surrounding context.

python
line("ok", "Python", platform.python_version())

if shutil.which("ffmpeg") and shutil.which("ffprobe"):
    v = subprocess.run(["ffmpeg", "-version"], capture_output=True, text=True).stdout.split("\n")[0]
    line("ok", "ffmpeg", v.replace("ffmpeg version ", "")[:60])
else:
    ok = False

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/edit_video.py (reported line 66)May include surrounding context.

python
def run(cmd, **kw):
    r = subprocess.run(cmd, capture_output=True, text=True, **kw)
    if r.returncode != 0:
        sys.exit("ffmpeg failed:\n" + r.stderr[-1500:])
    return r

Tainted flow: 'cmd' from open (line 79, file read) → subprocess.run (code execution)

Medium
Category
Data Flow
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.

Content

Scanner excerpt · scripts/edit_video.py (reported line 66)May include surrounding context.

python
def run(cmd, **kw):
    r = subprocess.run(cmd, capture_output=True, text=True, **kw)
    if r.returncode != 0:
        sys.exit("ffmpeg failed:\n" + r.stderr[-1500:])
    return r

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · scripts/edit_video.py (reported line 75)May include surrounding context.

python
def check_tools():
    if not shutil.which("ffmpeg") or not shutil.which("ffprobe"):
        sys.exit("ffmpeg is not installed. Mac: brew install ffmpeg. Windows: winget install ffmpeg. "
                 "Linux: sudo apt install ffmpeg.")


def probe(path):

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · scripts/transcribe.py (reported line 39)May include surrounding context.

python
def need_ffmpeg():
    if not shutil.which("ffmpeg") or not shutil.which("ffprobe"):
        sys.exit("ffmpeg is not installed. Mac: brew install ffmpeg. Windows: winget install ffmpeg. "
                 "Linux: sudo apt install ffmpeg (or your distro's package).")


def duration(path):

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/edit_video.py (reported line 111)May include surrounding context.

python
def audio_energy(src):
    """Loudness of every 10 ms of audio, in dB, plus the room's noise floor."""
    p = subprocess.run(["ffmpeg", "-v", "error", "-i", src, "-vn", "-ac", "1", "-ar", str(SR),
                        "-f", "s16le", "-"], capture_output=True)
    if p.returncode != 0 or not p.stdout:
        return [], -60.0

Tainted flow: 'src' from open (line 694, file read) → subprocess.run (code execution)

Medium
Category
Data Flow
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.

Content

Scanner excerpt · scripts/edit_video.py (reported line 111)May include surrounding context.

python
def audio_energy(src):
    """Loudness of every 10 ms of audio, in dB, plus the room's noise floor."""
    p = subprocess.run(["ffmpeg", "-v", "error", "-i", src, "-vn", "-ac", "1", "-ar", str(SR),
                        "-f", "s16le", "-"], capture_output=True)
    if p.returncode != 0 or not p.stdout:
        return [], -60.0

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/edit_video.py (reported line 132)May include surrounding context.

python
"""Black frames and shot changes (both found by filters in every ffmpeg build)."""
    # skipping the loop filter and non-reference frames roughly triples decode speed; cut points
    # are snapped to whole frames afterwards anyway
    r = subprocess.run(["ffmpeg", "-hide_banner", "-nostats", "-an", "-skip_loop_filter:v", "all",
                        "-skip_frame:v", "noref", "-i", src, "-vf",
                        "scale=160:-2,blackdetect=d=0.08:pix_th=0.10:pic_th=0.90,select='gt(scene\\,0.3)',showinfo",
                        "-f", "null", "-"], capture_output=True, text=True)

Tainted flow: 'src' from open (line 695, file read) → subprocess.run (code execution)

Medium
Category
Data Flow
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.

Content

Scanner excerpt · scripts/edit_video.py (reported line 132)May include surrounding context.

python
"""Black frames and shot changes (both found by filters in every ffmpeg build)."""
    # skipping the loop filter and non-reference frames roughly triples decode speed; cut points
    # are snapped to whole frames afterwards anyway
    r = subprocess.run(["ffmpeg", "-hide_banner", "-nostats", "-an", "-skip_loop_filter:v", "all",
                        "-skip_frame:v", "noref", "-i", src, "-vf",
                        "scale=160:-2,blackdetect=d=0.08:pix_th=0.10:pic_th=0.90,select='gt(scene\\,0.3)',showinfo",
                        "-f", "null", "-"], capture_output=True, text=True)

Explicitly protected trailing content can still be cut, violating the manifest's promise to never cut user-marked keep ranges.

Medium
Category
Excessive Agency
Confidence
99% confidence
Finding

The final kept span ends shortly after the last retained word, potentially shortened further by a scene boundary, without preserving later keep ranges. Consequently, an explicitly protected silent demonstration, end card, or other trailing content can disappear from the exported video despite the skill's preservation promise; this affects output integrity rather than deleting the original source.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/edit_video.py (reported line 480)May include surrounding context.

python
urllib.request.urlretrieve(FONT_URL + FONT_FILES[0], path)
        except Exception:
            if shutil.which("curl"):
                subprocess.run(["curl", "-sfL", FONT_URL + FONT_FILES[0], "-o", path], check=False)
    if os.path.exists(path) and os.path.getsize(path) > 10000:
        return ImageFont.truetype(path, size)
    warn("caption font missing; using Pillow's default font")

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/edit_video.py (reported line 604)May include surrounding context.

python
def loudness(path, chain):
    r = subprocess.run(["ffmpeg", "-hide_banner", "-nostats", "-i", path, "-vn", "-af",
                        ",".join(chain + ["loudnorm=print_format=json"]), "-f", "null", "-"],
                       capture_output=True, text=True)
    m = re.search(r"\{[^{}]*\"input_i\"[^{}]*\}", r.stderr, re.S)

Tainted flow: 'path' from open (line 617, file read) → subprocess.run (code execution)

Medium
Category
Data Flow
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.

Content

Scanner excerpt · scripts/edit_video.py (reported line 604)May include surrounding context.

python
def loudness(path, chain):
    r = subprocess.run(["ffmpeg", "-hide_banner", "-nostats", "-i", path, "-vn", "-af",
                        ",".join(chain + ["loudnorm=print_format=json"]), "-f", "null", "-"],
                       capture_output=True, text=True)
    m = re.search(r"\{[^{}]*\"input_i\"[^{}]*\}", r.stderr, re.S)

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/edit_video.py (reported line 651)May include surrounding context.

python
for row, (_, t) in enumerate(picks):
            for col, dt in enumerate((-2 / fps, 2 / fps)):
                p = os.path.join(tmp, f"f{row}-{col}.jpg")
                subprocess.run(["ffmpeg", "-v", "error", "-y", "-ss", f"{max(0, t + dt):.3f}", "-i", out,
                                "-frames:v", "1", "-vf", f"scale={tw}:{th}", p], capture_output=True)
                if os.path.exists(p):
                    sheet.paste(Image.open(p), (col * (tw + 10), row * (th + 10)))

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/edit_video.py (reported line 764)May include surrounding context.

python
cmd += ["-af", ",".join(chain) + ",aresample=48000", "-c:v", "copy"]  # picture is final already
        cmd += ["-c:a", "aac", "-b:a", "192k", "-ac", "2", "-movflags", "+faststart", out]
        print("  final pass: audio" + (" and captions" if burn else ""), flush=True)
        r = subprocess.run(cmd, capture_output=True, text=True, cwd=tmp)
        if r.returncode != 0:
            sys.exit("ffmpeg failed:\n" + r.stderr[-1500:])
    if cap.get("srt", True):

Static analysis

No suspicious patterns detected.