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

  1. Client sends request with CRLF in URL: GET /path%0D%0AX-Injected:evil HTTP/1.1
  2. TinyWeb URL-decodes the path to: /path\r\nX-Injected:evil
  3. ReturnNewLocation() creates redirect with unsanitized path
  4. Response includes injected header in Location field

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-Cookie to 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:

  1. CRLF injection in HTTP response: Shows the injected header appearing as a separate line in the server's HTTP response after the Location header.
  2. Attack payload example: Demonstrates the crafted URL with %0D%0A sequences.
  3. Log file spoofing: Shows corrupted access_log entries 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:

  1. THTTPServerThread.Execute receives raw HTTP request bytes
  2. TCollector.Collect() splits request into lines by CRLF delimiter
  3. First line parsed as Method SP Request-URI SP HTTP-Version
  4. Request-URI split into path and query at ? character
  5. UnpackPchars(s) URL-decodes the path -- %0D becomes byte 0x0D (CR), %0A becomes 0x0A (LF). The UnpackXchars() function in xBase.pas decodes any %XX sequence unconditionally; the __pchar() validation only applies to non-percent characters, so decoded CR/LF bypass it.
  6. Decoded path stored as URIPath := s -- now contains raw CR/LF bytes
  7. If path is a directory without trailing slash, ReturnNewLocation(d.URIPath + '/', d) is called
  8. Before the fix, ReturnNewLocation() directly assigned the tainted path to Location header -- 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

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 %0D or %0A
  • Monitor logs for suspicious requests containing encoded CRLF sequences (%0D%0A or %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.