T09 · Insecure Skill Coding Practices
- Location
scripts/stt_simple.py:39- Finding
Unvalidated Session Identifier Allows Transcript Writes Outside the Intended Output Directory
- Content
View full analysis
Vulnerability Details
File Location:
scripts/stt_simple.py, lines 39-55; attacker-controlled input originates at line 74
Vulnerability Type: Path traversal and arbitrary file placement
Risk Level: HighVulnerable Code:
python # Determine output directory based on session_id if session_id: # Use session-specific subdirectory for multi-Agent isolation output_dir = os.path.join(BASE_OUTPUT_DIR, session_id) else: # Default shared directory output_dir = BASE_OUTPUT_DIR os.makedirs(output_dir, exist_ok=True) # Generate unique filename with timestamp to avoid collisions base_name = Path(audio_path).stem timestamp = uuid.uuid4().hex[:8] output_txt = os.path.join(output_dir, f"{base_name}_{timestamp}.txt") with open(output_txt, "w", encoding="utf-8") as f: f.write(result["text"])The value used by this code is obtained directly from the command line:
python session_id = sys.argv[4] if len(sys.argv) > 4 else NoneTechnical Analysis
The
session_idargument is used as a filesystem path component without validation or canonical-path containment checks. Python'sos.path.join()does not guarantee that the resulting path remains beneathBASE_OUTPUT_DIR.A session identifier containing parent-directory segments, such as
../../other-directory, can traverse outside the intended output directory. Ifsession_idis an absolute path,os.path.join(BASE_OUTPUT_DIR, session_id)discards the base path entirely and returns the absolute path.The program subsequently calls
os.makedirs()on the resulting path and writes the transcript to it. The randomized filename suffix limits deterministic replacement of a specific existing file, but it does not prevent arbitrary directory creation or placement of attacker-influenced transcript data in unintended filesystem locations.Attack Path
- An attacker or untrusted caller supplies a valid audio f ...[truncated 1347 chars]
- Remediation
View remediation
Remediation Suggestions
- Restrict
session_idto a conservative identifier format, for example^[A-Za-z0-9_-]{1,64}$. - Reject absolute paths, path separators,
.components, and..components. - Resolve both the base directory and candidate directory to canonical paths, then verify that the candidate remains beneath the base directory before creating it.
- Use
pathlib.Pathcontainment checks rather than relying only on string-prefix comparisons. - Run the transcription process under a dedicated unprivileged account with write access limited to the transcript directory.
- Set restrictive output permissions and consider per-session access controls because transcripts may contain sensitive information.
- Add tests covering absolute paths, parent traversal, nested traversal, symlink traversal, empty identifiers, and excessively long identifiers.
Example hardening approach:
python import re from pathlib import Path base_dir = Path(BASE_OUTPUT_DIR).resolve() if session_id: if not re.fullmatch(r"[A-Za-z0-9_-]{1,64}", session_id): raise ValueError("Invalid session identifier") output_dir = (base_dir / session_id).resolve() if output_dir.parent != base_dir: raise ValueError("Session directory escapes output root") else: output_dir = base_dir- Restrict
