mirror of
https://github.com/yogeshojha/rengine.git
synced 2026-10-20 23:31:31 +02:00
A sweep of every GET operation with hostile query values found eighteen that reached the database and failed there. Three causes, all of them user input arriving unbounded. A NUL byte in any text filter — project_slug, a WHOIS registrant, a screenshot path — is rejected by Postgres while binding, so the request died as a server error. NUL is never meaningful in a URL and is now refused once, at the edge, with a sentence saying so. Paging was unbounded upwards: a page number of 10^28 multiplied out to an offset the database refuses, and the user list took any skip or limit at all. Every paginated endpoint now shares one page shape with a ceiling, and the user list bounds both of its own. The activity filters typed their project, target and scan ids as plain strings, so anything that was not a UUID reached the query; the RIPEstat routes passed an ASN to int() without checking it was one. Both are now refused as malformed input rather than answered with a crash. The same sweep now reports no 5xx across 2,686 requests, and every list endpoint still reads. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01K6LcH8uUddjJbKrahf34ys
22 lines
852 B
Python
22 lines
852 B
Python
"""Reject request input the database cannot store before it reaches a query."""
|
|
|
|
from starlette.middleware.base import BaseHTTPMiddleware
|
|
from starlette.requests import Request
|
|
from starlette.responses import JSONResponse
|
|
from starlette.status import HTTP_400_BAD_REQUEST
|
|
|
|
# Postgres rejects NUL in text, so a parameter carrying one fails while binding and
|
|
# surfaces as a 500. It is never meaningful in a URL.
|
|
_NUL = "\x00"
|
|
|
|
|
|
class RejectNulMiddleware(BaseHTTPMiddleware):
|
|
async def dispatch(self, request: Request, call_next):
|
|
query = request.url.query
|
|
if query and (_NUL in query or "%00" in query.lower()):
|
|
return JSONResponse(
|
|
status_code=HTTP_400_BAD_REQUEST,
|
|
content={"detail": "Query parameters must not contain NUL bytes."},
|
|
)
|
|
return await call_next(request)
|