Back to skill

Security audit

TSW Shorts Factory

Security checks for vulnerabilities and agentic risk

Overview

This skill matches its video-automation purpose, but it contains under-disclosed high-impact upload behavior and unsafe implementation choices that users should review before installing.

Review this skill before installing. It automates YouTube uploads and uses persistent OAuth access, so run it only in a contained account. Do not rely on its draft/unlisted claim unless the missing uploader script is supplied and audited. Rotate the exposed Pexels key, replace pickle token storage, remove hard-coded /root paths and external sys.path injection, and pin dependencies before production use.

Vulnerability Patterns
  • Tool Hijacking and SpoofingModifies or replaces tools so legitimate-looking calls execute attacker logic
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (4)

T07 · Tool Hijacking and Spoofing

Error
Location
scripts/pipeline.py:18
Finding
Execution of an Unpackaged and Unaudited External Uploader## Vulnerability Details **File Location**: `scripts/pipeline.py`, lines 18–23 and 245–260 **Vulnerability Type**: External tool hijacking through hard-coded mutable paths **Risk Level**: High ### Vulnerable Code ```python sys.path.insert(0, '/root/.openclaw/workspace/projects/content/vanyan_video_factory') # ── Config ────────────────────────────────────────────────────────────────── QUOTE_LIBRARY = "/root/.openclaw/workspace/projects/content/tsw_quote_library.json" OUTPUT_DIR = "/root/tsw_videos/noltx_output" AUDIO_DIR = "/root/tsw_videos/noltx_audio" CLIP_CACHE_DIR = "/root/tsw_videos/clip_library" LOG_FILE = "/root/.openclaw/workspace/agents/tsw/cron.log" YT_UPLOADER = "/root/.openclaw/workspace/projects/content/yt_uploader.py" ``` ```python def upload_to_youtube(video_path, title, description): try: result = subprocess.run( ["python3", YT_UPLOADER, video_path, title, description], capture_output=True, text=True, timeout=300 ) if result.returncode == 0: log.info(f"YouTube upload: {result.stdout.strip()[:200]}") return True else: log.warning(f"YouTube upload failed: {result.stderr.strip()[:200]}") return False except Exception as e: log.error(f"Upload error: {e}") return False ``` ### Technical Analysis The pipeline executes `yt_uploader.py` from a hard-coded path outside the audited project. That uploader is not included in the supplied directory, so its behavior, credential handling, network destinations, and YouTube privacy configuration cannot be verified. The script also prepends an external directory to `sys.path`. Because the directory is placed first in Python's module search order, a malicious module placed there could shadow imported packages such as `requests`, `edge_tts`, or `moviepy`. Although the subprocess call uses an argument list and is not directly vulnerable to shell inje ...[truncated 1074 chars]
Remediation
## Remediation Suggestions - Package the uploader inside the audited project and review it together with the pipeline. - Remove the external `sys.path.insert` operation and use normal package imports. - Resolve project resources relative to `Path(__file__)` rather than hard-coded workspace paths. - If an external executable is unavoidable, configure its path explicitly, verify its ownership and permissions, and validate it against a trusted cryptographic hash before execution. - Run the pipeline as a dedicated, unprivileged service account rather than root. - Implement YouTube uploading directly through the reviewed Google API client and explicitly set and verify the intended privacy status. - Restrict write access to all executable code and dependency directories.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/pipeline.py:24
Finding
Hard-Coded Pexels API Credential in Source Code## Vulnerability Details **File Location**: `scripts/pipeline.py`, lines 24 and 113–119 **Vulnerability Type**: Embedded plaintext API credential **Risk Level**: High ### Vulnerable Code ```python PEXELS_KEY = "z4qzlGqn6cZzDpEzt6vsrLfxPXXVrGfDRJ7n3bB7xReXA53drnG0b3BD" ``` ```python r = requests.get("https://api.pexels.com/videos/search", headers={"Authorization": PEXELS_KEY}, params={"query": query, "per_page": count + 2, "orientation": "portrait", "size": "medium"}, timeout=15) ``` ### Technical Analysis A Pexels API key is embedded directly in the distributed Python source. Anyone who can download or inspect the project can recover and reuse the credential. This contradicts `SKILL.md`, which instructs users to provide `PEXELS_API_KEY` through the environment; the implementation never reads that variable. Source-code credentials are difficult to rotate safely and may remain recoverable from package copies, logs, caches, forks, or repository history even after removal from the current version. ### Attack Path 1. An attacker obtains a copy of the project or views its source. 2. The attacker extracts the plaintext value assigned to `PEXELS_KEY`. 3. The attacker sends requests to the Pexels API using the key in the `Authorization` header. 4. Requests consume the credential owner's quota and are attributed to that account until the key is revoked. ### Impact Assessment The exposed credential can be used for unauthorized Pexels API access within the permissions assigned to the key. Likely consequences include quota exhaustion, service interruption, account attribution issues, and possible account suspension for abusive traffic. This credential does not by itself provide operating-system or YouTube account access.
Remediation
## Remediation Suggestions - Immediately revoke and rotate the exposed Pexels key. - Remove the credential from source code and repository history. - Load it from the documented environment variable: ```python PEXELS_KEY = os.environ.get("PEXELS_API_KEY") if not PEXELS_KEY: raise RuntimeError("PEXELS_API_KEY is required") ``` - Use a secret manager for automated deployments and restrict secret access to the dedicated runtime account. - Add secret-scanning checks to CI and pre-commit workflows. - Avoid logging credentials or complete authorization headers.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/yt_setup.py:15
Finding
Unsafe Deserialization of YouTube OAuth Credentials with Pickle## Vulnerability Details **File Location**: `scripts/yt_setup.py`, lines 15–19 **Vulnerability Type**: Arbitrary code execution through unsafe deserialization **Risk Level**: High ### Vulnerable Code ```python def setup(): creds = None if os.path.exists(TOKEN_FILE): with open(TOKEN_FILE, 'rb') as f: creds = pickle.load(f) ``` ### Technical Analysis Python pickle is an executable serialization format. Loading a pickle can invoke attacker-selected Python callables through reduction methods; therefore, `pickle.load()` must not be used on data whose integrity cannot be guaranteed. The token is read from the predictable path `~/.yt_token.pickle` without checking file ownership, permissions, file type, or integrity. A malicious token file placed or replaced at that location can execute code before credential validity is checked. ### Attack Path 1. An attacker or compromised process writes a crafted pickle payload to `~/.yt_token.pickle`. 2. The operator runs `python3 scripts/yt_setup.py`. 3. `pickle.load(f)` deserializes the crafted object. 4. The payload's reduction callable executes with the privileges of the operator. 5. The payload can access credentials and other resources available to that account. ### Impact Assessment Exploitation permits arbitrary Python code execution under the account running the setup script. If setup is run as root, this can result in full host compromise. Otherwise, the attacker can access or modify files, environment variables, OAuth credentials, and processes available to the affected user. The issue requires an attacker to create or replace the token file, such as through another compromised process, an unsafe shared home directory, or insecure file permissions.
Remediation
## Remediation Suggestions - Replace pickle persistence with a non-executable format supported by Google credentials, such as JSON serialization. - Create credential files with mode `0600` and verify that the file is owned by the current user before reading it. - Reject symbolic links and non-regular files when opening the token. - Store OAuth material in an operating-system credential store or managed secret store where practical. - If migration from the existing pickle is necessary, treat the old file as trusted only after an explicit ownership and permission check, then delete it after conversion. - Run authentication setup as a dedicated, unprivileged account.

T08 · Insecure Dependencies

Warning
Location
SKILL.md:12
Finding
Unpinned Third-Party Dependencies Installed Without Integrity Verification## Vulnerability Details **File Location**: `SKILL.md`, lines 12–16 **Vulnerability Type**: Non-reproducible and integrity-unverified dependency installation **Risk Level**: Medium ### Vulnerable Code ```bash # 1. Install dependencies pip install moviepy edge-tts google-api-python-client google-auth-oauthlib pillow ``` ### Technical Analysis The deployment instructions install third-party packages without exact versions, hashes, or a lock file. Consequently, installations performed at different times may resolve to different package and transitive-dependency versions. Python package installation can execute package build hooks. If a dependency account, package release, or transitive dependency is compromised, following the documented command can install and execute attacker-controlled code. The absence of version constraints also increases the likelihood of incompatible or newly vulnerable releases being introduced without review. No evidence shows that the listed package names are themselves malicious; the confirmed issue is the unsafe, non-reproducible dependency-management practice. ### Attack Path 1. A listed package or one of its transitive dependencies publishes a compromised release, or an upstream distribution channel is compromised. 2. An operator follows the documented unpinned `pip install` command. 3. Pip resolves the compromised version because no approved version or hash is enforced. 4. Malicious installation hooks or imported runtime code execute under the operator's account. ### Impact Assessment A compromised dependency could execute arbitrary code with the privileges used for installation or pipeline execution. This could expose local files, OAuth credentials, API keys, and generated media. The practical likelihood depends on an upstream supply-chain compromise, but the impact can include full compromise of the runtime account.
Remediation
## Remediation Suggestions - Provide a reviewed dependency lock file containing exact versions. - Generate and enforce cryptographic package hashes, for example with `pip install --require-hashes -r requirements.txt`. - Pin transitive dependencies in addition to direct dependencies. - Install dependencies inside an isolated virtual environment under an unprivileged account. - Use a trusted internal package mirror where appropriate. - Enable automated dependency vulnerability scanning and controlled update review. - Document supported Python and FFmpeg versions to make deployments reproducible.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (13)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The documented behavior claims the pipeline uses configured credentials and uploads videos as drafts, but the finding indicates undeclared credential use and delegation to an external uploader script whose actual behavior is not established here. This mismatch is dangerous because reviewers and users cannot reliably determine what data is accessed, which credentials are used, or whether uploads are really restricted to draft/unlisted states.

Credential Access

High
Category
Privilege Escalation
Content
1. Go to [Google Cloud Console](https://console.cloud.google.com/)
2. Create project → Enable **YouTube Data API v3**
3. Create credentials → **OAuth 2.0 Client ID** → Desktop app
4. Download JSON → rename to `yt_client_secrets.json` in working dir
5. Run: `python3 scripts/yt_setup.py` (opens browser for auth)
6. Token saved to `~/.yt_token.pickle` — valid until revoked
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
1. Go to [Google Cloud Console](https://console.cloud.google.com/)
2. Create project → Enable **YouTube Data API v3**
3. Create credentials → **OAuth 2.0 Client ID** → Desktop app
4. Download JSON → rename to `yt_client_secrets.json` in working dir
5. Run: `python3 scripts/yt_setup.py` (opens browser for auth)
6. Token saved to `~/.yt_token.pickle` — valid until revoked
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
1. Go to [Google Cloud Console](https://console.cloud.google.com/)
2. Create project → Enable **YouTube Data API v3**
3. Create credentials → **OAuth 2.0 Client ID** → Desktop app
4. Download JSON → rename to `yt_client_secrets.json` in working dir
5. Run: `python3 scripts/yt_setup.py` (opens browser for auth)
6. Token saved to `~/.yt_token.pickle` — valid until revoked
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
## Token Refresh
Tokens auto-refresh. If auth breaks after 6+ months:
```bash
rm ~/.yt_token.pickle
python3 scripts/yt_setup.py
```
Confidence
85% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Lp3

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding
The skill advertises operational behavior that clearly requires file access, network access, and shell execution, but it does not declare any tool scope or permissions boundary. This is dangerous because an agent may invoke the skill with broader ambient privileges than intended, making external network calls, reading local files, or executing commands without explicit user-visible authorization.

Vague Triggers

Medium
Confidence
90% confidence
Finding
Because this is a markdown file, vague-trigger review applies. The description lists broad activation conditions such as 'building faceless quote/motivation channels' and 'automating social video content at scale' without clear constraints, negative examples, or a bounded trigger list, which can cause unintended invocation for generic social-media automation requests.

Session Persistence

Medium
Category
Rogue Agent
Content
## One-Time Setup

1. Go to [Google Cloud Console](https://console.cloud.google.com/)
2. Create project → Enable **YouTube Data API v3**
3. Create credentials → **OAuth 2.0 Client ID** → Desktop app
4. Download JSON → rename to `yt_client_secrets.json` in working dir
5. Run: `python3 scripts/yt_setup.py` (opens browser for auth)
Confidence
60% 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.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The TTS generation hard-codes the voice to "en-US-GuyNeural", which enforces a specific language and locale for all output. This is a natural-language policy concern because the skill does not provide any user choice, opt-in, or documented justification for the locale restriction.

External Transmission

Medium
Category
Data Exfiltration
Content
# Fetch from Pexels
    try:
        r = requests.get("https://api.pexels.com/videos/search",
            headers={"Authorization": PEXELS_KEY},
            params={"query": query, "per_page": count + 2,
                    "orientation": "portrait", "size": "medium"},
Confidence
95% confidence
Finding
The pipeline sends requests to an external service and embeds a hardcoded Pexels API key in source, creating credential exposure and uncontrolled third-party transmission. In this autonomous content-generation context, the skill routinely reaches out to external infrastructure, so leaked credentials and unsupervised data egress are more consequential than in a purely local tool.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
# ── Stage 5: Upload to YouTube ───────────────────────────────────────────────
def upload_to_youtube(video_path, title, description):
    try:
        result = subprocess.run(
            ["python3", YT_UPLOADER, video_path, title, description],
            capture_output=True, text=True, timeout=300
        )
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Insecure deserialization: pickle.load()

Medium
Category
Dangerous Code Execution
Content
creds = None
    if os.path.exists(TOKEN_FILE):
        with open(TOKEN_FILE, 'rb') as f:
            creds = pickle.load(f)
    
    if not creds or not creds.valid:
        if creds and creds.expired and creds.refresh_token:
Confidence
94% confidence
Finding
The script deserializes ~/.yt_token.pickle using pickle.load(), which can execute arbitrary code if that file is replaced or tampered with. Although this is intended for storing OAuth credentials, pickle is unsafe for untrusted data and a local attacker or poisoned file could turn token loading into code execution.

Missing User Warnings

Low
Confidence
83% confidence
Finding
This markdown file documents that an OAuth token is saved to `~/.yt_token.pickle`, but it does not warn the user that this file contains sensitive authentication material or should be protected. For markdown files, SQP-2 applies when behaviour affecting privacy or system integrity is described without user-facing warning.

Static analysis

No suspicious patterns detected.