Skip to content

fix(daemon): reject path-traversal ids in readPromptTemplate - #5027

Merged
AmyShang-alt merged 1 commit into
nexu-io:mainfrom
EthanGuo-coder:fix/prompt-template-path-traversal
Jul 2, 2026
Merged

fix(daemon): reject path-traversal ids in readPromptTemplate#5027
AmyShang-alt merged 1 commit into
nexu-io:mainfrom
EthanGuo-coder:fix/prompt-template-path-traversal

Conversation

@EthanGuo-coder

Copy link
Copy Markdown
Contributor

Why

readPromptTemplate joins the caller-supplied id straight into a filesystem path without checking that the result stays inside the surface directory. The daemon exposes it at GET /api/prompt-templates/:surface/:id, so a percent-encoded id such as ..%2f..%2ffoo decodes to ../../foo and escapes the templates directory — an arbitrary .json file read against the machine running the daemon. I noticed this while adding the prompt-template scanner tests in #2447 and am fixing it on its own so the containment is explicit rather than resting on the incidental id === filename validation.

What users will see

Nothing changes for correctly-authored templates — every committed template id equals its filename, so all 104 still resolve. Only ids that would escape the surface directory (those containing a path separator or a .. segment, which are never valid template ids) now return 404 instead of reading outside the directory.

Surface area

  • UI
  • Keyboard shortcut
  • CLI / env var
  • API / contract
  • Extension point
  • i18n keys
  • New top-level dependency
  • Default behavior change
  • None — internal daemon hardening; no new product surface. The /api/prompt-templates/:surface/:id response is unchanged for every valid id; only traversal ids that never matched a real template are now rejected before the read.

Bug fix verification

  • Bug: readPromptTemplate joined id into the file path (<root>/<surface>/<id>.json) with no containment check, so a traversal id like ../secret resolved outside the surface directory and returned its contents.
  • Test: apps/daemon/tests/prompt-templates.test.ts → "returns null for a path-traversal id instead of reading outside the surface dir" plants <root>/secret.json one level above the image surface directory and asserts readPromptTemplate(root, 'image', '../secret') is null.
  • Red on main, green here? Yes — on main the call returns the out-of-directory template's full contents; with the path.dirname(filePath) !== dir guard it returns null.

Validation

  • pnpm --filter @open-design/daemon testtests/prompt-templates.test.ts 14/14, plus tests/static-resource-routes.test.ts and tests/server-bootstrap-regression.test.ts (which exercise the endpoint) 19/19.
  • daemon tsc --noEmit for both tsconfig.json and tsconfig.tests.json.

@lefarcen
lefarcen requested a review from mrcfps July 2, 2026 02:55
@lefarcen lefarcen added size/XS PR changes <20 lines risk/high High risk: apps/desktop, daemon, auth, migration, workflows, package deps type/bugfix Bug fix needs-validation Runtime change detected; needs human or /explore agent validation. labels Jul 2, 2026
@lefarcen

lefarcen commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

🧪 Added a QA gate for this one because it hardens a live daemon read path that user flows depend on. Nothing needed from you right now — we'll update here once it goes through validation before merge. Thanks for the focused fix.

@mrcfps mrcfps left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@EthanGuo-coder I reviewed the daemon prompt-template containment fix and the added regression coverage. The changed helper now rejects ids whose resolved path would leave the surface directory before attempting the read, while valid direct-child ids continue through the existing JSON validation path. I also checked the route caller and daemon ownership guidance; this stays scoped to the daemon helper and its tests. Thanks for the focused security hardening here.

🔁 Powered by Looper · runner=reviewer · agent=codex · An autonomous AI dev team for your GitHub repos.

@lefarcen
lefarcen requested a review from AmyShang-alt July 2, 2026 03:06

@AmyShang-alt AmyShang-alt left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

QA 验收记录

验收范围:

  • PR head: 3ed33c4
  • daemon prompt-template path traversal fix: readPromptTemplate rejects ids that resolve outside the surface directory while preserving valid direct-child template reads.

已验证:

  • pnpm --dir apps/daemon exec vitest run -c vitest.config.ts tests/prompt-templates.test.ts -> 14/14 passed.
  • pnpm --dir apps/daemon exec vitest run -c vitest.config.ts tests/static-resource-routes.test.ts tests/server-bootstrap-regression.test.ts -> 19/19 passed.
  • pnpm --filter @open-design/daemon typecheck passed.
  • GitHub CI is green for Workspace unit tests, E2E Vitest, Preflight, UI P0 smoke, and related UI P0 groups.

未验证:

  • No Electron manual validation run; this PR is daemon helper/API hardening with no UI behavior change.

风险/关注点:

  • Security-sensitive daemon file-read boundary, but the diff is tightly scoped and has direct regression coverage for the traversal case plus route/bootstrap regression coverage.

结论:

  • 验收通过 / 可接受。

@AmyShang-alt AmyShang-alt added validated Runtime change validated (via /explore Pass or manual QA). and removed needs-validation Runtime change detected; needs human or /explore agent validation. labels Jul 2, 2026
@AmyShang-alt
AmyShang-alt added this pull request to the merge queue Jul 2, 2026
Merged via the queue into nexu-io:main with commit 5567a04 Jul 2, 2026
31 checks passed
xxiaoxiong pushed a commit to xxiaoxiong/open-design that referenced this pull request Jul 9, 2026
xxiaoxiong pushed a commit to xxiaoxiong/open-design that referenced this pull request Jul 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk/high High risk: apps/desktop, daemon, auth, migration, workflows, package deps size/XS PR changes <20 lines type/bugfix Bug fix validated Runtime change validated (via /explore Pass or manual QA).

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants