Skip to content

Commit 1563614

Browse files
authored
fix: redact token from TokenSecret repr to prevent API key leaks (#11810)
1 parent a913f01 commit 1563614

3 files changed

Lines changed: 17 additions & 0 deletions

File tree

haystack/utils/auth.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,10 @@ def _from_dict(_: dict[str, Any]) -> "Secret":
162162
"Cannot deserialize token-based secret. Use an alternative secret type like environment variables."
163163
)
164164

165+
def __repr__(self) -> str:
166+
# Hide the token so it can't leak through print/log/traceback formatting.
167+
return f"TokenSecret(_token=<redacted>, _type={self._type!r})"
168+
165169
def resolve_value(self) -> Any | None:
166170
"""Return the token."""
167171
return self._token
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
security:
3+
- |
4+
The ``repr()`` of a ``Secret`` built via ``Secret.from_token(...)`` no longer
5+
includes the raw token. Previously the dataclass-generated repr printed the
6+
token verbatim, so any path that formats a component's locals — exception
7+
tracebacks, ``print()``, Jupyter echo, log aggregators — could leak the API
8+
key. The token is now rendered as ``<redacted>``.

test/utils/test_auth.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ def test_token_secret():
3636
with pytest.raises(FrozenInstanceError):
3737
secret._type = SecretType.ENV_VAR # type: ignore[misc]
3838

39+
secret = Secret.from_token("sk-supersecret-1234567890ABCDEF")
40+
assert "sk-supersecret-1234567890ABCDEF" not in repr(secret)
41+
assert "sk-supersecret-1234567890ABCDEF" not in str(secret)
42+
assert "<redacted>" in repr(secret)
43+
3944

4045
def test_env_var_secret():
4146
secret = Secret.from_env_var("TEST_ENV_VAR1")

0 commit comments

Comments
 (0)