T05 · Unauthorized Access and Privilege Escalation
- Location
scripts/audit.cjs:231- Finding
Target Directory Escape Through Symbolic File Links
- Content
View full analysis
Vulnerability Details
File Location:
scripts/audit.cjs:231-260
Vulnerability Type: Target-boundary bypass through symbolic links
Risk Level: MediumVulnerable Code
js function readUtf8(filePath) { try { return fs.readFileSync(filePath, 'utf8'); } catch { return null; } } function getFilesRecursively(dir, extensions = DEFAULT_EXTENSIONS, ignoredDirs = DEFAULT_IGNORED_DIRS) { const files = []; function walk(currentDir) { let entries = []; try { entries = fs.readdirSync(currentDir, { withFileTypes: true }); } catch { return; } for (const entry of entries) { const fullPath = path.join(currentDir, entry.name); if (entry.isDirectory()) { if (!ignoredDirs.has(entry.name)) { walk(fullPath); } continue; } if (extensions.some(ext => entry.name.endsWith(ext))) { files.push(fullPath); } } } walk(dir); return files; }Technical Analysis
Recursive discovery does not reject symbolic links or verify that each candidate's canonical path remains beneath the canonical
--targetdirectory. A symbolic link is not treated as a directory byentry.isDirectory(), so a file symlink whose name has an accepted extension is added to the scan list. Later,fs.readFileSync()follows the symbolic link and reads its destination.For example, a repository may contain
config.jsonas a symbolic link to a sensitive JSON file outside the repository. When the repository is audited, the external file is read using the auditor process's privileges. This violates the documented target boundary.The scanner does not include matched secret values in its report, which limits direct disclosure. Nevertheless, generated findings can reveal the destination file's existence and content characteristics, including whether it appears to contain private keys, credentials, passwords, tokens, or risky configuration.
Attack Path
- A ...[truncated 1314 chars]
- Remediation
View remediation
Remediation Suggestions
- Reject symbolic links during recursive discovery by checking
entry.isSymbolicLink()before accepting a file. - Canonicalize the target root once with
fs.realpathSync()orfs.realpathSync.native(). - Before every file read, canonicalize the candidate path and use
path.relative()to verify that it remains beneath the canonical target root. - Reject candidates when the relative path is absolute, equals
.., or begins with..followed by a path separator. - Perform containment validation immediately before opening the file to reduce time-of-check/time-of-use risk.
- Prefer opening files without following symlinks where the platform supports an equivalent to
O_NOFOLLOW, and then inspect the opened descriptor. - Apply the same containment policy to explicitly supplied
--env-fileand--dockerfilepaths unless reading external files is an intentional, clearly documented capability. - Add regression tests covering file symlinks to external files, links within the target, broken links, and link replacement during scanning.
- Reject symbolic links during recursive discovery by checking
