T09 · Insecure Skill Coding Practices
- Location
scripts/transcribe.py:28- Finding
Sensitive narration audio and plaintext transcripts persist in temporary directories
- Content
View full analysis
str: out_dir = tempfile.mkdtemp(prefix="teach_whisper_") if shutil.which("whisper"): subprocess.run( ["whisper", wav, "--model", model, "--output_format", "txt", "--output_dir", out_dir], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, ) else: subprocess.run( [sys.executable, "-m", "whisper", wav, "--model", model, "--output_format", "txt", "--output_dir", out_dir], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, ) txt = os.path.join(out_dir, os.path.splitext(os.path.basename(wav))[0] + ".txt") return open(txt, encoding="utf-8").read() ``` ```python wav = os.path.join(tempfile.mkdtemp(prefix="teach_audio_"), "narration.wav") ``` ### Technical Analysis The transcription script creates two persistent temporary directories using `tempfile.mkdtemp()`: - `teach_audio_*` contains the extracted, unredacted narration as a WAV file. - `teach_whisper_*` contains the generated plaintext transcript. Neither directory is deleted after successful processing or when an exception occurs. The script also does not report these paths to the calling agent. Consequently, the cleanup instruction in `SKILL.md`, which covers the original recording and reported frame or part files, cannot reliably remove these hidden temporary artifacts. The transcript is read using `open()` without a context manager, although the more consequential issue is that the transcript and audio files remain on disk. Application-level redaction performed after transcription cannot protect the original WAV or raw Whisper output, both of which may contain passwords, one- ...[truncated 1304 chars]- Remediation
View remediation
str: with tempfile.TemporaryDirectory(prefix="teach_whisper_") as out_dir: if shutil.which("whisper"): cmd = [ "whisper", wav, "--model", model, "--output_format", "txt", "--output_dir", out_dir, ] else: cmd = [ sys.executable, "-m", "whisper", wav, "--model", model, "--output_format", "txt", "--output_dir", out_dir, ] subprocess.run( cmd, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, ) txt = os.path.join( out_dir, os.path.splitext(os.path.basename(wav))[0] + ".txt", ) with open(txt, encoding="utf-8") as transcript_file: return transcript_file.read() ``` 2. Scope the extracted WAV similarly: ```python with tempfile.TemporaryDirectory(prefix="teach_audio_") as audio_dir: wav = os.path.join(audio_dir, "narration.wav") extract_audio(video, wav) transcript = run_whisper(wav, model) ``` 3. Place cleanup in `finally` blocks if scoped context managers cannot be used, ensuring deletion on success, interruption, extraction failure, and Whisper failure. 4. Restrict temporary-directory permissions to the current user and avoid globally readable temporary locations. 5. Add tests that execute both successful and failing transcription paths and verify that no `teach_audio_*` or `teach_whisper_*` directories remain afterward. 6. Update the cleanup documentation to explicitly cover extracted audio and raw transcript files. ]]>
