Skip to content

security: symlink traversal in process_doc allows reading arbitrary files #150

Description

@paulbreuler

Severity: Critical

`process_doc` (singular) does not apply symlink safety checks before reading a file. An adversary who can place a symlink inside the indexed plans directory can read any file on the filesystem accessible to the server process.

Root cause

`process_doc.ts` calls `validatePath()` which uses `path.resolve()` for containment checks. `path.resolve()` does not follow symlinks. However, `readFile()` in Node.js does follow symlinks, so the containment check is bypassed.

The sibling tools `process_docs` (plural), `create_doc`, and `update_doc` all correctly call `checkPathSafety()` and `checkSymlinkAncestors()` from `src/utils/fs-safety.ts`. `process_doc` (singular) calls neither.

Fix

In `src/tools/process-doc.ts`, add the same safety checks as `process_docs`:

```typescript
import { checkPathSafety, checkSymlinkAncestors } from '../utils/fs-safety.js';

// After validatePath() and existsSync() checks, before readFile():
const safetyCheck = checkPathSafety(validated.absolute, {});
if (!safetyCheck.safe) {
return { content: [{ type: 'text', text: `Permission denied: ${safetyCheck.reason}` }], isError: true };
}
const ancestorCheck = checkSymlinkAncestors(validated.absolute, docsRoot);
if (!ancestorCheck.safe) {
return { content: [{ type: 'text', text: `Permission denied: ${ancestorCheck.reason}` }], isError: true };
}
```

Files to modify

  • `src/tools/process-doc.ts` — add `checkPathSafety` + `checkSymlinkAncestors` calls
  • `tests/tools/process-doc.test.ts` — add symlink traversal rejection test

Also audit

  • `src/tools/manage-tags.ts` — reads files after `validatePath` without symlink checks (medium risk)
  • `src/tools/delete-doc.ts` — lower risk (`unlink` removes the symlink itself, not the target)

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingsecuritySecurity vulnerability or concern

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions