Django should not be leaking
your secrets.

Django is one of the most widely used web frameworks in Python. Exposing user secrets is a serious vulnerability for a framework of this scale. Kodah closed it in 78 seconds.

Repositorydjango/django · issue #12700
SeveritySecurity — disclosed publicly after review by Django's security team
Kodah runtime78.4 seconds

The bug

When a Django application crashes in debug mode, the framework displays a detailed error page that includes every value in the configuration file: database credentials, API keys, third-party service tokens, anything stored in settings. Django ships with a filter designed to make that page safe: before rendering, it scans every setting and replaces any value whose key matches sensitive patterns with a row of asterisks.

The filter worked correctly for dictionaries, recursing through every level and redacting what it found. What it didn't do was descend into lists, tuples, or sets.

If a sensitive value was stored inside a list, a completely common structure in Django configuration, the filter returned it untouched.

The filter stopped at the container boundary and passed the entire value through as-is. The redaction it was designed to provide simply didn't happen.

What Kodah did

Kodah identified that the filter's recursion logic covered dictionaries but stopped at other iterable types. The fix required extending that same recursion to lists, tuples, and sets, including arbitrarily nested combinations of them. Kodah also handled the edge case where a set contains unhashable items which would cause a silent failure if reconstructed naively after cleansing.


Kodah's patch

django/views/debug.py
+ elif isinstance(value, (list, tuple, set)): + def _clean_item(item): + if isinstance(item, dict): + return {k: self.cleanse_setting(k, v) for k, v in item.items()} + if isinstance(item, (list, tuple, set)): + cleaned = [_clean_item(i) for i in item] + if isinstance(item, tuple): + return tuple(cleaned) + try: + return set(cleaned) if isinstance(item, set) else cleaned + except TypeError: + return cleaned + return item

The human patch — commit 2c4e0f4

django/views/debug.py
+ elif isinstance(value, list): + cleansed = [self.cleanse_setting('', v) for v in value] + elif isinstance(value, tuple): + cleansed = tuple([self.cleanse_setting('', v) for v in value])

How they compare

Both patches fix the reported case. The human patch covers lists and tuples at a single level of depth, a direct answer to the issue as filed. Kodah, however, went further: beyond the reported cases, it covered sets, handled arbitrarily nested combinations of all three types recursively, and added a fallback for the edge case of unhashable items inside sets; none of which were in the original report, all of them already handled.

Coverage Kodah Human (commit 2c4e0f4)
Lists ✓ Covered ✓ Covered
Tuples ✓ Covered ✓ Covered
Sets ✓ Covered ✗ Not covered
Nested iterables ✓ Recursive ✗ One level only
Unhashable item fallback ✓ Handled ✗ Silent failure
78s Kodah runtime
Security Severity
5 Edge cases covered

A security gap in one of the most widely used frameworks in Python, fixed in 78 seconds. Kodah — $0.50 per fix.


← Back to Blog