T09 · Insecure Skill Coding Practices
- Location
scripts/batch_transcribe.py:132- Finding
Unvalidated force-date argument enables arbitrary recursive directory deletion
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This transcription skill is coherent overall, but needs review because some optional flags can delete or overwrite user-controlled paths and send job details to an arbitrary webhook URL.
Review this before installing. Use it only in a constrained working directory, avoid --force-dates unless the arguments are trusted date strings, avoid pointing --progress-file at existing important files, and do not use --discord-webhook unless you are comfortable sending filenames, dates, status, and error details to that endpoint. Prefer pinned dependencies and a sandboxed environment for model downloads and transcription runs.
scripts/batch_transcribe.py:132Unvalidated force-date argument enables arbitrary recursive directory deletion
scripts/batch_transcribe.py:43Caller-controlled progress path permits arbitrary file overwrite
scripts/batch_transcribe.py:56Unrestricted webhook URL enables server-side request forgery
SKILL.md:36Setup instructions install unpinned dependencies and retrieve mutable model artifacts
Referenced artifact was not completely inspected
The bundled `scripts/batch_transcribe.py` handles the full daylog pipeline:
Referenced artifact was not completely inspected
The bundled `scripts/batch_transcribe.py` handles the full daylog pipeline:
Referenced artifact was not completely inspected
The bundled `scripts/batch_transcribe.py` handles the full daylog pipeline:
Referenced artifact was not completely inspected
The bundled `scripts/batch_transcribe.py` handles the full daylog pipeline:
Referenced artifact was not completely inspected
The bundled `scripts/batch_transcribe.py` handles the full daylog pipeline:
The skill documents shell execution, file writing, and network use but does not declare any tool scope or permissions boundaries. That mismatch increases the risk of over-privileged execution and makes it harder for a caller or runtime to understand that transcription can also write files and send outbound requests.
The sample invocation sets language='zh' and the parsing logic splits on <|zh|> tags, which forces a specific language behavior. The document does not present this as an opt-in choice or clearly justify that the skill is limited to Chinese-only usage.
The manifest and description present the skill as a local transcription tool, but the documented batch behavior also performs external Discord notifications. This scope drift is dangerous because operators may grant or run the skill assuming offline processing while it can transmit metadata externally.
Discord webhook posting introduces an external network channel that is not necessary for core transcription. In a skill handling potentially sensitive audio workflows, even progress or filename metadata sent to a third party can create privacy and data-governance issues beyond the stated purpose.
Posting transcription progress to Discord can disclose sensitive operational metadata such as processing times, dates, filenames, or activity patterns, yet the skill provides no privacy warning or consent guidance. In the context of daylog audio, that metadata may itself be confidential even if transcript text is not sent.
The script includes destructive behavior that deletes existing transcripts when --force-dates is used, but the top-level description presents it primarily as a batch transcription tool. That mismatch can lead to accidental data loss because operators may not anticipate recursive deletion of prior outputs.
The script can send transcription job metadata to an external Discord webhook, which introduces outbound data exfiltration capability unrelated to the core local transcription function. Even if it only sends filenames, dates, failure messages, and progress by default, those details can reveal sensitive recording activity and operational information to a third party.
The outbound webhook feature creates an unnecessary network egress path in a transcription utility, expanding the attack surface and enabling unauthorized sharing of job state externally. In a skill expected to process potentially sensitive audio locally, hidden or poorly disclosed network transmission materially increases privacy and compliance risk.
Webhook notifications transmit operational details without any built-in confirmation, warning banner, or consent mechanism at runtime. In the context of transcription of personal recordings, even metadata such as filenames, dates, counts, and failure traces may expose sensitive information about users and their activities.
The file fixes the language/locale to Chinese via WHISPER_LANG = "zh", and later also passes language="zh" to SenseVoice, with no opt-in or user-selectable alternative. This is a natural-language locale policy concern because it forces a specific language behavior without choice or justification.
The SenseVoice generate call explicitly sets language="zh", which enforces Chinese processing regardless of user preference. Since no language selection mechanism or justification is provided, this constitutes a locale-policy issue under the natural-language rules.
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
else:
# Whisper path (unchanged from v2)
import tempfile
res = subprocess.run(
['ffmpeg', '-i', str(wav), '-af',
f'silencedetect=noise={SILENCE_NOISE_DB}dB:d={SILENCE_MIN_DUR}',
'-f', 'null', '-'],
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
me = re.search(r'silence_end: ([\d.]+)', line)
if me: silence_ends.append(float(me.group(1)))
dur_res = subprocess.run(
['ffprobe', '-v', 'quiet', '-show_entries', 'format=duration', '-of', 'json', str(wav)],
capture_output=True, text=True
)
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
try:
for idx, (seg_s, seg_e) in enumerate(non_silent):
chunk = tmpdir / f"chunk_{idx:04d}.wav"
subprocess.run(['ffmpeg', '-y', '-i', str(wav), '-ss', str(seg_s), '-to', str(seg_e), '-ar', '16000', '-ac', '1', str(chunk)], capture_output=True)
r = mlx_whisper.transcribe(str(chunk), path_or_hf_repo=WHISPER_MODEL, language=WHISPER_LANG, condition_on_previous_text=False)
for seg in r['segments']:
seg['start'] += seg_s; seg['end'] += seg_s
No suspicious patterns detected.