Skip to content

Commit

Permalink
fix: sanitize traceback for common secrets (#19805) (#19806)
Browse files Browse the repository at this point in the history
(cherry picked from commit 70ee927)

Co-authored-by: Ankush Menat <ankush@frappe.io>
  • Loading branch information
mergify[bot] and ankush committed Jan 27, 2023
1 parent 2f0dd6f commit ae6f2b1
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 2 deletions.
13 changes: 13 additions & 0 deletions frappe/tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -734,3 +734,16 @@ def test_url_expansion(self):
transforms = [("<a href='/about'>About</a>)", f"<a href='{site}/about'>About</a>)")]
for input, output in transforms:
self.assertEqual(output, expand_relative_urls(input))


class TestTBSanitization(FrappeTestCase):
def test_traceback_sanitzation(self):
try:
password = "42"
args = {"password": "42", "pwd": "42", "safe": "safe_value"}
raise Exception
except Exception:
traceback = frappe.get_traceback(with_context=True)
self.assertNotIn("42", traceback)
self.assertIn("********", traceback)
self.assertIn("safe_value", traceback)
43 changes: 41 additions & 2 deletions frappe/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
from urllib.parse import quote, urlparse

from redis.exceptions import ConnectionError
from traceback_with_variables import iter_exc_lines
from werkzeug.test import Client

import frappe
Expand Down Expand Up @@ -295,13 +294,15 @@ def get_traceback(with_context=False) -> str:
"""
Returns the traceback of the Exception
"""
from traceback_with_variables import iter_exc_lines

exc_type, exc_value, exc_tb = sys.exc_info()

if not any([exc_type, exc_value, exc_tb]):
return ""

if with_context:
trace_list = iter_exc_lines()
trace_list = iter_exc_lines(fmt=_get_sanitizer())
tb = "\n".join(trace_list)
else:
trace_list = traceback.format_exception(exc_type, exc_value, exc_tb)
Expand All @@ -311,6 +312,44 @@ def get_traceback(with_context=False) -> str:
return tb.replace(bench_path, "")


@functools.lru_cache(maxsize=1)
def _get_sanitizer():
from traceback_with_variables import Format

blocklist = [
"password",
"passwd",
"secret",
"token",
"key",
"pwd",
]

placeholder = "********"

def dict_printer(v: dict) -> str:
from copy import deepcopy

v = deepcopy(v)
for key in blocklist:
if key in v:
v[key] = placeholder

return str(v)

# Adapted from https://github.com/andy-landy/traceback_with_variables/blob/master/examples/format_customized.py
# Reused under MIT license: https://github.com/andy-landy/traceback_with_variables/blob/master/LICENSE

return Format(
custom_var_printers=[
# redact variables
*[(variable_name, lambda: placeholder) for variable_name in blocklist],
# redact dictionary keys
(["_secret", dict, lambda *a, **kw: False], dict_printer),
],
)


def log(event, details):
frappe.logger(event).info(details)

Expand Down

0 comments on commit ae6f2b1

Please sign in to comment.