T05 · Unauthorized Access and Privilege Escalation
- Location
scripts/merge_feishu_identity_batch.js:14- Finding
Unrestricted Batch Input Path Enables Disclosure of Arbitrary JSON Files
- Content
View full analysis
Vulnerability Details
File Location:
scripts/merge_feishu_identity_batch.js:14-21, 24-43
Vulnerability Type: Unrestricted local file read and sensitive output exposure
Risk Level: MediumVulnerable Code
javascript const inputPath = process.argv[2]; if (!inputPath) fail('Usage: node bin/merge_feishu_identity_batch.js <json-file>'); const resolved = path.isAbsolute(inputPath) ? inputPath : path.join(workspace, inputPath); if (!fs.existsSync(resolved)) fail(`Input file not found: ${resolved}`); const raw = fs.readFileSync(resolved, 'utf8'); const records = JSON.parse(raw); if (!Array.isArray(records)) fail('Input JSON must be an array of records'); const results = []; for (const rec of records) { const out = spawnSync(process.execPath, [singleScript, JSON.stringify(rec)], { encoding: 'utf8' }); results.push({ record: rec, code: out.status, stdout: out.stdout.trim(), stderr: out.stderr.trim() }); } const summary = { ok: results.every(r => r.code === 0), total: results.length, succeeded: results.filter(r => r.code === 0).length, failed: results.filter(r => r.code !== 0).length, results }; console.log(JSON.stringify(summary, null, 2)); if (!summary.ok) process.exit(2);Technical Analysis
The batch script accepts an input path directly from the command line. Absolute paths are used without restriction, while relative paths are joined to the workspace without canonicalization or containment validation. The script does not require the resolved file to remain within an authorized import directory and does not reject symbolic links that resolve outside that directory.
Once parsed, every element of a JSON array is copied into the
resultsstructure and printed to standard output asrecord, regardless of whether the downstream merge operation succeeds. Consequently, any readable file containing a top-level JSON arra ...[truncated 1532 chars]- Remediation
View remediation
Remediation Suggestions
- Restrict imports to a dedicated directory under the workspace.
- Resolve both the approved directory and requested file with
fs.realpathSync()before reading. - Verify that the canonical file path is equal to, or is a descendant of, the approved directory using
path.relative(). - Reject absolute paths unless they are explicitly required and pass the same containment check.
- Reject symbolic links or verify their final canonical destination.
- Validate the complete input array before invoking the single-record script.
- Do not include raw input records in the summary. Return only record indexes, status codes, and redacted validation errors.
- Run the script under a dedicated operating-system account with access only to the identity workspace.
Example containment logic:
javascript const importRoot = fs.realpathSync(path.join(workspace, 'identity', 'imports')); const candidate = fs.realpathSync(path.resolve(importRoot, inputPath)); const relative = path.relative(importRoot, candidate); if (relative.startsWith('..') || path.isAbsolute(relative)) { fail('Input file must be inside the approved import directory'); }
