mirror of
https://github.com/frappe/gunicorn.git
synced 2026-07-01 18:21:30 +08:00
Reject chunk extensions with bare CR bytes (RFC 9112)
Both WSGI and ASGI parsers now validate that chunk extensions do not contain bare CR characters, which are not allowed per RFC 9112. Fixes #3556
This commit is contained in:
parent
7057fc9f89
commit
bdb2ebd5a4
@ -15,6 +15,9 @@
|
||||
- **HTTP/2 Documentation**: Fix `http_protocols` examples to use comma-separated string
|
||||
instead of list syntax ([#3561](https://github.com/benoitc/gunicorn/issues/3561))
|
||||
|
||||
- **Chunked Encoding**: Reject chunk extensions containing bare CR bytes per RFC 9112
|
||||
([#3556](https://github.com/benoitc/gunicorn/discussions/3556))
|
||||
|
||||
### Security
|
||||
|
||||
- **ASGI Parser Header Validation**: Add security checks per RFC 9110/9112:
|
||||
|
||||
@ -15,6 +15,9 @@
|
||||
- **HTTP/2 Documentation**: Fix `http_protocols` examples to use comma-separated string
|
||||
instead of list syntax ([#3561](https://github.com/benoitc/gunicorn/issues/3561))
|
||||
|
||||
- **Chunked Encoding**: Reject chunk extensions containing bare CR bytes per RFC 9112
|
||||
([#3556](https://github.com/benoitc/gunicorn/discussions/3556))
|
||||
|
||||
### Security
|
||||
|
||||
- **ASGI Parser Header Validation**: Add security checks per RFC 9110/9112:
|
||||
|
||||
@ -670,6 +670,10 @@ class PythonProtocol:
|
||||
# Handle chunk extensions (e.g., "5;ext=value")
|
||||
semicolon = size_line.find(b';')
|
||||
if semicolon != -1:
|
||||
# RFC 9112: chunk-ext must not contain bare CR
|
||||
chunk_ext = size_line[semicolon + 1:]
|
||||
if b'\r' in chunk_ext:
|
||||
raise ParseError("Invalid chunk extension: bare CR not allowed")
|
||||
size_line = size_line[:semicolon]
|
||||
|
||||
# Strict validation: reject leading/trailing whitespace
|
||||
|
||||
@ -6,7 +6,7 @@ import io
|
||||
import sys
|
||||
|
||||
from gunicorn.http.errors import (NoMoreData, ChunkMissingTerminator,
|
||||
InvalidChunkSize)
|
||||
InvalidChunkSize, InvalidChunkExtension)
|
||||
|
||||
|
||||
class ChunkedReader:
|
||||
@ -90,6 +90,9 @@ class ChunkedReader:
|
||||
# RFC9112 7.1.1: BWS before chunk-ext - but ONLY then
|
||||
chunk_size, *chunk_ext = line.split(b";", 1)
|
||||
if chunk_ext:
|
||||
# RFC 9112: chunk-ext must not contain bare CR
|
||||
if b'\r' in chunk_ext[0]:
|
||||
raise InvalidChunkExtension("bare CR not allowed")
|
||||
chunk_size = chunk_size.rstrip(b" \t")
|
||||
if any(n not in b"0123456789abcdefABCDEF" for n in chunk_size):
|
||||
raise InvalidChunkSize(chunk_size)
|
||||
|
||||
@ -113,6 +113,16 @@ class ChunkMissingTerminator(IOError):
|
||||
return "Invalid chunk terminator is not '\\r\\n': %r" % self.term
|
||||
|
||||
|
||||
class InvalidChunkExtension(IOError):
|
||||
"""Invalid chunk extension per RFC 9112."""
|
||||
|
||||
def __init__(self, reason):
|
||||
self.reason = reason
|
||||
|
||||
def __str__(self):
|
||||
return "Invalid chunk extension: %s" % self.reason
|
||||
|
||||
|
||||
class LimitRequestLine(ParseException):
|
||||
def __init__(self, size, max_size=None):
|
||||
self.size = size
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user