Skip to content

feat: add followSymlinks option to restrict symlink traversal#298

Open
DebuggingMax wants to merge 1 commit intopillarjs:masterfrom
DebuggingMax:add-follow-symlinks-option
Open

feat: add followSymlinks option to restrict symlink traversal#298
DebuggingMax wants to merge 1 commit intopillarjs:masterfrom
DebuggingMax:add-follow-symlinks-option

Conversation

@DebuggingMax
Copy link

Summary

This PR adds a new followSymlinks option that allows restricting symlink traversal to stay within the configured root directory.

Motivation

Currently, send resolves file paths using string normalization but does not check whether the final canonical path (after symlink resolution) remains inside the configured root. This means symbolic links inside the root can point to — and serve — files outside of it.

This is especially problematic for applications that serve user-writable directories where users could create symlinks pointing to sensitive system files.

Implementation

When followSymlinks is set to false:

  • Uses fs.realpath() to resolve the canonical path of requested files
  • Rejects the request with 403 if the resolved path falls outside the root directory
  • Works with all file serving methods (direct files, extensions fallback, index files)

Options

  • followSymlinks: true (default) - Current behavior, symlinks are followed without restriction
  • followSymlinks: false - Reject requests for symlinks that resolve outside root

Requirements

  • The root option must be set for the symlink check to apply
  • This is a semver-minor change with no breaking changes

Example

const send = require("send");

// Reject symlinks pointing outside /www/public
send(req, path, { 
  root: "/www/public",
  followSymlinks: false
}).pipe(res);

Changes

  • Added followSymlinks option to SendStream constructor
  • Added checkSymlink method to verify paths remain within root
  • Updated sendFile and sendIndex to check symlinks when option is disabled
  • Added documentation in README.md
  • Added comprehensive test suite with symlink fixtures

Tests

All 146 tests pass, including 7 new tests for the followSymlinks option:

  • Default behavior (follow symlinks)
  • Allow internal symlinks when disabled
  • Reject external symlinks when disabled
  • Regular file serving when disabled
  • Integration with extensions option
  • Integration with index files
  • Behavior without root option

Closes #297

Add a new `followSymlinks` option that allows restricting symlink
traversal to stay within the configured root directory.

When `followSymlinks` is set to `false`, the module will use
`fs.realpath()` to resolve the canonical path of files and reject
requests (with 403) if the resolved path falls outside the root
directory. This provides an explicit opt-in safeguard for applications
that serve user-writable directories.

- Default: `true` (backward compatible - current behavior)
- When `false`: reject symlinks pointing outside root
- Requires `root` option to be set for the check to apply

Closes pillarjs#297
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.

add followSymlinks option to restrict symlink traversal

1 participant