T09 · Insecure Skill Coding Practices
- Location
scripts/transcribe_tracked_light.mjs:7- Finding
Predictable Output Files Are Overwritten Without Symlink or Path Validation
- Content
View full analysis
Vulnerability Details
File Location:
scripts/transcribe_tracked_light.mjs:7-20, 33-35, 53, 65, 67-68;scripts/final_structurer.py:4-8, 24-27, 31-32, 118-120
Vulnerability Type: Unsafe file handling and predictable workspace files
Risk Level: MediumVulnerable Code
scripts/transcribe_tracked_light.mjs:7-20:javascript const BASE = process.argv[2] || process.cwd(); const VIDEO = `${BASE}/video.mp4`; const OUTPUT = `${BASE}/transcript.jsonl`; const STATUS = `${BASE}/status.json`; const ANALYSIS = `${BASE}/analysis.md`; const LOG = `${BASE}/progress.log`; const CHUNK = 15; const MODEL = 'Xenova/whisper-tiny'; function writeStatus(patch) { let current = {}; try { current = JSON.parse(fs.readFileSync(STATUS, 'utf8')); } catch {} fs.writeFileSync(STATUS, JSON.stringify({ ...current, ...patch, updatedAt: new Date().toISOString() }, null, 2)); } function log(line) { fs.appendFileSync(LOG, line + '\n'); }scripts/transcribe_tracked_light.mjs:33-35:javascript fs.writeFileSync(OUTPUT, ''); fs.writeFileSync(LOG, ''); fs.writeFileSync(ANALYSIS, '# Video analysis\n\n_In progress..._\n');scripts/final_structurer.py:24-32:python def write_status(**patch): current = {} if STATUS.exists(): try: current = json.loads(STATUS.read_text()) except Exception: current = {} current.update(patch) current['updatedAt'] = time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime()) STATUS.write_text(json.dumps(current, ensure_ascii=False, indent=2)) def log(msg): with LOG.open('a', encoding='utf-8') as f: f.write(msg + '\n')Technical Analysis
The JavaScript script accepts its base directory directly from a command-line argument and constructs all input and output paths through string concatenation. Neither script validates that its destination paths resolve inside an app ...[truncated 2266 chars]
- Remediation
View remediation
Remediation Suggestions
- Resolve the requested base directory with
realpathand require it to be a descendant of a dedicated, trusted workspace. - Inspect every existing destination with
lstatand reject symbolic links, non-regular files, and paths whose resolved parent escapes the approved workspace. - Create a private per-run directory with restrictive permissions rather than relying on fixed filenames in a shared directory.
- Write status and analysis artifacts to temporary files in the same directory, flush them, and atomically rename them into place.
- Use exclusive creation where replacement is unnecessary and explicitly control file permissions.
- Do not truncate existing transcripts or logs automatically. Detect prior output, support deliberate resume behavior, or require an explicit overwrite option.
- Validate that
video.mp4is a regular file before creating or truncating any output. - Apply the same checks to temporary chunk files, including
chunk_<start>.wav, and clean them up through a protected per-run directory.
- Resolve the requested base directory with
