T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/humanize-de.js:1257
- Finding
- Predictable Output Path Allows Symbolic-Link File Overwrite## Vulnerability Details **File Location**: `scripts/humanize-de.js:1257-1258` **Vulnerability Type**: Symbolic-link following and unsafe predictable output file **Risk Level**: Medium ### Complete Code Snippet ```js const outPath = path.join(dir, `${base}.fixed${ext}`); fs.writeFileSync(outPath, fixed, 'utf-8'); ``` ### Technical Analysis The `fix` command derives a predictable output path from the input filename and writes to it unconditionally. Node.js `fs.writeFileSync()` follows an existing symbolic link, while this implementation does not inspect the destination with `lstatSync()`, reject symbolic links, request exclusive creation, or obtain confirmation before replacing an existing file. An attacker who can create files in the input directory can therefore prepare the expected output path as a symbolic link to another file writable by the user running the command. When the user invokes `fix`, the linked target is truncated and replaced with the transformed document. The backup logic does not prevent this issue because the vulnerable write affects the separate `.fixed` destination. ### Attack Path 1. A victim has an input file named `document.md` in a shared or attacker-controlled directory. 2. The attacker predicts that the command will write to `document.fixed.md`. 3. The attacker creates `document.fixed.md` as a symbolic link to a target file that the victim can modify. 4. The victim runs: ```bash node scripts/humanize-de.js fix document.md ``` 5. `fs.writeFileSync()` follows the symbolic link and truncates the linked target. 6. The target is replaced with the transformed contents of `document.md`. ### Impact Assessment Exploitation permits overwrite of any file writable by the invoking user and reachable through the prepared symbolic link. Potential consequences include data loss, corruption of user configuration, or modification of scripts and other files later consumed by trusted ap ...[truncated 348 chars]
- Remediation
- ## Remediation Suggestions 1. Refuse to use an existing output destination by opening it with exclusive creation: ```js const fd = fs.openSync(outPath, 'wx', 0o600); try { fs.writeFileSync(fd, fixed, 'utf8'); } finally { fs.closeSync(fd); } ``` 2. Before writing, use `fs.lstatSync()` when the path exists and explicitly reject symbolic links and non-regular files. Treat this as defense in depth rather than relying on a separate check alone, because check-then-write sequences can be subject to race conditions. 3. Use no-follow filesystem semantics where the platform and Node.js version support them. Combine no-follow behavior with exclusive creation to prevent both symbolic-link traversal and unintended replacement. 4. Avoid predictable destinations in shared directories. Create output through a securely generated temporary filename in a trusted directory, then atomically rename it only after validating the final destination. 5. Require explicit user confirmation before replacing any existing `.fixed` file, or fail safely and ask the user to choose another path. 6. Apply equivalent safeguards to the `.bak` destination so future changes cannot introduce the same symbolic-link issue in backup creation. 7. Document that input and output operations should not be performed in untrusted writable directories until secure destination handling is implemented.
