]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MINOR: mux-fcgi: sanitize the STDERR records before logging them
authorOlivier Houchard <ohouchard@haproxy.com>
Thu, 6 Aug 2026 11:54:52 +0000 (13:54 +0200)
committerWilly Tarreau <w@1wt.eu>
Fri, 7 Aug 2026 08:29:19 +0000 (10:29 +0200)
fcgi_strm_handle_stderr() emits one log line per STDERR record, appending
its own newline, but passes the record payload to app_log() with a bare
"%s", and neither app_log() nor __send_log() escape anything. FastCGI
applications routinely echo parts of the request in their warnings, so a
client whose input is reflected there can insert CR/LF and turn one record
into several log lines, or insert ESC sequences which the operator's
terminal interprets when reading the log. Verified with an application
writing "bad input 'x\r\nFAKE-INJECTED-LINE: ...\033[31m...'": the syslog
datagram carries all of it verbatim.

Escaping data emitted to logs is normally a configuration matter, but this
path bypasses the log-format machinery entirely, and the intent here is
clearly one record per line. Let's replace the control characters with a
dot before logging, which is a single pass over a record that is only ever
produced when the application writes to its stderr. Only controls are
replaced, so that the UTF-8 messages commonly found in such warnings are
left intact.

This has been there since the FCGI mux was introduced in 2.1 by commit
99eff65f4 ("MEDIUM: mux-fcgi: Add the FCGI multiplexer"). It may be
backported to all stable versions.

Reported-by: Claude (ANT-2026-9JD79F3M)
src/mux_fcgi.c

index 16ccdfe428570d0e7a769398e727225feabd10f5..94995bca33e7b1c400cbbc9155700d9963a0401c 100644 (file)
@@ -2456,7 +2456,7 @@ static int fcgi_strm_handle_stderr(struct fcgi_conn *fconn, struct fcgi_strm *fs
 {
        struct buffer *dbuf;
        struct buffer tag;
-       size_t ret;
+       size_t ret, i;
 
        TRACE_ENTER(FCGI_EV_RX_RECORD|FCGI_EV_RX_STDERR, fconn->conn, fstrm);
        dbuf = &fconn->dbuf;
@@ -2477,6 +2477,11 @@ static int fcgi_strm_handle_stderr(struct fcgi_conn *fconn, struct fcgi_strm *fs
        fconn->drl -= ret;
        TRACE_PROTO("FCGI STDERR record rcvd", FCGI_EV_RX_RECORD|FCGI_EV_RX_STDERR, fconn->conn, fstrm, 0, (size_t[]){ret});
 
+       for (i = 0; i < ret; i++) {
+               if (iscntrl((unsigned char)trash.area[i]))
+                       trash.area[i] = '.';
+       }
+
        trash.area[ret]   = '\n';
        trash.area[ret+1] = '\0';
        tag.area = fconn->app->name; tag.data = strlen(fconn->app->name);