T09 · Insecure Skill Coding Practices
- Location
index.js:27- Finding
Symbolic Link Following Allows Unauthorized Local JSON File Disclosure
- Content
View full analysis
f.startsWith('status_') && f.endsWith('.json')) .sort() .reverse(); return files.map(f => { const match = f.match(/status_(\d+)\.json/); const cycle = match ? parseInt(match[1], 10) : 0; const filepath = path.join(logsDir, f); let data = null; try { data = JSON.parse(fs.readFileSync(filepath, 'utf8')); ``` The same unsafe file-reading behavior is present in `get`: ```javascript function get(workspacePath, cycle) { const filepath = path.join(workspacePath, HISTORY_DIR, `status_${String(cycle).padStart(4, '0')}.json`); if (!fs.existsSync(filepath)) { return null; } return JSON.parse(fs.readFileSync(filepath, 'utf8')); } ``` ### Technical Analysis The implementation trusts entries under the workspace's `logs` directory based only on their names. It accepts entries matching the `status_*.json` naming convention and then reads them using `fs.readFileSync`. Node.js file-reading operations follow symbolic links. The code does not use `lstatSync` to reject symbolic links, confirm that entries are regular files, resolve their canonical paths, or verify that the resolved targets remain inside the intended `logs` directory. Consequently, a user who can create or modify entries in the workspace can place a symbolic link such as `logs/status_0001.json` that points to a JSON-formatted file elsewhere on the local filesystem. The linked target will then be read and parsed as if it were an ordinary cycle history file. The affected APIs include: - `listFiles`, which returns the parsed object in each entry's `data` field. - `get`, which directly returns the entire parsed JSON object. - `search`, which can expose selected fields from the parsed object. - `summary` and `generateRep ...[truncated 1647 chars]- Remediation
View remediation
