fix(filesystem): add stable fail-closed path validation reason codes - #4789
Open
tiagovilasboas wants to merge 2 commits into
Open
Conversation
Throw PathValidationError with machine-readable reasons for fail-closed denials, and rethrow coded errors in inner catch blocks so PARENT_OUTSIDE_ALLOWED is not remapped to PARENT_DIRECTORY_NOT_FOUND. Co-authored-by: Tiago Vilas Boas <tcarvalhovb@gmail.com>
Cover PATH_OUTSIDE_ALLOWED, SYMLINK_TARGET_OUTSIDE_ALLOWED, PARENT_OUTSIDE_ALLOWED, and PARENT_DIRECTORY_NOT_FOUND with structured assertions, including a real-filesystem parent-escape regression. Co-authored-by: Tiago Vilas Boas <tcarvalhovb@gmail.com>
tiagovilasboas
marked this pull request as ready for review
September 10, 2026 22:40
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.
Description
Filesystem path validation now fails closed with stable, machine-readable reason codes. Callers can classify denials without parsing free-form strings.
This implements the intended contract from #3525 on current
main(which already walks missing ancestors viaresolveUnicodeEquivalentPath). Open PR #3526 introducedPathValidationErroron an oldervalidatePath, but a bare innercatchremappedPARENT_OUTSIDE_ALLOWEDtoPARENT_DIRECTORY_NOT_FOUND, making that reason code dead. This PR keeps the coded error type and rethrowsPathValidationErrorin both catch paths soPARENT_OUTSIDE_ALLOWEDis observable.Reason codes:
path_outside_allowed— requested path is outside configured rootssymlink_target_outside_allowed— existing path resolves (via symlink) outside allowed directoriesparent_outside_allowed— missing path whose nearest existing ancestor resolves outside allowed directoriesparent_directory_not_found— no resolvable ancestor directory existsPublishing Your Server
Not applicable — this changes the existing filesystem server only.
Server Details
validatePath/resolveUnicodeEquivalentPath)Motivation and Context
Filesystem roots are the primary safety boundary for the reference filesystem server. Denial paths need a deterministic, auditable contract so symlink escapes and parent-directory escapes cannot be confused with a missing parent.
Fixes #3525
Related: #3526 (still open; this rebase onto current
mainavoids the catch-swallow bug called out in review)How Has This Been Tested?
src/filesystem/__tests__/lib.test.tsassertinstanceof PathValidationErrorand thereasonfield for all four codes (including mocked symlink-target and parent-outside cases).src/filesystem/__tests__/nested-parents.test.tsprovePATH_OUTSIDE_ALLOWED,SYMLINK_TARGET_OUTSIDE_ALLOWED, andPARENT_OUTSIDE_ALLOWEDare observable (the last would fail if the inner catch swallowed the coded error).vitestwith coverage).I have not re-tested this through an interactive LLM client; coverage is the existing filesystem validation suite plus the new structured reason-code assertions.
Breaking Changes
No client configuration changes. Thrown messages keep the existing
Access denied - .../Parent directory does not existtext. Errors are nowPathValidationErrorinstances (stillErrorsubclasses), somessage-based handling continues to work.Types of changes
Checklist
Additional context
Narrow AppSec change: no promotional links, no README listing updates, no new server.
#3526remains the prior attempt on stalevalidatePath; this PR is a clean implementation of that contract on currentmainwith the review-requested catch fix and missing reason-code tests.