summaryrefslogtreecommitdiff
path: root/django/utils
diff options
context:
space:
mode:
authorYashRaj1506 <yashraj504300@gmail.com>2025-06-26 03:31:00 +0530
committernessita <124304+nessita@users.noreply.github.com>2025-10-20 16:21:32 -0300
commit9bb83925d6c231e964f8b54efbc982fb1333da27 (patch)
treebbf430620cdb633c587414ef9a4910812aa148d7 /django/utils
parent5625bd590766e5ca8c2c76ba2307b98f7450ff83 (diff)
Fixed #36470 -- Prevented log injection in runserver when handling NOT FOUND.
Migrated `WSGIRequestHandler.log_message()` to use a more robust `log_message()` helper, which was based of `log_response()` via factoring out the common bits. Refs CVE-2025-48432. Co-authored-by: Natalia <124304+nessita@users.noreply.github.com>
Diffstat (limited to 'django/utils')
-rw-r--r--django/utils/log.py67
1 files changed, 47 insertions, 20 deletions
diff --git a/django/utils/log.py b/django/utils/log.py
index 67a40270f0..d4e96a9816 100644
--- a/django/utils/log.py
+++ b/django/utils/log.py
@@ -214,6 +214,46 @@ class ServerFormatter(logging.Formatter):
return self._fmt.find("{server_time}") >= 0
+def log_message(
+ logger,
+ message,
+ *args,
+ level=None,
+ status_code=None,
+ request=None,
+ exception=None,
+ **extra,
+):
+ """Log `message` using `logger` based on `status_code` and logger `level`.
+
+ Pass `request`, `status_code` (if defined) and any provided `extra` as such
+ to the logging method,
+
+ Arguments from `args` will be escaped to avoid potential log injections.
+
+ """
+ extra = {"request": request, **extra}
+ if status_code is not None:
+ extra["status_code"] = status_code
+ if level is None:
+ if status_code >= 500:
+ level = "error"
+ elif status_code >= 400:
+ level = "warning"
+
+ escaped_args = tuple(
+ a.encode("unicode_escape").decode("ascii") if isinstance(a, str) else a
+ for a in args
+ )
+
+ getattr(logger, level or "info")(
+ message,
+ *escaped_args,
+ extra=extra,
+ exc_info=exception,
+ )
+
+
def log_response(
message,
*args,
@@ -237,26 +277,13 @@ def log_response(
if getattr(response, "_has_been_logged", False):
return
- if level is None:
- if response.status_code >= 500:
- level = "error"
- elif response.status_code >= 400:
- level = "warning"
- else:
- level = "info"
-
- escaped_args = tuple(
- a.encode("unicode_escape").decode("ascii") if isinstance(a, str) else a
- for a in args
- )
-
- getattr(logger, level)(
+ log_message(
+ logger,
message,
- *escaped_args,
- extra={
- "status_code": response.status_code,
- "request": request,
- },
- exc_info=exception,
+ *args,
+ level=level,
+ status_code=response.status_code,
+ request=request,
+ exception=exception,
)
response._has_been_logged = True