Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# 7.8.3 - 2026-02-09

fix: do not pattern match long values in code variables

# 7.8.3 - 2026-02-06

fix: openAI input image sanitization
Expand Down
39 changes: 23 additions & 16 deletions posthog/exception_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,26 +43,29 @@
DEFAULT_MAX_VALUE_LENGTH = 1024

DEFAULT_CODE_VARIABLES_MASK_PATTERNS = [
r"(?i).*password.*",
r"(?i).*secret.*",
r"(?i).*passwd.*",
r"(?i).*pwd.*",
r"(?i).*api_key.*",
r"(?i).*apikey.*",
r"(?i).*auth.*",
r"(?i).*credentials.*",
r"(?i).*privatekey.*",
r"(?i).*private_key.*",
r"(?i).*token.*",
r"(?i).*aws_access_key_id.*",
r"(?i).*_pass",
r"(?i)sk_.*",
r"(?i).*jwt.*",
r"(?i)password",
r"(?i)secret",
r"(?i)passwd",
r"(?i)pwd",
r"(?i)api_key",
r"(?i)apikey",
r"(?i)auth",
r"(?i)credentials",
r"(?i)privatekey",
r"(?i)private_key",
r"(?i)token",
r"(?i)aws_access_key_id",
r"(?i)_pass",
r"(?i)sk_",
r"(?i)jwt",
]

DEFAULT_CODE_VARIABLES_IGNORE_PATTERNS = [r"^__.*"]

CODE_VARIABLES_REDACTED_VALUE = "$$_posthog_redacted_based_on_masking_rules_$$"
CODE_VARIABLES_TOO_LONG_VALUE = "$$_posthog_value_too_long_$$"

_MAX_VALUE_LENGTH_FOR_PATTERN_MATCH = 5_000

DEFAULT_TOTAL_VARIABLES_SIZE_LIMIT = 20 * 1024

Expand Down Expand Up @@ -962,6 +965,8 @@ def _mask_sensitive_data(value, compiled_mask):
masked_items = [_mask_sensitive_data(item, compiled_mask) for item in value]
return type(value)(masked_items)
elif isinstance(value, str):
if len(value) > _MAX_VALUE_LENGTH_FOR_PATTERN_MATCH:
return CODE_VARIABLES_TOO_LONG_VALUE
if _pattern_matches(value, compiled_mask):
return CODE_VARIABLES_REDACTED_VALUE
return value
Expand All @@ -982,7 +987,9 @@ def _serialize_variable_value(value, limiter, max_length=1024, compiled_mask=Non
limiter.add(result_size)
return value
elif isinstance(value, str):
if compiled_mask and _pattern_matches(value, compiled_mask):
if len(value) > _MAX_VALUE_LENGTH_FOR_PATTERN_MATCH:
result = CODE_VARIABLES_TOO_LONG_VALUE
elif compiled_mask and _pattern_matches(value, compiled_mask):
result = CODE_VARIABLES_REDACTED_VALUE
else:
result = value
Expand Down
94 changes: 94 additions & 0 deletions posthog/test/test_exception_capture.py
Original file line number Diff line number Diff line change
Expand Up @@ -450,3 +450,97 @@ def trigger_error():
assert "<CustomReprClass: custom representation>" in output
assert "<lambda>" in output
assert "<function trigger_error at" in output


def test_code_variables_too_long_string_value_replaced(tmpdir):
app = tmpdir.join("app.py")
app.write(
dedent(
"""
import os
from posthog import Posthog

posthog = Posthog(
'phc_x',
host='https://eu.i.posthog.com',
debug=True,
enable_exception_autocapture=True,
capture_exception_code_variables=True,
project_root=os.path.dirname(os.path.abspath(__file__))
)

def trigger_error():
short_value = "I am short"
long_value = "x" * 20000
long_blob = "password_" + "a" * 20000

1/0

trigger_error()
"""
)
)

with pytest.raises(subprocess.CalledProcessError) as excinfo:
subprocess.check_output([sys.executable, str(app)], stderr=subprocess.STDOUT)

output = excinfo.value.output.decode("utf-8")

assert "ZeroDivisionError" in output
assert "code_variables" in output

assert "'short_value': 'I am short'" in output

assert "$$_posthog_value_too_long_$$" in output

assert "'long_blob': '$$_posthog_value_too_long_$$'" in output


def test_code_variables_too_long_string_in_nested_dict(tmpdir):
app = tmpdir.join("app.py")
app.write(
dedent(
"""
import os
from posthog import Posthog

posthog = Posthog(
'phc_x',
host='https://eu.i.posthog.com',
debug=True,
enable_exception_autocapture=True,
capture_exception_code_variables=True,
project_root=os.path.dirname(os.path.abspath(__file__))
)

def trigger_error():
my_data = {
"short_key": "short_val",
"long_key": "y" * 20000,
"nested": {
"deep_long": "z" * 20000,
"deep_short": "ok",
},
}

1/0

trigger_error()
"""
)
)

with pytest.raises(subprocess.CalledProcessError) as excinfo:
subprocess.check_output([sys.executable, str(app)], stderr=subprocess.STDOUT)

output = excinfo.value.output.decode("utf-8")

assert "ZeroDivisionError" in output
assert "code_variables" in output

assert "short_val" in output
assert "ok" in output

assert "$$_posthog_value_too_long_$$" in output
assert "y" * 1000 not in output
assert "z" * 1000 not in output
2 changes: 1 addition & 1 deletion posthog/version.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
VERSION = "7.8.3"
VERSION = "7.8.4"

if __name__ == "__main__":
print(VERSION, end="") # noqa: T201
Loading