6767 r"(?i)conn_str" ,
6868 r"(?i)connstr" ,
6969 r"(?i)dsn" ,
70+ # The signature parameter of a signed URL, such as an Azure SAS URL. It is matched
71+ # as a query parameter, because the bare word `sig` occurs in common names.
72+ r"(?i)[?&]sig=" ,
7073]
7174
7275DEFAULT_CODE_VARIABLES_IGNORE_PATTERNS = [r"^__.*" ]
@@ -124,6 +127,39 @@ def _redact_url_credentials(value):
124127 )
125128
126129
130+ # Matches the credential of an HTTP `Authorization` value, e.g. `Bearer <token>` or
131+ # `Basic <base64 user:pass>`. A header pair list or an ASGI scope holds this value apart
132+ # from its header name, so the name patterns never see it.
133+ _AUTH_HEADER_CREDENTIALS_RE = re .compile (
134+ r"\b(bearer|basic)(\s+)([A-Za-z0-9._~+/-]+=*)" , re .IGNORECASE
135+ )
136+
137+ # Shorter values, and lowercase words, are prose such as "basic authentication".
138+ _AUTH_HEADER_CREDENTIAL_MIN_LENGTH = 8
139+
140+
141+ def _redact_auth_header_match (match ):
142+ credential = match .group (3 )
143+ if len (credential ) < _AUTH_HEADER_CREDENTIAL_MIN_LENGTH or (
144+ credential .isalpha () and credential .islower ()
145+ ):
146+ return match .group (0 )
147+ return match .group (1 ) + match .group (2 ) + CODE_VARIABLES_REDACTED_VALUE
148+
149+
150+ def _redact_auth_header_credentials (value ):
151+ return _AUTH_HEADER_CREDENTIALS_RE .sub (_redact_auth_header_match , value )
152+
153+
154+ def _redact_embedded_credentials (value , config ):
155+ """Scrub credentials embedded in otherwise safe text: `Authorization` values always,
156+ and URL credentials when that toggle is on."""
157+ value = _redact_auth_header_credentials (value )
158+ if config .mask_url_credentials :
159+ value = _redact_url_credentials (value )
160+ return value
161+
162+
127163DEFAULT_TOTAL_VARIABLES_SIZE_LIMIT = 10 * 1024
128164
129165
@@ -1270,16 +1306,14 @@ def _looks_like_secret(value):
12701306
12711307def _mask_string (value , config ):
12721308 """Apply the string masking policy: over-length cap, name/value patterns,
1273- entropy-based secret detection, then embedded URL credentials."""
1309+ entropy-based secret detection, then embedded `Authorization` and URL credentials."""
12741310 if len (value ) > _MAX_VALUE_LENGTH_FOR_PATTERN_MATCH :
12751311 return CODE_VARIABLES_TOO_LONG_VALUE
12761312 if _matcher_matches (value , config .mask ):
12771313 return CODE_VARIABLES_REDACTED_VALUE
12781314 if config .detect_secrets and _looks_like_secret (value ):
12791315 return CODE_VARIABLES_REDACTED_VALUE
1280- if config .mask_url_credentials :
1281- return _redact_url_credentials (value )
1282- return value
1316+ return _redact_embedded_credentials (value , config )
12831317
12841318
12851319def _safe_type_name (value ):
@@ -1306,9 +1340,7 @@ def _safe_repr(value, config):
13061340 # A __repr__ that is itself a bare secret would otherwise bypass detection.
13071341 if config .detect_secrets and _looks_like_secret (rendered ):
13081342 return CODE_VARIABLES_REDACTED_VALUE
1309- if config .mask_url_credentials :
1310- return _redact_url_credentials (rendered )
1311- return rendered
1343+ return _redact_embedded_credentials (rendered , config )
13121344
13131345
13141346def _extract_object_attrs (value ):
@@ -1485,8 +1517,8 @@ def _mask_mapping(items, config, seen, depth):
14851517 out_key = _redacted_key (result )
14861518 elif not key_is_json_safe and _key_parts_fail_masking (key , config , seen , depth ):
14871519 out_key = _redacted_key (result )
1488- elif config . mask_url_credentials and isinstance (out_key , str ):
1489- out_key = _redact_url_credentials (out_key )
1520+ elif isinstance (out_key , str ):
1521+ out_key = _redact_embedded_credentials (out_key , config )
14901522 if out_key in result :
14911523 # Two keys can end up with the same text, for example URLs that differ only in
14921524 # their credentials. A placeholder keeps the later entry from overwriting.
0 commit comments