Back to skill

Security audit

autoshorts

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its stated video-clipping purpose, but it asks for powerful publishing credentials through chat and stores them in a plaintext project file, so it should be reviewed before installation.

Install only if you are comfortable giving the skill Gemini and Upload-Post credentials, uploading full videos and transcripts to Gemini, and allowing Upload-Post to schedule social posts after approval. Prefer configuring secrets through a local secret manager or protected terminal instead of pasting keys into chat, lock down any .env file permissions, review connected Upload-Post profiles, keep TikTok direct posting disabled unless explicitly needed, and treat the learning files as persistent local history of your clips and analytics.

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

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:79
Finding

API Keys Requested Through Logged Agent Conversations

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:39
Finding

API Credentials Stored in a Plaintext Environment File Without Enforced Access Controls

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Note
Location
autoshorts.py:834
Finding

Source Video Filenames Unnecessarily Disclosed to Gemini During Analytics Learning

Content
View full analysis
str: m = c["metrics"] return json.dumps({ "hook_text": c.get("hook_text"), "duration_s": c.get("duration_s"), "viral_score_gemini": c.get("viral_score_gemini"), "reason_gemini": c.get("reason_gemini"), "platforms": c.get("platforms"), "video_source": c.get("video_source"), "metrics": { "total_views": m["total_views"], "total_engagement": m["total_engagement"], "engagement_rate": round(m["engagement_rate"], 4), "per_platform": m["per_platform"], }, "composite_score": round(c["composite"], 3), }, ensure_ascii=False) winners_text = "\n".join(render_clip(c) for c in winners) losers_text = "\n".join(render_clip(c) for c in losers) current_hot = HOT_FILE.read_text() if HOT_FILE.exists() else "" full_prompt = ( LEARN_META_PROMPT + "\n\n## CURRENT HOT.md\n" + (current_hot or "(empty — first learn run)") + f"\n\n## WINNERS (top {len(winners)} of {n})\n" + winners_text + f"\n\n## LOSERS (bottom {len(losers)} of {n})\n" + losers_text ) client = genai.Client(api_key=api_key_g) response = client.models.generate_content( model=GEMINI_MODEL, contents=[full_prompt], ) ``` ### Technical Analysis The weekly learning workflow serializes `video_source` into every winner and loser record and sends the resulting prompt to Gemini. Local source filenames can contain personal names, customer names, internal project identifiers, campaign titles, dates, or other confidential metadata. The filename is not required to infer relationships between hook styles, clip durations, scores, and engagement metrics. Including it therefore violates data-minimization princi ...[truncated 1260 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
Findings (30)

Tainted flow: 'data' from os.getenv (line 1005, credential/environment) → requests.post (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 · autoshorts.py (reported line 590)May include surrounding context.

python
with video.open("rb") as fh:
        files = {"video": (video.name, fh, "video/mp4")}
        res = requests.post(
            f"{UPLOAD_POST_BASE}/upload",
            headers={"Authorization": f"Apikey {api_key}"},
            data=data,

Tainted flow: 'api_key_up' from os.getenv (line 751, credential/environment) → requests.get (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 · autoshorts.py (reported line 788)May include surrounding context.

python
continue
        url = f"{UPLOAD_POST_BASE}/uploadposts/post-analytics/{rid}"
        try:
            r = requests.get(url, headers={"Authorization": f"Apikey {api_key_up}"}, timeout=30)
        except requests.RequestException as e:
            print(f"[learn] {rid}: HTTP error {e}", file=sys.stderr)
            continue

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · README.md (reported line 232)May include surrounding context.

md
├── README.md                  ← you are here
├── autoshorts.py              ← CLI: pick / transcribe / analyze / extract / hook / publish / mark-processed
├── requirements.txt
├── .env                       ← secrets (gitignored)
├── .env.example
├── input/                     ← drop long videos here
├── output/

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · autoshorts.py (reported line 32)May include surrounding context.

python
from dotenv import load_dotenv

ROOT = Path(__file__).resolve().parent
load_dotenv(ROOT / ".env")

INPUT_FOLDER = Path(os.getenv("INPUT_FOLDER", ROOT / "input")).expanduser()
OUTPUT_FOLDER = Path(os.getenv("OUTPUT_FOLDER", ROOT / "output")).expanduser()

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · autoshorts.py (reported line 299)May include surrounding context.

python
from dotenv import load_dotenv

ROOT = Path(__file__).resolve().parent
load_dotenv(ROOT / ".env")

INPUT_FOLDER = Path(os.getenv("INPUT_FOLDER", ROOT / "input")).expanduser()
OUTPUT_FOLDER = Path(os.getenv("OUTPUT_FOLDER", ROOT / "output")).expanduser()

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · autoshorts.py (reported line 546)May include surrounding context.

python
from dotenv import load_dotenv

ROOT = Path(__file__).resolve().parent
load_dotenv(ROOT / ".env")

INPUT_FOLDER = Path(os.getenv("INPUT_FOLDER", ROOT / "input")).expanduser()
OUTPUT_FOLDER = Path(os.getenv("OUTPUT_FOLDER", ROOT / "output")).expanduser()

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · autoshorts.py (reported line 754)May include surrounding context.

python
from dotenv import load_dotenv

ROOT = Path(__file__).resolve().parent
load_dotenv(ROOT / ".env")

INPUT_FOLDER = Path(os.getenv("INPUT_FOLDER", ROOT / "input")).expanduser()
OUTPUT_FOLDER = Path(os.getenv("OUTPUT_FOLDER", ROOT / "output")).expanduser()

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · autoshorts.py (reported line 756)May include surrounding context.

python
from dotenv import load_dotenv

ROOT = Path(__file__).resolve().parent
load_dotenv(ROOT / ".env")

INPUT_FOLDER = Path(os.getenv("INPUT_FOLDER", ROOT / "input")).expanduser()
OUTPUT_FOLDER = Path(os.getenv("OUTPUT_FOLDER", ROOT / "output")).expanduser()

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · autoshorts.py (reported line 939)May include surrounding context.

python
from dotenv import load_dotenv

ROOT = Path(__file__).resolve().parent
load_dotenv(ROOT / ".env")

INPUT_FOLDER = Path(os.getenv("INPUT_FOLDER", ROOT / "input")).expanduser()
OUTPUT_FOLDER = Path(os.getenv("OUTPUT_FOLDER", ROOT / "output")).expanduser()

Known Vulnerable Dependency: Pillow==12.2.0 — 16 advisory(ies): CVE-2026-55379 (Pillow `BdfFontFile`: `Image.new()` called without `_decompression_bomb_check()`); CVE-2026-55798 (Pillow: WindowsViewer.get_command() OS command injection via unescaped shell pat); CVE-2026-54060 (Pillow: `FontFile.compile()`: `Image.new()` called without `_decompression_bomb_) +13 more

High
Category
Supply Chain
Confidence
96% confidence
Finding

The dependency is pinned to a Pillow version flagged with multiple known security advisories, so this is a real supply-chain vulnerability rather than a false positive. In this skill, Pillow is likely used to process images/text overlays for short-form video generation, which can involve untrusted media inputs; vulnerable image/font handling can enable denial of service, memory corruption, or command injection depending on the affected code path and platform.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
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.

Content

Scanner excerpt · README.md (reported line 27)May include surrounding context.

md
1. Clone or `git pull` this repo into `~/Documents/skill-autoshorts/` (or whatever path the user prefers).
2. Make sure `ffmpeg` is installed (`brew install ffmpeg` on macOS, `apt install ffmpeg` on Linux). Verify with `ffmpeg -version`.
3. Create the venv and install Python deps: `python3 -m venv venv && ./venv/bin/pip install -r requirements.txt`.
4. Register `SKILL.md` with whichever agent harness is running. For Claude Code, copy or symlink it into `~/.claude/skills/autoshorts/SKILL.md`. For Hermes / Openclaw follow their skill registration docs.
5. Create `.env` from `.env.example` and ask the user to paste the values you need:
   - `GEMINI_API_KEY` — https://aistudio.google.com/apikey (free tier is enough).

Skill Enumeration

Medium
Category
Agent Snooping
Confidence
80% confidence
Finding

Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.

Content

Scanner excerpt · README.md (reported line 28)May include surrounding context.

md
1. Clone or `git pull` this repo into `~/Documents/skill-autoshorts/` (or whatever path the user prefers).
2. Make sure `ffmpeg` is installed (`brew install ffmpeg` on macOS, `apt install ffmpeg` on Linux). Verify with `ffmpeg -version`.
3. Create the venv and install Python deps: `python3 -m venv venv && ./venv/bin/pip install -r requirements.txt`.
4. Register `SKILL.md` with whichever agent harness is running. For Claude Code, copy or symlink it into `~/.claude/skills/autoshorts/SKILL.md`. For Hermes / Openclaw follow their skill registration docs.
5. Create `.env` from `.env.example` and ask the user to paste the values you need:
   - `GEMINI_API_KEY` — https://aistudio.google.com/apikey (free tier is enough).
   - `UPLOAD_POST_API_KEY` and `UPLOAD_POST_PROFILE` — https://app.upload-post.com → Settings → API Keys + Manage Users (free tier available, no credit card required).

External Transmission

Medium
Category
Data Exfiltration
Confidence
91% confidence
Finding

The skill integrates with an external service (Upload-Post) and the README instructs the agent to verify the API key by contacting the remote API and summarizing connected platforms. This is expected functionality, but it still represents real external data transmission and account metadata exposure; in an agent setting, users may not realize their connected social-account details are being fetched and surfaced.

Content

Scanner excerpt · README.md (reported line 33)May include surrounding context.

md
- `GEMINI_API_KEY` — https://aistudio.google.com/apikey (free tier is enough).
   - `UPLOAD_POST_API_KEY` and `UPLOAD_POST_PROFILE` — https://app.upload-post.com → Settings → API Keys + Manage Users (free tier available, no credit card required).
   - Default `INPUT_FOLDER` and `OUTPUT_FOLDER` to `~/Documents/skill-autoshorts/input` and `.../output` unless the user says otherwise. Default `WHISPER_MODEL=medium` and `TIMEZONE=Europe/Madrid` (override if the user is in another timezone).
6. Verify the Upload-Post key works: `curl -s -H "Authorization: Apikey $UPLOAD_POST_API_KEY" https://api.upload-post.com/api/uploadposts/users` should return the user's profile and connected platforms.
7. Read `SKILL.md` end-to-end. That's the canonical daily workflow — visual QA, weekly `learn`, all the operational rules.

**After install, do nothing else.** Don't transcribe, don't call Gemini, don't publish. Tell the user everything is ready, summarize what's connected on Upload-Post, and wait. The user will forward videos to you in chat going forward — your job is to save each one into `INPUT_FOLDER` and invoke the skill (`/autoshorts` or equivalent) when they ask.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The README explicitly states that the full video and transcript are sent to Gemini in the cloud, but it does not clearly warn users about privacy implications, data handling, or the risk of uploading sensitive footage or speech content to a third party. In this skill's context, videos may contain personal, confidential, or client material, so omission of an explicit consent/privacy notice creates a real data exposure risk.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
97% confidence
Finding

The skill requires shell, filesystem, environment-variable, and network access but does not declare any explicit tool/permission scope. In an agent harness, that mismatch can cause the skill to be invoked with broader-than-expected capabilities, increasing the blast radius for credential handling, file operations, and external publishing actions.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The activation phrases are broad enough to match common user requests about clips, reels, or automation, which can cause unintended skill invocation. In this skill, accidental activation is more serious because it can lead to environment checks, credential collection prompts, file copying, network uploads, and publishing workflow execution.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
88% confidence
Finding

The skill is explicitly designed to transmit data and credentials to third-party services, including Upload-Post and Gemini. External transmission is expected in context, but it remains security-relevant because the workflow handles API keys, uploads user media, and sends derived metadata off-host; compromise or misuse could expose private content or enable unauthorized posting.

Content

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

md
- Connect TikTok, Instagram (Business/Creator account linked to a Facebook Page), and YouTube via OAuth in the dashboard.
- In **Manage Users**, create a profile — its name is `UPLOAD_POST_PROFILE` (NOT the social handle).
- Generate an API key in **Settings**.
- Verify: `curl -H "Authorization: Apikey $UPLOAD_POST_API_KEY" https://api.upload-post.com/api/uploadposts/me`.

## Orchestration model

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
81% confidence
Finding

The instruction to perform setup actions 'without asking' authorizes autonomous shell execution and package installation steps before explicit user approval. Even if limited to creating a venv and installing dependencies, autonomous execution against a repository and network package sources increases supply-chain and unintended-change risk.

Content

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

md
Before doing any work, check that the environment is ready and ask the user for whatever is missing:

1. **venv** — does `~/Documents/skill-autoshorts/venv/bin/python` exist? If not, run setup step 1 from the Setup section. (You can do this without asking — it's mechanical.)
2. **`ffmpeg`** in `PATH` — if missing, ask the user to `brew install ffmpeg` (do not install yourself; system-wide installs deserve confirmation).
3. **`.env` file** — check that every required key is set and non-empty:
   - `GEMINI_API_KEY` → if missing, ask: *"Falta la API key de Gemini. Pégamela (la generas en https://aistudio.google.com/apikey)."*

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The file hardcodes Spanish prompt text when asking for missing API credentials, regardless of the user's preferred language or locale. This is a natural-language policy concern because it imposes a specific language without documenting opt-in, choice, or region-specific justification.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

L107 instructs the operator to remove an entry from state/processed.json before rerunning pick, while L309 says the file should never be edited programmatically except via mark-processed and that reprocessing should be done by asking the user to remove the entry manually. These instructions contradict each other about the permitted mechanism for altering processing state.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

L308 says that if pick reports "all videos already processed," the skill should stop and require a new video. But L070, L103, and L105 explicitly describe a cyclic workflow where, after all videos are processed in a cycle, a new cycle starts automatically and previously processed videos become eligible again. This is an active documentation contradiction about core pipeline behavior.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill description frames the tool as a human-gated one-video clip workflow, but the code also performs broader autonomous learning and reflection over historical post analytics. This mismatch can mislead operators about the scope of data processing and automation, causing unanticipated collection, profiling, and third-party transmission of creator performance data.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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 · autoshorts.py (reported line 48)May include surrounding context.

python
VIDEO_EXTS = {".mp4", ".mov", ".mkv", ".m4v", ".webm"}
GEMINI_MODEL = "gemini-3-flash-preview"
UPLOAD_POST_BASE = "https://api.upload-post.com/api"


def append_jsonl(path: Path, record: dict) -> None:

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 · autoshorts.py (reported line 113)May include surrounding context.

python
def run_ffmpeg(args: list[str]) -> None:
    cmd = ["ffmpeg", "-y", "-hide_banner", "-loglevel", "error", *args]
    res = subprocess.run(cmd, capture_output=True, text=True)
    if res.returncode != 0:
        sys.stderr.write(res.stderr)
        raise SystemExit(f"ffmpeg failed: {' '.join(cmd)}")

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 · autoshorts.py (reported line 120)May include surrounding context.

python
def ffprobe_duration(video: Path) -> float:
    res = subprocess.run(
        [
            "ffprobe", "-v", "error",
            "-show_entries", "format=duration",

Static analysis

No suspicious patterns detected.