Skip to content

Sanitize sensitive variables in RequestPanel #2105

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Prev Previous commit
Next Next commit
Add tests for sanitizing sensitive data
- Test handling in dicts and QueryDicts
- Test string substitution
  • Loading branch information
dr-rompecabezas committed Mar 13, 2025
commit 12ef38f8b4f067d922bc8ab440d0e78fc6c97b36
73 changes: 73 additions & 0 deletions tests/panels/test_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,3 +136,76 @@ def test_session_list_sorted_or_not(self):
self.panel.generate_stats(self.request, response)
panel_stats = self.panel.get_stats()
self.assertEqual(panel_stats["session"], data)

def test_sensitive_post_data_sanitized(self):
"""Test that sensitive POST data is redacted."""
self.request.POST = {"username": "testuser", "password": "secret123"}
response = self.panel.process_request(self.request)
self.panel.generate_stats(self.request, response)

# Check that password is redacted in panel content
content = self.panel.content
self.assertIn("username", content)
self.assertIn("testuser", content)
self.assertIn("password", content)
self.assertNotIn("secret123", content)
self.assertIn("********************", content)

def test_sensitive_get_data_sanitized(self):
"""Test that sensitive GET data is redacted."""
self.request.GET = {"api_key": "abc123", "q": "search term"}
response = self.panel.process_request(self.request)
self.panel.generate_stats(self.request, response)

# Check that api_key is redacted in panel content
content = self.panel.content
self.assertIn("api_key", content)
self.assertNotIn("abc123", content)
self.assertIn("********************", content)
self.assertIn("q", content)
self.assertIn("search term", content)

def test_sensitive_cookie_data_sanitized(self):
"""Test that sensitive cookie data is redacted."""
self.request.COOKIES = {"session_id": "abc123", "auth_token": "xyz789"}
response = self.panel.process_request(self.request)
self.panel.generate_stats(self.request, response)

# Check that auth_token is redacted in panel content
content = self.panel.content
self.assertIn("session_id", content)
self.assertIn("abc123", content)
self.assertIn("auth_token", content)
self.assertNotIn("xyz789", content)
self.assertIn("********************", content)

def test_sensitive_session_data_sanitized(self):
"""Test that sensitive session data is redacted."""
self.request.session = {"user_id": 123, "auth_token": "xyz789"}
response = self.panel.process_request(self.request)
self.panel.generate_stats(self.request, response)

# Check that auth_token is redacted in panel content
content = self.panel.content
self.assertIn("user_id", content)
self.assertIn("123", content)
self.assertIn("auth_token", content)
self.assertNotIn("xyz789", content)
self.assertIn("********************", content)

def test_querydict_sanitized(self):
"""Test that sensitive data in QueryDict objects is properly redacted."""
query_dict = QueryDict("username=testuser&password=secret123&token=abc456")
self.request.GET = query_dict
response = self.panel.process_request(self.request)
self.panel.generate_stats(self.request, response)

# Check that sensitive data is redacted in panel content
content = self.panel.content
self.assertIn("username", content)
self.assertIn("testuser", content)
self.assertIn("password", content)
self.assertNotIn("secret123", content)
self.assertIn("token", content)
self.assertNotIn("abc456", content)
self.assertIn("********************", content)
62 changes: 62 additions & 0 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import unittest

from django.http import QueryDict
from django.test import override_settings

import debug_toolbar.utils
Expand All @@ -8,6 +9,7 @@
get_stack,
get_stack_trace,
render_stacktrace,
sanitize_and_sort_request_vars,
tidy_stacktrace,
)

Expand Down Expand Up @@ -109,3 +111,63 @@ def __init__(self, value):
rendered_stack_2 = render_stacktrace(stack_2_wrapper.value)
self.assertNotIn("test_locals_value_1", rendered_stack_2)
self.assertIn("test_locals_value_2", rendered_stack_2)


class SanitizeAndSortRequestVarsTestCase(unittest.TestCase):
"""Tests for the sanitize_and_sort_request_vars function."""

def test_dict_sanitization(self):
"""Test sanitization of a regular dictionary."""
test_dict = {
"username": "testuser",
"password": "secret123",
"api_key": "abc123",
}
result = sanitize_and_sort_request_vars(test_dict)

# Convert to dict for easier testing
result_dict = dict(result["list"])

self.assertEqual(result_dict["username"], "testuser")
self.assertEqual(result_dict["password"], "********************")
self.assertEqual(result_dict["api_key"], "********************")

def test_querydict_sanitization(self):
"""Test sanitization of a QueryDict."""
query_dict = QueryDict("username=testuser&password=secret123&api_key=abc123")
result = sanitize_and_sort_request_vars(query_dict)

# Convert to dict for easier testing
result_dict = dict(result["list"])

self.assertEqual(result_dict["username"], "testuser")
self.assertEqual(result_dict["password"], "********************")
self.assertEqual(result_dict["api_key"], "********************")

def test_non_sortable_dict_keys(self):
"""Test dictionary with keys that can't be sorted."""
test_dict = {
1: "one",
"2": "two",
None: "none",
}
result = sanitize_and_sort_request_vars(test_dict)
self.assertEqual(len(result["list"]), 3)
result_dict = dict(result["list"])
self.assertEqual(result_dict[1], "one")
self.assertEqual(result_dict["2"], "two")
self.assertEqual(result_dict[None], "none")

def test_querydict_multiple_values(self):
"""Test QueryDict with multiple values for the same key."""
query_dict = QueryDict("name=bar1&name=bar2&title=value")
result = sanitize_and_sort_request_vars(query_dict)
result_dict = dict(result["list"])
self.assertEqual(result_dict["name"], ["bar1", "bar2"])
self.assertEqual(result_dict["title"], "value")

def test_non_dict_input(self):
"""Test handling of non-dict input."""
test_input = ["not", "a", "dict"]
result = sanitize_and_sort_request_vars(test_input)
self.assertEqual(result["raw"], test_input)