fix(redact): anchor the path/var exemption so leading-/ and $ secrets still mask

_PATH_OR_VAR_VALUE_RE was an unanchored character class, so re.match made it a
first-character test: any assignment value beginning with '$', '/', or '~'
returned early from _should_redact_assignment, ahead of the strong-key and
opaque-credential checks. AWS secret access keys (~1 in 64 begin with '/') and
argon2/bcrypt digests (always '$'-prefixed) leaked verbatim through
redact_sensitive_text.

Anchor the pattern on both ends so the exemption only fires on a complete
$VAR/${VAR}/~/path//abs/path reference, and require a single-segment absolute
path — indistinguishable by shape from a high-entropy secret — to clear the
opaque-credential bar first. $VAR and ~/ references stay exempt
unconditionally, preserving the rc-readability contract that motivated the
exemption (SSH_AUTH_SOCK=$HOME/.ssh/agent.sock,
DOCKER_AUTH_CONFIG=/home/u/.docker).
This commit is contained in:
beardthelion
2026-09-15 10:15:53 -05:00
committed by Teknium
parent 7c5296ce1c
commit 93a0ec705a
2 changed files with 45 additions and 2 deletions
+13 -2
View File
@@ -312,7 +312,12 @@ _STRONG_KEY_KEYWORD_RE = re.compile(
# ``/usr/...`` or ``~/...`` references a variable or a path, not a credential, even under a strong key
# (``SSH_AUTH_SOCK=$HOME/.ssh/agent.sock``, ``DOCKER_AUTH_CONFIG=/home/u/.docker``).
_PASSWORD_KEY_RE = re.compile(r"passwd|password|pass|pw", re.IGNORECASE)
_PATH_OR_VAR_VALUE_RE = re.compile(r"[$/~]")
# Anchored on both ends: the whole value must be a ``$VAR``/``${VAR}`` reference, a ``~/``
# path, or an absolute path — not merely a string whose FIRST character is one of those.
# A 40-char AWS secret key starts with '/' ~1 in 64 times and argon2/bcrypt digests always
# start with '$'; an unanchored class let those secrets skip every check below.
_PATH_OR_VAR_VALUE_RE = re.compile(
r"^(?:\$\{?[A-Za-z_][A-Za-z0-9_]*\}?[/:.\w-]*|~/[\w./-]*|/(?:[\w.-]+/)*[\w.-]*)$")
def _is_word_start(s: str, i: int) -> bool:
@@ -381,7 +386,13 @@ def _should_redact_assignment(key: str, value: str, *, check_keyword: bool) -> b
# A shell rc's ``SSH_AUTH_SOCK=$HOME/.ssh/agent.sock`` is configuration the agent must keep
# readable; only password-class keys mask a path/variable reference.
if _PATH_OR_VAR_VALUE_RE.match(value) and not _has_word_bounded_keyword(key, _PASSWORD_KEY_RE):
return False
# ``$VAR`` and ``~/`` are unambiguous references. A bare ``/...`` is not:
# ``/home/u/.docker`` and ``/8f3kd9sKd0als...`` have the same shape, so a
# single-segment absolute path still has to clear the opaque-credential bar
# before it is treated as configuration.
if not (value.startswith("/") and "/" not in value[1:]
and _looks_like_opaque_credential(value)):
return False
return (_has_word_bounded_keyword(key, _STRONG_KEY_KEYWORD_RE)
or _looks_like_opaque_credential(value))