Skip to content

NCSA log filter: escape client-controlled fields - #567

Merged
michaelJustin merged 1 commit into
masterfrom
563-ncsa-log-escaping
Oct 14, 2026
Merged

michaelJustin merged 1 commit into
masterfrom
563-ncsa-log-escaping

Conversation

@michaelJustin

Copy link
Copy Markdown
Owner

Closes #563.

TdjNCSALogFilter concatenated client-controlled values into its access-log line unescaped. Before:

10.0.0.1 - x
127.0.0.1 - admin [10/Oct/2026:13:55:36 +0200] "GET /admin HTTP/1.1" 200 0 [...] "GET / HTTP/1.1" 401 0

After (the same request):

10.0.0.1 - x\x0D\x0A127.0.0.1 - admin [10/Oct/2026:13:55:36 +0200] \"GET /admin HTTP/1.1\" 200 0 [...] "GET / HTTP/1.1" 401 0

Changes

  • NCSAEscape escapes the way Apache httpd does for its access log: " → \", \ → \, control characters (#0..#31, #127, which covers CR, LF and ESC) → \xHH. Other characters are unchanged.
  • FormatNCSALogLine builds the line from plain values and escapes the user name, method, URI and version. DoFilter now only gathers the values, so the format can be tested without a server. The output is unchanged for ordinary requests.
  • New djNCSALogFilterTests suite (10 tests): the escaping, the line format, a forged user name staying on one line, and a " in the URI not ending the request field. It's registered in TestHelper and added to Unittests.lpr/.lpi/.dpr/.dproj.
  • SECURITY.md: the optional-units note now describes the escaping instead of warning about it.

Not escaped: characters outside ASCII, which the issue suggested writing as \xHH. In the FPC build string holds UTF-8 bytes, but in Delphi it holds UTF-16 code units, so a byte-level rule would either break valid UTF-8 or behave differently on the two compilers. Line breaks, quotes and ESC are covered on both.

Verification

  • FPC (run-fpc.cmd): 208 tests, 0 errors, 0 failures; heap trace at the clean baseline (6 blocks / 744 bytes).
  • Delphi 2009 (run-delphi.cmd): OK, 208 tests.

🤖 Generated with Claude Code

@michaelJustin michaelJustin added this to the 3.5.0 milestone Oct 14, 2026
TdjNCSALogFilter concatenated the user name (base64-decoded from an
Authorization: Basic header), method, URI and version into the access-log
line unescaped. A CR/LF in the user name forged extra log entries, a '"'
shifted the fields, and an ESC could start a terminal escape sequence.

- NCSAEscape: Apache-style escaping -- '"' -> \", '\' -> \, control
  characters (#0..#31, #127) -> \xHH; other characters unchanged.
- FormatNCSALogLine builds the line from plain values (escaping the
  client-controlled ones), so DoFilter only gathers them and the format is
  testable without a server.
- New djNCSALogFilterTests suite (10 tests), registered in TestHelper and
  added to the FPC and Delphi test projects.
- SECURITY.md: the optional-units note now describes the escaping.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@michaelJustin
michaelJustin merged commit 8473a07 into master Oct 14, 2026
2 checks passed
@michaelJustin
michaelJustin deleted the 563-ncsa-log-escaping branch October 14, 2026 17:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

NCSA log filter writes request fields unescaped (log forging)

1 participant