T08 · Insecure Dependencies
- Location
README.md:40- Finding
Unpinned Third-Party Dependencies Allow Supply-Chain Version Drift
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill appears to make audiobooks as advertised, but it needs review because it downplays first-run network downloads and uses unpinned install commands that can change what code runs.
Review this before installing in offline, sensitive, or policy-restricted environments. Pre-download and verify the model assets if you need no runtime network access, pin and hash dependencies where possible, and run it only on manuscripts and output directories you intentionally choose.
README.md:40Unpinned Third-Party Dependencies Allow Supply-Chain Version Drift
scripts/verify_job.py:54Manifest-Controlled Paths Can Escape the Selected Job Directory
The README makes a strong 'no network at run time' and 'fully local' claim, but later admits the model and voice assets are fetched automatically on first synthesis from HuggingFace. This is a real documentation integrity issue because users may run the skill in offline, restricted, or sensitive environments based on that claim and unintentionally trigger outbound network access or fail at runtime.
This is the same underlying issue as SDI-1: the documentation presents the workflow as having no runtime network dependency, while first use actually performs automatic downloads. In security-conscious deployments, misleading network-behavior claims can cause policy violations, unreliable operation, or accidental trust in unvetted remote artifacts.
The skill describes and instructs use of file read/write and shell execution via Python scripts, but it declares no explicit tool scope or permissions. That increases the chance an agent platform grants broader capabilities than intended or invokes the skill without sufficient user visibility into its access needs.
The trigger phrases are broad natural-language requests like 'read this aloud' and 'narrate this,' which could match ordinary user intent too loosely and cause unintended invocation. In a skill that writes output files and runs local scripts, accidental activation can lead to unnecessary file processing or command execution without the user explicitly choosing this workflow.
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
def probe_duration(path: Path) -> float:
r = subprocess.run(
["ffprobe", "-v", "error", "-show_entries", "format=duration",
"-of", "default=noprint_wrappers=1:nokey=1", str(path)],
capture_output=True, text=True, check=True,
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
"-shortest", "-movflags", "+faststart",
str(out),
]
subprocess.run(cmd, check=True, capture_output=True, text=True)
def faststart_ok(path: Path) -> bool:
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
"print(json.dumps(d))"
)
try:
r = subprocess.run([python_bin, "-c", probe],
capture_output=True, text=True, check=False)
line = r.stdout.strip().splitlines()[-1] if r.stdout.strip() else "{}"
out.update(json.loads(line))
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
except Exception:
out["python"] = "unknown"
try:
ff = subprocess.run(["ffmpeg", "-version"],
capture_output=True, text=True, check=False)
out["ffmpeg"] = ff.stdout.splitlines()[0] if ff.stdout else "unknown"
except FileNotFoundError:
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
"--output_path", str(seg_dir),
"--file_prefix", prefix,
]
r = subprocess.run(cmd, input=text, capture_output=True, text=True, check=False)
if r.returncode != 0:
raise RuntimeError(
f"CLI exit {r.returncode}: {r.stderr.strip().splitlines()[-1:]}"
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
def preflight(python_bin: str, model: str) -> None:
"""Fail fast with a clear message if the engine is not importable."""
r = subprocess.run(
[python_bin, "-c", "import mlx_audio.tts.generate"],
capture_output=True, text=True, check=False,
)
The script writes a concat list for ffmpeg using unescaped file paths and enables ffmpeg concat with -safe 0. If a segment path contains quotes or specially crafted characters, ffmpeg may misparse the list, potentially reading unintended files or failing in unsafe ways; because file names derive from filesystem paths under user-controlled output locations, this is a real file-parsing/injection surface even though no shell is used.
with open(listfile, "w") as f:
for seg in segments:
f.write(f"file '{Path(seg).resolve()}'\n")
subprocess.run(
["ffmpeg", "-y", "-f", "concat", "-safe", "0", "-i", str(listfile),
"-c", "copy", str(master)],
check=True, capture_output=True, text=True,
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
def encode_mp3(master: Path, mp3: Path):
subprocess.run(
["ffmpeg", "-y", "-i", str(master),
"-codec:a", "libmp3lame", "-qscale:a", "2", str(mp3)],
check=True, capture_output=True, text=True,
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
def decodes(path: Path) -> bool:
r = subprocess.run(["ffmpeg", "-v", "error", "-i", str(path), "-f", "null", "-"],
capture_output=True, text=True, check=False)
return r.returncode == 0 and not r.stderr.strip()
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
def decodes(path: Path) -> bool:
r = subprocess.run(["ffmpeg", "-v", "error", "-i", str(path), "-f", "null", "-"],
capture_output=True, text=True, check=False)
return r.returncode == 0 and not r.stderr.strip()
The README does mention automatic downloads, but it does not elevate this as a prominent operational/security warning despite earlier emphasizing a local, no-network runtime. That omission can mislead users about egress behavior and supply-chain exposure from fetching model weights at execution time.
No suspicious patterns detected.