T09 · Insecure Skill Coding Practices
Warning
- Location
- src/disk-watch.js:17
- Finding
- Predictable Shared Temporary History File Permits Symlink-Based File Overwrite## Vulnerability Details **File Location**: `src/disk-watch.js:17` and `src/disk-watch.js:161-166` **Vulnerability Type**: Unsafe temporary file handling and symlink following **Risk Level**: Medium ### Vulnerable Code ```javascript this.historyFile = options.historyFile || path.join(os.tmpdir(), 'disk-watch-history.json'); ``` ```javascript _saveHistory(drives) { try { let history = []; try { history = JSON.parse(fs.readFileSync(this.historyFile, 'utf8')); } catch {} history.push({ timestamp: Date.now(), drives }); if (history.length > 168) history = history.slice(-168); // Keep 1 week at hourly fs.writeFileSync(this.historyFile, JSON.stringify(history, null, 2)); } catch {} } ``` ### Technical Analysis DiskWatch stores its history at a fixed, predictable filename under the operating system's shared temporary directory. The code subsequently opens that path with `fs.writeFileSync()`, which follows symbolic links by default. The implementation does not: - Verify the file with `lstat()` before writing. - Confirm that the file is a regular file owned by the current user. - Reject symbolic links. - Create the file exclusively. - Use a private per-user directory with restrictive permissions. - Perform an atomic, securely validated replacement. On systems where another local user can create the predictable path, an attacker can place a symbolic link at that location. If a victim subsequently runs DiskWatch with permissions to modify the symlink target, `_saveHistory()` follows the link and truncates or replaces the target's contents with JSON history data. Exploitability can be reduced by operating-system protections for shared temporary directories, such as sticky-directory and protected-symlink policies, but the application itself does not enforce those protections. ### Attack Path 1. A local attacker determines the temporary directory returned by `os.tmpdir()`. 2. B ...[truncated 1500 chars]
- Remediation
- ## Remediation Suggestions 1. Store history in a private per-user application data directory rather than directly in the shared temporary directory. 2. Create the containing directory with mode `0700` and verify that it is owned by the current user. 3. Before reading or replacing an existing history file, use `fs.lstatSync()` and reject symbolic links, non-regular files, unexpected ownership, and overly permissive modes. 4. Create new files with restrictive permissions such as `0600` and exclusive creation flags where appropriate. 5. Write updates to a securely created temporary file in the same private directory, flush and close it, and then atomically rename it over the validated history file. 6. Where supported, use no-follow filesystem semantics when opening files. Do not rely solely on a separate check followed by an open, because that introduces a time-of-check/time-of-use race. 7. Avoid silently swallowing history I/O and validation errors. Surface or log security-relevant failures so unsafe path conditions can be diagnosed. 8. If callers provide `historyFile`, document that the path must reside in a trusted directory and apply the same ownership, file-type, and symlink validation.
