Skip to content

filesystem: FS_SEARCH_EXCLUDE_PREFIXES is lexical; should excludes be canonical/symlink-aware? #4208

Description

@JonoGitty

Context. The proposed fix for #4162 (PR #4212) adds FS_SEARCH_EXCLUDE_PREFIXES as a fast lexical prefilter that refuses recursive search_files / directory_tree on configured slow roots, typically macOS CloudStorage / FileProvider paths.

Discussion on #4162 surfaced that the check is purely lexical: a symlink such as /allowed/sneaky whose target lives under an excluded prefix is not caught by the prefix check, and may still reach the slow provider path during canonicalisation / validation.

The case for keeping the #4162 fix scoped to the lexical prefilter, as discussed in that thread:

  • The bypass is pre-existing behaviour — the original searchFilesWithValidation exclude check is also lexical.
  • validatePath continues to enforce the allowed_directories escape boundary via its own realpath, so the security boundary is unaffected. This question is about whether excludes should be symlink-aware.
  • The impact of the bypass is performance / hang risk from reaching a slow provider path, not an authorization bypass.
  • An unbounded realpath-before-compare exclude check risks re-introducing the kind of hang filesystem: recursive search can hang on macOS CloudStorage / lazy provider paths #4162 is trying to avoid.

Design question. Should excludes be hardened against symlink bypass?

One possible shape is two-stage:

  1. Fast lexical check first, preserving current cheap behaviour.
  2. If not excluded lexically, optionally perform bounded canonicalisation, e.g. withFsTimeout(fs.realpath(...)), then re-check the canonical path against excluded prefixes, with an explicit fail-policy on timeout — deny, allow, or return a typed error.

This affects both search_files and directory_tree, so it seems like a design decision rather than a drop-in fix. Not gating #4162; filing this separately so the symlink-aware exclude question is not lost.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions