CVE-2026-22041

Redaction via Destruction: Crashing Python Logs with CVE-2026-22041

Alon Barad
Alon Barad
Software Engineer

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_copy

In 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-is

The 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, loggingredactor will 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.

Fix Analysis (1)

Technical Appendix

CVSS Score
7.5/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
EPSS Probability
0.04%
Top 100% most exploited

Affected Systems

Python applications using loggingredactor < 0.0.6Django/Flask apps with custom logging filters using this library

Affected Versions Detail

Product
Affected Versions
Fixed Version
loggingredactor
armurox
< 0.0.60.0.6
AttributeDetail
CWE IDCWE-704 (Incorrect Type Conversion)
Attack VectorLocal / Network (Triggerable via log inputs)
CVSS7.5 (High)
ImpactDenial of Service (Application Crash)
LanguagePython
Fix StatusPatched in v0.0.6
CWE-704
Incorrect Type Conversion or Cast

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.

Vulnerability Timeline

Issue Reported on GitHub
2024-01-01
Patch Developed (v0.0.6)
2024-01-02
Advisory Published
2024-01-03

Subscribe to updates

Get the latest CVE analysis reports delivered to your inbox.