Summary
Despite the basic host validation introduced in #196 / #172, Uri::withHost() still accepts malformed and ambiguous host values containing:
- whitespace
- tabs
- malformed IPv6 authorities
- ambiguous multi-port authorities
These values propagate into:
Request Host headers
- serialized HTTP requests
- trusted
X-Forwarded-Host rewriting flows
This allows malformed Host headers such as:
Host: evil.com bad:8080
Host: evil.com<TAB>bad:8080
Host: example.com:80:90:8080
Host: [::1
to be generated by Diactoros request objects.
Affected Components
Laminas\Diactoros\Uri::withHost()
Laminas\Diactoros\Request
Laminas\Diactoros\RequestTrait
Laminas\Diactoros\ServerRequestFilter\FilterUsingXForwardedHeaders
Reproduction
Direct withHost() usage
<?php
require 'vendor/autoload.php';
use Laminas\Diactoros\Uri;
$hosts = [
'evil.com bad',
"evil.com\tbad",
'[::1',
'example.com:80:90',
];
foreach ($hosts as $host) {
echo "====================\n";
echo "HOST: " . json_encode($host) . "\n";
try {
$uri = (new Uri('http://example.com'))
->withHost($host);
echo "RESULT = " . (string)$uri . "\n";
} catch (Throwable $e) {
echo "EXCEPTION = " . $e->getMessage() . "\n";
}
echo "\n";
}
Output:
HOST: "evil.com bad"
RESULT = http://evil.com bad
HOST: "evil.com\tbad"
RESULT = http://evil.com bad
HOST: "[::1"
RESULT = http://[::1
HOST: "example.com:80:90"
RESULT = http://example.com:80:90
Host header propagation
<?php
require 'vendor/autoload.php';
use Laminas\Diactoros\Request;
use Laminas\Diactoros\Request\Serializer;
use Laminas\Diactoros\Uri;
$uri = (new Uri('http://127.0.0.1:8080'))
->withHost("evil.com\tbad");
$request = new Request($uri);
echo Serializer::toString($request);
Serialized request:
GET / HTTP/1.1
Host: evil.com bad:8080
Trusted X-Forwarded-Host rewriting
<?php
require 'vendor/autoload.php';
use Laminas\Diactoros\ServerRequest;
use Laminas\Diactoros\ServerRequestFilter\FilterUsingXForwardedHeaders;
use Laminas\Diactoros\Uri;
$request = new ServerRequest(
serverParams: [
'REMOTE_ADDR' => '127.0.0.1',
],
headers: [
'X-Forwarded-Host' => "evil.com\tbad",
],
uri: new Uri('http://original.local/')
);
$filter = FilterUsingXForwardedHeaders::trustAny();
$filtered = $filter($request);
echo $filtered->getHeaderLine('Host');
Output:
Expected Behavior
Uri::withHost() should reject malformed host values containing invalid whitespace, malformed authorities, or ambiguous host/port forms before they propagate into Host headers or serialized HTTP requests.
Notes
This appears related to the existing malformed URI handling discussions in:
The issue does not appear to be limited to URI stringification; malformed host values can propagate into actual serialized HTTP messages and trusted forwarded-header rewriting flows.
Summary
Despite the basic host validation introduced in #196 / #172,
Uri::withHost()still accepts malformed and ambiguous host values containing:These values propagate into:
RequestHost headersX-Forwarded-Hostrewriting flowsThis allows malformed Host headers such as:
to be generated by Diactoros request objects.
Affected Components
Laminas\Diactoros\Uri::withHost()Laminas\Diactoros\RequestLaminas\Diactoros\RequestTraitLaminas\Diactoros\ServerRequestFilter\FilterUsingXForwardedHeadersReproduction
Direct
withHost()usageOutput:
Host header propagation
Serialized request:
Trusted X-Forwarded-Host rewriting
Output:
Expected Behavior
Uri::withHost()should reject malformed host values containing invalid whitespace, malformed authorities, or ambiguous host/port forms before they propagate into Host headers or serialized HTTP requests.Notes
This appears related to the existing malformed URI handling discussions in:
Uri::__toString()can yield malformed URIs #172The issue does not appear to be limited to URI stringification; malformed host values can propagate into actual serialized HTTP messages and trusted forwarded-header rewriting flows.