T09 · Insecure Skill Coding Practices
- Location
protoss_fx.py:49- Finding
Predictable Temporary Files Allow Symlink-Based File Overwrite
- Content
View full analysis
Vulnerability Details
File Location:
protoss_fx.py, lines 49-53, with unsafe file writes at lines 59-65, 84-85, and 97-104
Vulnerability Type: Predictable and unsafe temporary-file handling
Risk Level: MediumThe application derives all temporary filenames deterministically from the output filename and places them in the output directory:
python work_dir = os.path.dirname(os.path.abspath(output_path)) filename_base = os.path.splitext(os.path.basename(output_path))[0] temp_wav_in = os.path.join(work_dir, f".{filename_base}_in.wav") temp_wav_psi = os.path.join(work_dir, f".{filename_base}_psi.wav") temp_wav_mix = os.path.join(work_dir, f".{filename_base}_mix.wav")These predictable paths are subsequently passed to FFmpeg and SoX as output files:
python subprocess.run( ["ffmpeg", "-y", "-i", input_path, "-vn", temp_wav_in], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL )python cmd_psi = [ "sox", temp_wav_in, temp_wav_psi, "pitch", "-200", "reverse", "reverb", "80", "50", "100", "100", "0", "0", "reverse", "vol", "0.5" ] subprocess.run(cmd_psi, check=True)python cmd_mix = [ "sox", temp_wav_psi, temp_wav_mix, "bass", "+5", "highpass", "100", "norm", "-1" ] subprocess.run(cmd_mix, check=True)python subprocess.run( ["ffmpeg", "-y", "-i", temp_wav_mix, output_path], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL )Technical Analysis
Temporary files must be created atomically with unpredictable names inside a directory inaccessible to untrusted users. Here, an attacker can calculate each temporary pathname from the expected output name. The files are created in the output directory, which may be shared or attacker-writable.
If an external utility follows a pre-existing sy ...[truncated 2120 chars]
- Remediation
View remediation
Remediation Suggestions
-
Create a private temporary directory using
tempfile.TemporaryDirectory()and place all intermediate files inside it:python import tempfile with tempfile.TemporaryDirectory(prefix="protoss_fx_") as temp_dir: temp_wav_in = os.path.join(temp_dir, "input.wav") temp_wav_psi = os.path.join(temp_dir, "psionic.wav") temp_wav_mix = os.path.join(temp_dir, "mix.wav") # Run the processing stages inside this block. -
Ensure the temporary directory has permissions that prevent access by other users. Python's standard temporary-directory API provides unpredictable naming and suitably restrictive creation semantics on supported platforms.
-
Validate the final output path separately. Reject a pre-existing symbolic link by inspecting it with
os.path.lexists()andos.path.islink(), or use platform-appropriate no-follow and exclusive-creation controls. -
Avoid unconditional FFmpeg
-ybehavior for the final destination. Require explicit user authorization before replacing an existing output file. -
For stronger output integrity, encode into a safely created temporary file in the destination filesystem and publish it with an atomic rename only after successful processing.
-
Do not use existence checks followed by ordinary file creation as a security control because that introduces a time-of-check/time-of-use race. Rely on atomic operating-system file-creation primitives instead.
-
