T09 · Insecure Skill Coding Practices
- Location
SKILL.md:40- Finding
API Key Disclosed Through Terminal Output
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill does what it claims, but it handles powerful credentials and private video data with weaker safeguards than users should accept without review.
Install only if you are comfortable sending video frames, transcripts, and metadata to Claude. Do not run the documented echo command for ANTHROPIC_API_KEY; check whether it is set without printing it. Treat cookies.txt files as account credentials, use a throwaway or dedicated account where possible, keep cookie files out of shared folders and logs, and delete them after use. Prefer public videos and review generated Markdown before trusting links, commands, or claims from it.
SKILL.md:40API Key Disclosed Through Terminal Output
scripts/requirements.txt:1Unpinned and Non-Reproducible Third-Party Dependency Installation
scripts/video_analyzer.py:278Indirect Prompt Injection Through Untrusted Video Content
scripts/video_analyzer.py:427YAML Frontmatter Injection Through Unescaped Remote Video Title
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
## Sensitive
cookies.txt
*.cookies
.env
## OS
.DS_Store
YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).
se` | Whisper model size (`tiny` / `base` / `small` / `medium` / `large-v3`) |
| `--cookies` | none | Path to cookies.txt (required for Facebook/Instagram) |
| `--model` | `claude-sonnet-4-6` | Claude model to use for analysis |
## Platform support
| Platform | Auth needed | Notes |
|---|---|---|
| YouTube | Usually no | Cookies needed on cloud IPs or age-restricted content |
| Instagram | Yes (cookies) | Firefox cookies; intermittent even with valid session |
| Facebook | Yes (cookies + impersonation) | Auto-handled; requires `curl_cffi` installed |
For cookie setup, see [`references/platforms.md`](references/platforms.md).
## Cost estimate (claude-sonnet-4-6)
| Video length | Frames | Approx. cost |
|---|---|---|
| 10 min | ~20 | ~$0.08 |
| 30 min | ~50 | ~$0.20 |
| 60 min | ~80 | ~$0.35 |
Switch to `claude-haiku-4-5` for ~5× lower cost.
## How it works
1. **Platform detection** — identifies YouTube, Facebook, or Instagram and selects appropriate download flags
2. **Transc
The skill sends extracted frames and transcripts to Anthropic for vision analysis, but the description does not clearly warn users that potentially sensitive video content will be transmitted to an external AI provider. This is a privacy and data-governance risk, especially for private, account-restricted, educational, or workplace videos that may contain personal data, confidential visuals, or copyrighted material.
The skill instructs users to export browser cookies from a logged-in Firefox session and pass them to the analyzer for Facebook/Instagram access. Although this appears operational rather than overtly malicious, handling reusable session cookies is dangerous because the workflow encourages extraction of authentication material that could be exposed in files, logs, shell history, or mishandled storage, enabling account compromise if leaked.
th doing
---
## Troubleshooting
**"No frames extracted"** → Check ffmpeg is installed and the video downloaded to the temp dir. Try `--max-frames 10` on a short public YouTube video first.
**"No captions found" (and no Whisper)** → Normal for non-captioned videos. Install faster-whisper and add `--whisper`, or the analysis continues from frames alone.
**Facebook "Cannot parse data"** → Cookies may be stale or from a different IP. Re-export from Firefox immediately before use, same network.
**Instagram fails with cookies** → Intermittent. Wait a few minutes and retry. Try a different account if it persists.
**Output is too short / missing visuals** → Increase `--max-frames` or upgrade to `--model claude-opus-4-8`.
**High cost** → Reduce `--max-frames` to 20–30. Talking-head content rarely needs more than 20 frames.
The documentation instructs users to export authenticated browser cookies and supply them to the tool, including guidance around browser choice, session freshness, and same-IP reuse. Even if framed as operational setup, this meaningfully facilitates handling of sensitive session tokens that could enable account compromise, unauthorized access, or unsafe scraping practices if the cookies file is exposed, reused, or mishandled.
# Platform Notes
## YouTube
**Auth required:** Only on datacenter/cloud IPs, or for age-restricted/sign-in-required content.
**Captions:** Excellent. Auto-captions available for most English content. Prefer manual captions (`en`) over auto (`en-orig`) when both are present — auto-captions sometimes insert stray `>>` markers.
**Cookie setup (when needed):**
1. Install the "cookies.txt" extension for Firefox
2. Log into youtube.com in Firefox
3. Click the extension → "Export" → save the file
4. Pass: `--cookies /path/to/cookies.txt`
5. Must export from the same IP you're downloading from
6. Cookies expire — re-export every ~2 weeks
**Note:** Chrome cookies are encrypted (app-bound since Chrome 127) and cannot be reliably extracted. Use Firefox.
---
## Instagram
**Auth required:** Yes — public Reels increasingly require a logged-in session.
**Captions:** Rarely available via yt-dlp. Whisper transcription recommended (`--whisper`).
**Cookie setup:**
1
The README documents use of Claude vision for analysis but does not clearly warn users that extracted video frames and transcripts are sent to Anthropic, an external third-party service. This creates a privacy and compliance risk because users may process copyrighted, sensitive, or personal video content without informed consent or awareness of external data transfer.
The skill invokes shell commands, reads environment variables, and reads/writes files, but it does not declare any tool scope or permission boundaries. That creates an avoidable trust gap: an agent may run networked download/transcription workflows and access local secrets or files without explicit least-privilege constraints or user-visible approval semantics.
The trigger language is extremely broad and includes common phrasings plus automatic triggering on pasted social-media URLs. This increases the chance of unintended invocation, causing the agent to fetch and process external content, incur cost, and transmit user-supplied media to third-party services when the user may only be asking a simple question.
The skill metadata scopes operation to YouTube, Instagram, and Facebook, but the documentation explicitly broadens behavior to any yt-dlp-supported site. This creates a capability expansion beyond the declared trust boundary, increasing the chance the agent is invoked on unsupported or riskier sites with different authentication, legal, or content-handling requirements.
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
echo ""
echo "WARNING: ffmpeg not found. Install it before using this skill:"
echo " macOS: brew install ffmpeg"
echo " Ubuntu/Debian: sudo apt install ffmpeg"
echo " Windows: https://ffmpeg.org/download.html"
echo ""
fi
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
echo ""
echo "WARNING: ffmpeg not found. Install it before using this skill:"
echo " macOS: brew install ffmpeg"
echo " Ubuntu/Debian: sudo apt install ffmpeg"
echo " Windows: https://ffmpeg.org/download.html"
echo ""
fi
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
if platform == "facebook":
cmd += ["--impersonate", "Chrome-99"]
subprocess.run(cmd, capture_output=True, text=True)
title = "Untitled Video"
info_file = work_dir / "video.info.json"
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
if platform == "facebook":
cmd += ["--impersonate", "Chrome-99"]
subprocess.run(cmd, capture_output=True, text=True)
title = "Untitled Video"
info_file = work_dir / "video.info.json"
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
if platform == "facebook":
cmd += ["--impersonate", "Chrome-99"]
subprocess.run(cmd, capture_output=True, text=True)
title = "Untitled Video"
info_file = work_dir / "video.info.json"
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
# Scene-detection pass
filter_expr = "select='gt(scene\\,0.25)*gte(t-prev_selected_t\\,2)',setpts=N/FRAME_RATE/TB"
subprocess.run(
["ffmpeg", "-i", str(video_path), "-vf", filter_expr,
"-vsync", "vfr", "-q:v", "2",
str(frames_dir / "frame_%04d.jpg"), "-y", "-loglevel", "error"],
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
if len(frames) < 5:
for f in frames:
f.unlink()
subprocess.run(
["ffmpeg", "-i", str(video_path), "-vf", "fps=1/15",
str(frames_dir / "frame_%04d.jpg"), "-y", "-loglevel", "error"],
capture_output=True,
The code forwards untrusted transcript text verbatim to the LLM and instructs it to extract as much as possible, which encourages reproduction and summarization of any secrets, personal data, or sensitive spoken/captioned content present in the source. In a video-analysis skill, this is more dangerous because videos frequently include API keys on screen, personal details, internal meeting content, or confidential narration that the model will surface into a durable Markdown artifact.
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
("yt-dlp", "--version", "pip install yt-dlp"),
]:
try:
r = subprocess.run([tool, ver_flag], capture_output=True, timeout=20)
except (FileNotFoundError, subprocess.TimeoutExpired):
sys.exit(f"[error] '{tool}' not found or timed out. Install: {install_hint}")
if r.returncode != 0:
The skill sends extracted video frames and the full transcript to Anthropic for analysis, but there is no explicit consent, warning, redaction step, or policy gate before transmitting potentially sensitive third-party content. In this skill context, users may paste private, copyrighted, or credential-bearing videos, making silent exfiltration to an external API materially risky.
The dependency yt-dlp is completely unpinned, so installs may pull different versions over time, including releases with known security issues or breaking behavior. In a skill that fetches and processes untrusted remote video content, supply-chain drift increases exposure and makes security posture non-reproducible.
yt-dlp
anthropic>=0.30.0
Pillow>=10.0.0
faster-whisper>=1.0.0
yt-dlp has multiple known advisories, and because no exact version is pinned, there is no way to verify that deployments avoid affected releases. This skill's purpose—retrieving and processing content from arbitrary social/video URLs—makes weaknesses in the downloader more relevant than in a less exposed application.
anthropic>=0.30.0 allows any newer version, which can introduce vulnerable or incompatible releases without review. Because this skill likely processes user-supplied content and may handle transcripts or generated documents, uncontrolled dependency upgrades create avoidable supply-chain risk.
yt-dlp
anthropic>=0.30.0
Pillow>=10.0.0
faster-whisper>=1.0.0
The anthropic package has known advisories, and without exact pinning the manifest cannot prove whether the installed version is patched. The context is somewhat less directly dangerous than the media-parsing stack, but it still creates avoidable uncertainty around SDK behavior and local file handling.
Pillow>=10.0.0 is not pinned to a specific version, so builds are not reproducible and may consume a later release with unresolved image-parsing issues. Since this skill analyzes extracted video frames, it directly relies on image handling of potentially untrusted media, making dependency hygiene more important.
yt-dlp
anthropic>=0.30.0
Pillow>=10.0.0
faster-whisper>=1.0.0
Pillow has a long history of image parsing vulnerabilities, and the unpinned requirement makes it impossible to verify that only a patched version will be installed. Because this skill processes video frames and images derived from user-provided URLs, a vulnerable image library is more dangerous in this context than in a package that never handles untrusted media.