Skip to content

Commit 7aa2bce

Browse files
committed
Bound decompression of the client-controlled rememberedidps cookie
# If applied, this commit will... Add an explicit 64KB max_length bound to the gzinflate() call used to decode the rememberedidps cookie. # Why is this change needed? Prior to this change, inflate() called gzinflate() with no explicit output-size bound, which was flagged in review: a small, highly compressible attacker-crafted cookie should never be allowed to decompress into an unbounded buffer. # How does it address the issue? This change passes a 65536-byte max_length to gzinflate(), so an oversized or maliciously compressed cookie is rejected as invalid instead of being decompressed without limit. # Provide links to any relevant tickets, articles or other resources #2091
1 parent 78ced24 commit 7aa2bce

2 files changed

Lines changed: 10 additions & 1 deletion

File tree

‎src/OpenConext/EngineBlock/Service/Wayf/RememberedIdpCookie.php‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
final class RememberedIdpCookie
3232
{
3333
public const NAME = 'rememberedidps';
34+
private const int MAX_INFLATED_BYTES = 65536;
3435

3536
public static function isEnabledForServiceProvider(
3637
bool $globalRememberChoiceEnabled,
@@ -241,7 +242,7 @@ private function inflate(string $decoded): ?string
241242
{
242243
set_error_handler(static fn(): bool => true);
243244
try {
244-
$inflated = gzinflate($decoded);
245+
$inflated = gzinflate($decoded, self::MAX_INFLATED_BYTES);
245246
} finally {
246247
restore_error_handler();
247248
}

‎tests/unit/OpenConext/EngineBlock/Service/Wayf/RememberedIdpCookieTest.php‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,14 @@ public static function invalidCookieProvider(): array
121121
'missing expires' => [self::rawJson('{"https://sp.example.org":{"idp":"https://idp.example.org"}}')],
122122
'non-integer expires' => [self::rawJson('{"https://sp.example.org":{"idp":"https://idp.example.org","expires":"1700003600"}}')],
123123
'extra entry key' => [self::rawJson('{"https://sp.example.org":{"idp":"https://idp.example.org","expires":1700003600,"extra":"unexpected"}}')],
124+
'oversized decompressed payload exceeds the bound' => [
125+
base64_encode((string) gzdeflate((string) json_encode([
126+
'https://sp.example.org' => [
127+
'idp' => 'https://idp.example.org/' . str_repeat('a', 100000),
128+
'expires' => 1700003600,
129+
],
130+
]))),
131+
],
124132
];
125133
}
126134

0 commit comments

Comments
 (0)