TinyWeb CRLF Injection (CVE-2024-5193)
Security Advisory. Published: 2024-05-22. Fixed in TinyWeb v1.99.
Summary
TinyWeb HTTP Server version 1.94 and below is vulnerable to CRLF (Carriage Return Line Feed) injection. An
unauthenticated remote attacker can inject arbitrary HTTP headers into server responses by including
URL-encoded CRLF sequences (%0D%0A) in request URLs.
Severity: Medium (CVSS 3.1 Base Score: 5.3)
Vulnerability Details
| CVE ID | CVE-2024-5193 |
|---|---|
| GHSA ID | GHSA-f49h-4f4j-3rjc |
| VulDB ID | VDB-265830 |
| Vulnerability Type | CRLF Injection (CWE-93) |
| Attack Type | Remote |
| Attack Vector | Network (unauthenticated HTTP request) |
| Original Vendor | RITLABS S.R.L. |
| Current Maintainer | Maxim Masiutin |
| Product | TinyWeb HTTP Server |
| Affected Versions | 1.94 and below (all versions through 1.98) |
| Fixed Version | 1.99 (January 5, 2026) |
| Affected Component | Request Handler, ReturnNewLocation function |
| Impact | HTTP Response Splitting, Header Injection, Log Spoofing, Potential XSS |
CVSS Scores
| CVSS Version | Score | Severity | Vector String |
|---|---|---|---|
| CVSS 4.0 | 6.9 | Medium | AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N |
| CVSS 3.1 | 5.3 | Medium | AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N |
| CVSS 3.0 | 5.3 | Medium | AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N |
| CVSS 2.0 | 5.0 | - | AV:N/AC:L/Au:N/C:N/I:P/A:N |
| EPSS | 0.391% | 60th percentile | Probability of exploitation in the wild within 30 days |
Background
TinyWeb HTTP Server was originally developed by RITLABS S.R.L. (Moldova) in 1997 as a minimal Windows HTTP server -- no GUI, no console window, no Windows Service; it runs as a silent background process. The last RITLABS release was v1.94 (April 2017). In 2021, Maxim Masiutin took over open-source maintenance on GitHub. The server is written in Object Pascal (compiles with both Delphi and Free Pascal) and produces a single ~60KB executable.
CRLF injection is a well-known class of HTTP vulnerabilities (OWASP, CWE-93). HTTP uses CRLF
(\r\n, bytes 0x0D 0x0A) as the delimiter between headers. If user-controlled input
containing CRLF sequences ends up in response headers without sanitization, attackers can inject arbitrary
headers or split the HTTP response entirely. This was recognized as a risk in RFC 3875 Section 7.2 (CGI
security considerations) as early as 2004.
TinyWeb's URL decoding function (UnpackPchars() in xBase.pas) converts
percent-encoded sequences like %0D%0A to raw bytes unconditionally. The decoded path is stored in
URIPath and later used in ReturnNewLocation() to build the Location
header for 302 redirects. Prior to v1.99, no sanitization was applied between URL decoding and header
emission, creating the injection point.
The vulnerability was reported by security researcher DMCERTCE (VulDB submission #333059, username "Senatorhotchkiss" on VulDB) in May 2024. DMCERTCE also discovered CVE-2024-34199 (buffer overflow DoS in TinyWeb). According to VulDB, the original vendor RITLABS was contacted but did not respond. The fix was implemented by the current maintainer in January 2026.
Technical Details
Root Cause
When TinyWeb HTTP Server processes requests that result in HTTP redirects (302 responses), the request URL
path is used to construct the Location header value. Prior to version 1.99, URL-encoded CRLF
sequences (%0D%0A) in the request path were URL-decoded and included directly in the response
headers without sanitization.
The CRLF characters (Carriage Return \r = %0D and Line Feed \n =
%0A) are HTTP header delimiters. When injected into headers, they allow attackers to terminate
the current header and inject arbitrary additional headers.
Affected Code Path
- Client sends request with CRLF in URL:
GET /path%0D%0AX-Injected:evil HTTP/1.1 - TinyWeb URL-decodes the path to:
/path\r\nX-Injected:evil ReturnNewLocation()creates redirect with unsanitized path- Response includes injected header in
Locationfield
Attack Vector
An attacker sends an HTTP request with CRLF sequences in the URL:
GET /path%0D%0AX-Injected-Header:%20malicious-value HTTP/1.1 Host: target.example.com
When TinyWeb redirects (e.g., adding trailing slash to directory), the response contains:
HTTP/1.1 302 Moved Temporarily Location: /path X-Injected-Header: malicious-value/ ...
Exploitation Scenarios
- HTTP Response Splitting: Inject complete HTTP responses to serve malicious content
- Header Injection: Add arbitrary headers like
Set-Cookieto hijack sessions - Log Spoofing: Inject fake log entries into access_log, agent_log, referer_log
- Cache Poisoning: Inject headers that cause proxy caches to store malicious responses
- XSS via Headers: Some browsers may execute JavaScript in certain injected headers
Exploitation Requirements
- TinyWeb version 1.98 or earlier
- Network access to the TinyWeb server
- A request path that triggers a redirect (e.g., directory without trailing slash)
Fix Applied in Version 1.99
Version 1.99 implements the StripCRLF() function that removes all CR (#13) and LF
(#10) characters from strings before they are used in HTTP response headers.
StripCRLF Function (SrvMain.pas)
function StripCRLF(const s: AnsiString): AnsiString;
var
i, j, len: Integer;
begin
len := Length(s);
SetLength(Result, len);
j := 0;
for i := 1 to len do
begin
if (s[i] <> #13) and (s[i] <> #10) then
begin
Inc(j);
Result[j] := s[i];
end;
end;
SetLength(Result, j);
end;
Applied in ReturnNewLocation (SrvMain.pas)
function ReturnNewLocation(const ALocation: AnsiString; d: THTTPData) : TAbstractHttpResponseData; begin // CVE-2024-5193: Strip CRLF to prevent HTTP header injection // Without this, attacker could inject headers via: GET /path%0D%0AEvil:Header d.ResponseResponseHeader.Location := StripCRLF(ALocation); Result := THttpResponseErrorCode.Create(302); end;
The fix ensures that any CRLF characters in the URL path are stripped before being included in the Location header, preventing header injection attacks. This is the standard mitigation -- Apache, nginx, and IIS all strip or reject CRLF in header values.
Proof of Concept Analysis
The PoC was published on May 22, 2024 by security researcher DMCERTCE (VulDB username "Senatorhotchkiss") at github.com/DMCERTCE/CRLF_Tiny. DMCERTCE also discovered and published the PoC for CVE-2024-34199 (buffer overflow DoS in TinyWeb). The VulDB submission ID is #333059.
Repository Contents
The repository contains a README.md with three screenshots demonstrating:
- CRLF injection in HTTP response: Shows the injected header appearing as a separate line
in the server's HTTP response after the
Locationheader. - Attack payload example: Demonstrates the crafted URL with
%0D%0Asequences. - Log file spoofing: Shows corrupted
access_logentries where the injected CRLF characters created fake log lines, masking the actual attack. The PoC notes this "most likely evident for agent_ and referer_ logs etc."
No automated exploit script is included; the attack is trivially reproducible with curl.
Reproduction Steps
# 1. Header Injection: inject a custom header via CRLF in URL curl -i "http://target:80/test%0D%0AX-Injected:%20pwned" # 2. Set-Cookie hijack: inject a Set-Cookie header to set attacker-controlled cookies curl -i "http://target:80/test%0D%0ASet-Cookie:%20session=evil" # 3. Response splitting: inject a blank line + full fake response body curl -i "http://target:80/test%0D%0A%0D%0A<html>Fake%20page</html>"
Vulnerable vs Fixed Response
# Vulnerable response (TinyWeb <= 1.98): HTTP/1.1 302 Moved Temporarily Location: /test X-Injected: pwned/ Content-Type: text/html ... # Fixed response (TinyWeb >= 1.99): HTTP/1.1 302 Moved Temporarily Location: /testX-Injected: pwned/ Content-Type: text/html ...
In the fixed version, StripCRLF() removes CR/LF bytes, so the injected content collapses into
the Location value as a harmless string fragment rather than becoming a separate header.
Internal Code Flow (Vulnerable Path)
Tracing through the source code to show exactly how the injection occurs:
THTTPServerThread.Executereceives raw HTTP request bytesTCollector.Collect()splits request into lines by CRLF delimiter- First line parsed as
Method SP Request-URI SP HTTP-Version - Request-URI split into path and query at
?character UnpackPchars(s)URL-decodes the path --%0Dbecomes byte0x0D(CR),%0Abecomes0x0A(LF). TheUnpackXchars()function inxBase.pasdecodes any%XXsequence unconditionally; the__pchar()validation only applies to non-percent characters, so decoded CR/LF bypass it.- Decoded path stored as
URIPath := s-- now contains raw CR/LF bytes - If path is a directory without trailing slash,
ReturnNewLocation(d.URIPath + '/', d)is called - Before the fix,
ReturnNewLocation()directly assigned the tainted path toLocationheader -- the raw CR/LF bytes in the header value terminate the header and inject attacker-controlled content as new headers
Log Spoofing Impact
Beyond header injection, the PoC demonstrates that CRLF characters in request URLs corrupt TinyWeb's log
files (access_log, agent_log, referer_log). Since TinyWeb logs the
decoded URI path, injected CRLF creates fake log entries that can:
- Mask the original malicious request by splitting it across multiple log lines
- Inject fake entries attributing activity to different IP addresses or user agents
- Corrupt log parsing tools that expect one entry per line
References
- CVE-2024-5193 (MITRE)
- NVD: CVE-2024-5193
- GitHub Advisory: GHSA-f49h-4f4j-3rjc
- VulDB: VDB-265830
- VulDB Submission #333059
- Proof of Concept (GitHub)
- Fix Commit (GitHub)
- TinyWeb v1.99 Release
- TinyWeb GitHub Repository
- CWE-93: Improper Neutralization of CRLF Sequences
- CWE-74: Improper Neutralization of Special Elements in Output
- OWASP: CRLF Injection
- RFC 3875 Section 7.2 (CGI Security Considerations)
Mitigation
Recommended: Upgrade to TinyWeb version 1.99 or later.
Workaround: If upgrade is not immediately possible:
- Place TinyWeb behind a reverse proxy that sanitizes CRLF sequences in URLs
- Use a Web Application Firewall (WAF) to block requests containing
%0Dor%0A - Monitor logs for suspicious requests containing encoded CRLF sequences (
%0D%0Aor%0d%0a)
Timeline
| 2024-05-22 | CVE-2024-5193 published by VulDB |
|---|---|
| 2024-05-22 | Proof of concept released on GitHub |
| 2024-05-22 | VulDB reports vendor (RITLABS) did not respond to disclosure |
| 2026-01-05 | Fix implemented by current maintainer (Maxim Masiutin) |
| 2026-01-05 | TinyWeb v1.99 released with fix |
Credit
Vulnerability Discovery and PoC: DMCERTCE (security researcher; VulDB username "Senatorhotchkiss", submission #333059). Published the PoC at github.com/DMCERTCE/CRLF_Tiny on May 22, 2024. Also discovered and published the PoC for CVE-2024-34199 (buffer overflow DoS).
CVE Assignment: VulDB (CNA). Published as CVE-2024-5193 on May 22, 2024. VulDB identifier: VDB-265830.
Fix Implementation: Maxim Masiutin (current open-source maintainer of TinyWeb since 2021; original vendor RITLABS S.R.L. is no longer maintaining the product). Fix committed January 5, 2026, released as TinyWeb v1.99.
Other TinyWeb CVEs
| CVE-2024-34199 | Buffer Overflow (CWE-787) - Fixed in v1.99. CVSS 8.6 High. Advisory |
|---|---|
| CVE-2026-22781 | Command Injection (CWE-78) - Fixed in v1.98. CVSS 9.8 Critical. Advisory |
| CVE-2004-2636 | Path Traversal (CWE-22) - Fixed in v1.93. CVSS 5.0 Medium. Advisory |
| CVE-2003-1510 | Denial of Service (CWE-400) - Fixed in v1.93. CVSS 7.8 High. Advisory |
See TinyWeb CGI Command Injection Security Advisory for details on the command injection vulnerability.
Vendor Response Note
According to VulDB (submission #333059), the original vendor (RITLABS S.R.L., Moldova) was contacted about this vulnerability but did not respond. RITLABS ceased active development of TinyWeb after v1.94 (April 2017). The product was originally created in 1997 and distributed as freeware.
In 2021, Maxim Masiutin took over open-source maintenance, publishing the source code on GitHub. The fix for CVE-2024-5193 was implemented on January 5, 2026 and released as TinyWeb v1.99 (the same release also fixes CVE-2024-34199, a buffer overflow DoS).
TinyWeb is now maintained at github.com/maximmasiutin/TinyWeb where security issues can be reported via GitHub Issues or Security Advisories.