Skip to content

Explicit symlink params for static files/dirs#3117

Merged
ahopkins merged 7 commits into
mainfrom
issue3073
Dec 31, 2025
Merged

Explicit symlink params for static files/dirs#3117
ahopkins merged 7 commits into
mainfrom
issue3073

Conversation

@ahopkins

Copy link
Copy Markdown
Member

Closes #3073

Sanic now provides granular control over symlinks in static file serving with two new parameters:

Parameter Default Description
follow_external_symlink_files False Allow serving file symlinks that point outside the static root
follow_external_symlink_dirs False Allow serving files from directory symlinks that point outside the static root

Examples

Secure defaults (block external symlinks):

# Symlinks pointing outside /var/www/static will return 404
app.static("/static", "/var/www/static")

Allow file symlinks only:

# Serves /var/www/static/config.json -> /etc/app/config.json
app.static("/static", "/var/www/static", follow_external_symlink_files=True)

Allow directory symlinks only:

# Serves files from /var/www/static/images/ -> /shared/images/
app.static("/static", "/var/www/static", follow_external_symlink_dirs=True)

Behavior Notes

  • Symlinks within the static root always work regardless of settings
  • Broken symlinks are always hidden from directory listings and return 404
  • Directory listings (directory_view=True) respect these settings - hidden symlinks won't appear

@ahopkins ahopkins requested a review from a team as a code owner December 31, 2025 10:39
Copilot AI review requested due to automatic review settings December 31, 2025 10:39

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds granular symlink control for static file serving in Sanic, addressing security concerns around symlinks that point outside the static root directory. Two new parameters (follow_external_symlink_files and follow_external_symlink_dirs) provide fine-grained control over whether file symlinks and directory symlinks pointing outside the root should be served.

Key Changes:

  • New security parameters default to False to prevent serving external symlinks by default
  • Updated path resolution logic to detect and block/allow external symlinks based on configuration
  • Directory listings now respect symlink policies and hide disallowed external symlinks

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
tests/test_static_directory.py Adds comprehensive test coverage for symlink behavior including internal symlinks, external file/directory symlinks, broken symlinks, and directory listing visibility under various permission combinations
tests/test_static.py Updates existing tests to enable follow_external_symlink_files=True where needed since the symlink fixture creates external symlinks that are now blocked by default
sanic/models/futures.py Adds follow_external_symlink_files and follow_external_symlink_dirs fields to the FutureStatic tuple to store configuration
sanic/mixins/static.py Implements core symlink detection and access control logic in _get_file_path, adds new parameters to static() method and passes them through the handler chain
sanic/handlers/directory.py Adds filtering logic to _iter_files to hide external symlinks from directory listings based on the new parameters, includes helper function _is_path_within_root for security checks

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread sanic/mixins/static.py Outdated

Copilot AI commented Dec 31, 2025

Copy link
Copy Markdown
Contributor

@ahopkins I've opened a new pull request, #3118, to work on those changes. Once the pull request is ready, I'll request review from you.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Copilot AI and others added 5 commits December 31, 2025 13:17
* Initial plan

* Fix symlink type detection to correctly distinguish file vs directory symlinks

Co-authored-by: ahopkins <166269+ahopkins@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: ahopkins <166269+ahopkins@users.noreply.github.com>
@codecov

codecov Bot commented Dec 31, 2025

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.91837% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 87.957%. Comparing base (41f2b38) to head (98d9683).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
sanic/handlers/directory.py 93.103% 2 Missing ⚠️
Additional details and impacted files
@@              Coverage Diff              @@
##              main     #3117       +/-   ##
=============================================
+ Coverage   87.869%   87.957%   +0.087%     
=============================================
  Files          105       105               
  Lines         8079      8113       +34     
  Branches      1281      1287        +6     
=============================================
+ Hits          7099      7136       +37     
+ Misses         672       671        -1     
+ Partials       308       306        -2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@ahopkins ahopkins merged commit 9aef932 into main Dec 31, 2025
50 of 51 checks passed
@ahopkins ahopkins deleted the issue3073 branch December 31, 2025 12:02
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.

File not found when trying to access static files behind a directory symlink

3 participants