SIGN IN SIGN UP

BUG/MEDIUM: http-fetch: reject a negative capture id in capture.{req,res}.hdr

The "capture.req.hdr" and "capture.res.hdr" sample fetches use their integer
argument directly as an index in the stream's captures array:

	idx = args->data.sint;

	if (idx > (fe->nb_req_cap - 1) || smp->strm->req_cap == NULL ||
	    smp->strm->req_cap[idx] == NULL)
		return 0;

Only the upper bound is verified, and unlike "req.hdr" and friends, which rely
on val_hdr() to enforce the lower bound of the occurrence number, these two
keywords are declared with no argument checker at all. A negative identifier is
therefore accepted at boot, and at runtime req_cap[-1] is read; if the pointer
found there is not NULL it is then passed to strlen() and returned as a string.

This is trivially reproduced with a frontend containing:

	capture request header Host len 32
	http-request return status 200 hdr X-Cap "%[capture.req.hdr(-1)]"

which segfaults the worker on the very first request.

Since a negative capture identifier is meaningless, the cleanest fix is to
reject it at configuration parsing time, as is done for the header occurrence.
Let's add a val_cap_id() checker and reference it from both keywords.

Note that the "capture-req"/"capture-res" converters in http_conv.c index the
same array with an unchecked value too, but they are saved by the list walk
that precedes the access and which stops on a NULL <hdr>, so they only fail to
capture. They are left untouched.

This bug has been there since the keywords were introduced, so this should be
backported to all supported versions.
W
Willy Tarreau committed
ce0b1d26eab9821379c710a00ec36cb4e9c748d1
Parent: 7be8f7a
Committed by Christopher Faulet <cfaulet@haproxy.com> on 7/27/2026, 1:28:17 PM