T09 · Insecure Skill Coding Practices
- Location
scripts/transcribe.py:2424- Finding
Hugging Face Token Is Exposed to Unrelated Child Processes
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This transcription skill is useful and mostly transparent, but it needs Review because it can fetch arbitrary network media, use Hugging Face credentials, and update/install unpinned code without tight safeguards.
Install only if you are comfortable with a transcription tool that can contact external media sites, Hugging Face, package indexes, and optional Docker images. Avoid using it with private RSS/URLs or sensitive Hugging Face tokens unless you can isolate the environment, prefer pinned dependencies/images, and do not open generated HTML transcripts from untrusted audio without sanitizing them first.
scripts/transcribe.py:2424Hugging Face Token Is Exposed to Unrelated Child Processes
scripts/transcribe.py:849Unrestricted URL and RSS Retrieval Permits SSRF-Style Internal Network Access
requirements.txt:1Unpinned Dependencies and Unconstrained Updates Create Supply-Chain Risk
The skill documents capabilities that read/write files, invoke shell commands, access environment-resident secrets, and make network requests, but it declares no explicit tool scope or permission boundaries. In an agent setting, that gap can lead to over-broad execution authority, making risky behaviors like arbitrary URL fetching, local file writes, and shell invocation available without clear policy enforcement.
The skill is presented as 'local speech-to-text', but the documentation also includes remote model downloads, URL/YouTube/RSS fetching, HuggingFace token use, and an API server mode. That mismatch can mislead users and policy systems into treating the skill as offline-only when it can initiate external network activity and expose local services.
The skill describes URL, RSS, and YouTube inputs that automatically download remote content, but it does not prominently warn that doing so contacts third-party services and may transmit IP address, request metadata, feed access patterns, or authentication-linked model-download activity. Users may reasonably assume 'local' means no network disclosure, making this omission security-relevant.
The trigger phrases include broad, everyday language such as 'what did they say' and 'make a transcript', which can cause accidental or overly eager invocation by an agent router. In a skill with file, shell, and network capabilities, unintended activation increases the chance of processing sensitive media or fetching remote content without sufficiently explicit user intent.
Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.
## Quick Reference
| Task | Command | Notes |
| ------------------------------ | -------------------------------------------------------------------------------------- | --------------------------------------------------- |
| **Basic transcription** | `./scripts/transcribe audio.mp3` | Batched inference, VAD on, distil-large-v3.5 |
| **SRT subtitles** | `./scripts/transcribe audio.mp3 --format srt -o subs.srt` | Word timestamps auto-enabled |
The documentation references running a container from ghcr.io/speaches-ai/speaches:latest-cuda, which is a mutable tag rather than a pinned immutable digest. If the upstream image changes or is compromised, users may unknowingly execute different code than expected, creating a supply-chain risk.
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.
- **OOM**: Lower `--batch-size` (try 4) if you hit out-of-memory errors
- **Pre-convert to WAV** (optional): `ffmpeg -i input.mp3 -ar 16000 -ac 1 input.wav` converts to 16kHz mono WAV before transcription. Benefit is minimal (~5%) for one-off use since PyAV decodes efficiently — most useful when re-processing the same file multiple times (research/experiments) or when a format causes PyAV decode issues. Note: `--normalize` and `--denoise` already perform this conversion automatically.
- **Silero VAD V6**: faster-whisper 1.2.1 upgraded to Silero VAD V6 (improved speech detection). Run `./setup.sh --update` to get it.
- **Batched silence removal**: faster-whisper 1.2.0+ automatically removes silence in `BatchedInferencePipeline` (used by default). Upgrade with `./setup.sh --update` to get this if you installed before August 2024.
## Why faster-whisper?
The HTML formatter injects unescaped file names, plain segment text, speaker labels, and especially word tokens directly into HTML markup. Because transcript content can come from attacker-controlled audio or remote media, this can produce stored XSS when the generated HTML is opened in a browser.
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
if not quiet:
print(f"🎚️ Extracting {channel} channel...", file=sys.stderr)
try:
subprocess.run(cmd, check=True, capture_output=True)
return tmp_path, tmp_path
except subprocess.CalledProcessError:
if not quiet:
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
if not quiet:
print(f"🎚️ Extracting {channel} channel...", file=sys.stderr)
try:
subprocess.run(cmd, check=True, capture_output=True)
return tmp_path, tmp_path
except subprocess.CalledProcessError:
if not quiet:
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
if not quiet:
print(f"🎚️ Extracting {channel} channel...", file=sys.stderr)
try:
subprocess.run(cmd, check=True, capture_output=True)
return tmp_path, tmp_path
except subprocess.CalledProcessError:
if not quiet:
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
]
if not quiet:
print(f"🎬 Burning subtitles into {output_path}...", file=sys.stderr)
subprocess.run(cmd, check=True)
else:
subprocess.run(cmd, check=True, capture_output=True)
if not quiet:
The code downloads audio from arbitrary URLs with yt-dlp and fetches podcast RSS feeds via urllib, which sends user-provided network destinations and may expose system IP/addressing information to third parties. Although there are progress messages, there is no clear user disclosure in comments, help text, or prompts warning that remote services will be contacted and external content downloaded.
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
print("⬇️ Downloading audio from URL...", file=sys.stderr)
try:
subprocess.run(cmd, check=True, capture_output=quiet)
except subprocess.CalledProcessError as e:
print(f"Error downloading URL: {e}", file=sys.stderr)
shutil.rmtree(tmpdir, ignore_errors=True)
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
if not audio_path.lower().endswith(".wav"):
tmp_wav = audio_path + ".diarize.wav"
try:
subprocess.run(
["ffmpeg", "-y", "-i", audio_path, "-ar", "16000", "-ac", "1", tmp_wav],
check=True, capture_output=True,
)
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
)
try:
subprocess.run(cmd, check=True, stderr=subprocess.DEVNULL if quiet else None)
if not quiet:
print(f" 💾 {out_file}", file=sys.stderr)
except subprocess.CalledProcessError as e:
A transcription skill does not need the ability to modify its installed package set during routine use, yet this file implements exactly that. Self-update materially increases supply-chain exposure and weakens change control because a user-invoked flag can pull and execute new dependency code from remote repositories.
The skill includes a self-update path that executes package-manager commands to fetch and install newer code at runtime, which exceeds the minimal requirements of a local transcription tool. This expands the trust boundary to remote package sources and can introduce unreviewed code changes or supply-chain compromise into the skill environment.
if "--update" in sys.argv:
_venv_python = _SCRIPT_DIR.parent / ".venv" / "bin" / "python"
if shutil.which("uv"):
subprocess.run(
["uv", "pip", "install", "--python", str(_venv_python), "--upgrade", "faster-whisper"],
check=True,
)
Like the adjacent uv-based branch, this pip-based self-update command installs the latest faster-whisper package into the skill venv on demand. That creates avoidable supply-chain and integrity risk because executing the skill can modify its own code dependencies from the network without any pinning or review.
check=True,
)
else:
subprocess.run(
[str(_venv_python), "-m", "pip", "install", "--upgrade", "faster-whisper"],
check=True,
)
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
import subprocess as _sp
cmd = ["ffmpeg", "-i", path, "-ar", str(sampling_rate), "-ac", "1",
"-f", "f32le", "-"]
result = _sp.run(cmd, capture_output=True, check=True)
return np.frombuffer(result.stdout, dtype=np.float32)
exit_code = 0
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
if [ "$OS_TYPE" = "macos" ]; then
echo " brew install ffmpeg"
else
echo " Ubuntu/Debian: sudo apt install ffmpeg"
echo " Fedora: sudo dnf install ffmpeg"
echo " Arch: sudo pacman -S ffmpeg"
fi
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
if [ "$OS_TYPE" = "macos" ]; then
echo " brew install ffmpeg"
else
echo " Ubuntu/Debian: sudo apt install ffmpeg"
echo " Fedora: sudo dnf install ffmpeg"
echo " Arch: sudo pacman -S ffmpeg"
fi
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
if [ "$OS_TYPE" = "macos" ]; then
echo " brew install ffmpeg"
else
echo " Ubuntu/Debian: sudo apt install ffmpeg"
echo " Fedora: sudo dnf install ffmpeg"
echo " Arch: sudo pacman -S ffmpeg"
fi
The manifest declares access to a local Hugging Face authentication token path, which can expose credentials usable to access private models or account-scoped resources. In a speech-to-text skill, that access is not clearly justified in the user-facing metadata, so users may not realize the skill can read sensitive local secrets if optional functionality is triggered.
The dependency is specified with a lower bound only, which allows future unreviewed versions of faster-whisper to be installed. This creates supply-chain risk because a malicious or breaking upstream release could be pulled into the environment without explicit approval, affecting a security-sensitive package that processes external media inputs.
# Core dependency — PyTorch installed separately by setup script (with CUDA if GPU detected)
faster-whisper>=1.2.1
No suspicious patterns detected.