Listen to this Post
Tornado’s StaticFileHandler serves files under a configured static root.
It joins the root with the requested URI path.
It calls os.path.abspath() on the root.
It calls os.path.abspath() on the candidate path.
It checks that the candidate starts with the root.
os.path.abspath() normalises “.” and “..” segments.
os.path.abspath() does not resolve symbolic links.
A symlink inside the static root can point outside the root.
The string path still starts with the static root prefix.
The prefix check therefore passes.
StaticFileHandler then calls os.path.exists().
StaticFileHandler also calls os.path.isfile().
Both functions follow symbolic links.
The file opened is the symlink target.
The target can be any file readable by the process user.
An unauthenticated attacker can request the symlink path.
The request can return /etc/passwd, private keys, configuration files, or secrets.
The vulnerability is in tornado/web.py.
It affects path validation and file opening.
Any application using StaticFileHandler may be affected.
The static directory may contain symlinks from build tooling.
Examples include npm link, webpack, Docker volume mounts, CDN sync tools.
The application may allow uploads into the static directory.
Uploads without symlink stripping can create malicious links.
The fix is to replace os.path.abspath() with os.path.realpath().
The resolved real path must be validated against the static root.
Both validation methods should use realpath.
This prevents symlink targets outside the root from passing the check.
No CVE identifier was provided in the source .
Severity and affected versions were not stated in the source .
DailyCVE Form:
Platform: Tornado StaticFileHandler
Version: Unspecified Tornado versions
Vulnerability : Symlink file read
Severity: Not stated
date: Not stated
Prediction: Unknown patch date
(end of form)
What Undercode Say:
Analytics
mkdir -p /tmp/static echo "DB_PASSWORD=s3cr3t" > /tmp/secret.conf ln -s /tmp/secret.conf /tmp/static/config.conf
import tornado.web, tornado.ioloop
app = tornado.web.Application([
(r"/static/(.)", tornado.web.StaticFileHandler, {"path": "/tmp/static"}),
])
app.listen(8888)
tornado.ioloop.IOLoop.current().start()
curl http://localhost:8888/static/config.conf
How Exploit: (Educational Purposes!)
mkdir -p /tmp/static echo "DB_PASSWORD=s3cr3t" > /tmp/secret.conf ln -s /tmp/secret.conf /tmp/static/config.conf python server.py curl http://localhost:8888/static/config.conf
Protection: from this CVE
os.path.realpath()
startswith(realpath(root))
Reject symlinks Strip symlinks on upload Run process least privilege
Impact:
Unauthenticated remote attacker reads arbitrary files readable by process user.
/etc/passwd
private keys
configuration files
application secrets
/etc/shadow
SSH keys
source code
🎯Let’s Practice Exploiting & Learn Patching For Free:
🎓 Live Courses & Certifications:
Join Undercode Academy for Verified Certifications
🚀 Request a Custom Project:
Secure, high-velocity infrastructure and disruptive technological engineering. Contact our engineering team for high-tier development and proprietary systems:
[email protected]
💎 Smart Architecture | 🛡️ Secure by Design | ⭐ Trusted by Thousands
Sources:
Reported By: github.com
Extra Source Hub:
Undercode

