Skip to content

v0.10.2

Choose a tag to compare

@github-actions github-actions released this 05 May 04:30
· 183 commits to main since this release

Fixed

  • lex-core::includes: platform-absolute include src (Windows C:\foo, \\server\share, \foo) is now rejected up front in resolve_path with the new IncludeError::AbsolutePath variant instead of relying on PathBuf::join's "absolute replaces base" semantics + the downstream root-escape check. The spec forbids absolute filesystem paths from entering the resolution pipeline; this holds the line at the input boundary and surfaces a clear "use relative or root-absolute" message instead of a misleading "escapes root" error. The root-absolute form (leading / against the includes root) is unchanged. Addresses item #4 from the security review. (#TBD)

Added

  • lex-core::includes: resource limits to bound resolver work against adversarial input. ResolveConfig::max_total_includes (default 1000) caps the total number of lex.include annotations resolved across the entire document — max_depth alone bounds chain length but a doc with thousands of includes at depth 1 still blows past it. FsLoader::with_max_file_size(bytes) (default 10 MiB) caps per-include file size; oversize files are rejected before any bytes hit memory. Both are surfaced as their own IncludeError variants (TotalIncludesExceeded, FileTooLarge) with include_site for editor diagnostics. Configurable via new [includes].max_total_includes and [includes].max_file_size keys in lex.toml. Addresses item #3 from the security review. (#503)

Security

  • lex-core: FsLoader now defends against arbitrary-file-read via symlink path traversal. Previously the resolver's lexical ..-normalization correctly blocked textual root escapes, but a symlink inside the repository pointing outside the resolution root (e.g., repo/sneaky -> /etc) bypassed the check — lexical_normalize doesn't touch the filesystem, so it can't see through symlinks. FsLoader now stores its allowed root and, on every load, calls fs::canonicalize on both the requested path and the root, then verifies the canonical target sits under the canonical root. Symlinks pointing outside root are rejected as IncludeError::RootEscape before any read happens. Editors and CI that process untrusted Lex repositories should pick up this fix immediately. Surfaces a new LoadError::OutsideRoot variant; Loader trait now returns LoadedFile { source, canonical_path } instead of bare String so the resolver can use the loader's authoritative identity for cycle detection. (#502)

Changed

  • lex-core::includes: Loader::load now returns LoadedFile { source, canonical_path } instead of String. Implementations decide what canonical_path means — FsLoader returns the post-fs::canonicalize path (symlinks resolved, case-folded on case-insensitive FS); MemoryLoader returns the lookup key unchanged. The resolver uses canonical_path for cycle detection and origin stamping, so symlink loops and case-folded re-includes are now caught as IncludeError::Cycle rather than slipping through to IncludeError::DepthExceeded.
  • lex-core::includes: FsLoader::new now takes the resolution root: FsLoader::new(root: PathBuf). Default impl removed (a loader without a root would be unsafe).
  • lex-core::includes: FsLoader now rejects non-regular files (FIFOs, sockets, devices, directories) before reading. Previously a malicious symlink to /dev/zero could block or OOM the reader once the symlink check landed; this is the second layer of defense.