fix: enforce symlink-aware filesystem roots - #326
Open
antfubot wants to merge 4 commits into
Open
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Static serving and asset RPC operations proved containment only from normalized path strings. Filesystem operations then follow symlinks, so a symlink inside an allowed root could redirect reads, writes, deletes, renames, or editor-opening outside that root. This adds canonical (symlink-resolved) containment checks on top of the existing lexical guards, closing deterministic, pre-existing symlink escapes.
Implements
plans/007-enforce-symlink-containment.md.What
serve-static.ts): canonicalizes the served root once per handler and requires every candidate file's canonical path to stay beneath it (direct hits, index candidates,.html/.htmextension candidates, and SPA fallback). An escaping symlink now reads as a 404 miss; an in-root symlink whose canonical target stays inside the root still serves.read-text,read-image-meta): allow an in-root symlink only when its canonical target remains inside the canonical managed root.upload,mkdir,rename,delete): reject every pre-existing symlink path component (including in-root ones), walking existing components before creation and re-checking after directory creation and immediately before the mutating I/O.list): configures the glob not to follow symbolic links and omits symlink entries from returnedAssetInfo.DP_ASSETS_0001/DS_OPEN_0002diagnostics.Scope & threat model
These canonical checks close pre-existing symlink escapes; they do not defeat a concurrent local process replacing path components between validation and I/O (documented in the plan's maintenance notes). Remote asset paths, upload quotas/content validation, and filesystem sandboxing outside configured roots are out of scope.
Verification
Targeted suites, typechecks, lint, and the API snapshot guard pass for the in-scope packages (
devframe,@devframes/plugin-assets,@devframes/service-open), including new regression tests for final-component and ancestor-directory symlinks across both static handlers, every asset read/mutation family, and the open service. New symlink tests skip on Windows (where symlink creation needs privileges hosted CI lacks). The repo-widepnpm buildgate fails only on unrelated, out-of-scope packages due to sandbox environment limits (a write-only leftover artifact in the git plugin's Next.js output; resource-limited exits in hub-ui/json-render-ui).This PR was created with the help of an agent.