Skip to content

fix: reject absolute containment relations and colon in Build ids - #442

Open
Wenjix wants to merge 1 commit into
hypit-ai:mainfrom
Wenjix:security/windows-path-containment
Open

Wenjix wants to merge 1 commit into
hypit-ai:mainfrom
Wenjix:security/windows-path-containment

Conversation

@Wenjix

@Wenjix Wenjix commented Oct 27, 2026 •

Copy link
Copy Markdown

Closes #450

Summary

Windows-only containment escapes — POSIX behavior unchanged:

  • 3 (low) + 35 (low) + the same pattern in runtime-local (medium-adjacent): on Windows, path.relative() returns an absolute path when the target resolves on a different drive or a UNC share, and an absolute relation can never start with ... Containment checks that only tested relation === ".." / startsWith(".." + sep) therefore admitted targets outside their declared root: containedResultPath and buildResultDirectory in packages/result/src/node/store.ts, buildWorkPath in packages/runtime-local/src/config.ts, and containedPath in packages/cli/src/result-export.ts. Each now also rejects isAbsolute(relation) — the check location.ts already does correctly.
  • 22 (medium): assertBuildId in packages/protocol/src/build-id.ts rejected /, \, NUL and dot-directories but not :, so d:build was a legal Build id — which resolve() treats as drive-relative on Windows, escaping the work/result root. : is now forbidden alongside the other path characters.

Behavior relative to main

Flow main this PR
resolve(root, build) cross-drive (C:\root, D:\x) relative() → D:\x, passes .. check, escapes root rejected as containment escape
Build id d:build accepted → drive-relative escape assertBuildId throws
Normal same-drive paths contained, unchanged contained, unchanged

Red / green

packages/protocol/test/canonical.test.ts: c: and d:build added to the rejecting Build id cases — on main both passed assertBuildId. The isAbsolute(relation) branches are Windows-only reachable, so the behavioral regression coverage lives there; the POSIX code path is unchanged.

Verification

  • node --import tsx --test packages/protocol/test/canonical.test.ts — pass.
  • pnpm check — clean.
  • Cross-drive/UNC behavior verified against Node's path.win32.relative semantics (returns absolute target, never ..-prefixed).

Merge Danger

  • Build ids containing : are now rejected (they were already unusable as single filesystem names on Windows).
  • On Windows, a location pointing off the declared root via drive/UNC now fails loudly instead of escaping silently.

Checklist

  • The why is documented in this description.
  • Test added for the portable half (Build ids); Windows-half documented above.
  • TypeScript check clean.

Generated with Devin

On Windows, path.relative() returns an absolute target when the resolved
path sits on a different drive or UNC share, and such a relation cannot
start with "..". Every containment check that only looked for ".."
therefore admitted a target outside its declared root: Build Result
stores, Runtime work directories and CLI result exports.

Build ids also admitted ':', letting an id like "d:build" resolve as a
drive-relative path on Windows.

Reject absolute relations at each check and ':' in Build ids.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings October 27, 2026 06:16

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: Windows drive-relative and UNC paths escape Build result, work and export containment

2 participants