Skip to content

security: redact private key material from SigningKey repr/str#494

Open
OscarOzaine wants to merge 1 commit into
Python-Cardano:mainfrom
OscarOzaine:security/redact-signing-key-repr
Open

security: redact private key material from SigningKey repr/str#494
OscarOzaine wants to merge 1 commit into
Python-Cardano:mainfrom
OscarOzaine:security/redact-signing-key-repr

Conversation

@OscarOzaine
Copy link
Copy Markdown

@OscarOzaine OscarOzaine commented Jun 6, 2026

The problem

Calling repr() or str() on a signing key returned its full JSON, including the raw private key in the cborHex field. That meant secret keys could leak into:

  • log files (anything that logs an object)
  • exception tracebacks
  • debugger / REPL output

…without the developer ever intending to export the key.

The fix

  • Signing keys (SigningKey, ExtendedSigningKey, and their subclasses) now print a redacted form instead of their secret material:

    <PaymentSigningKey type='PaymentSigningKey' hash=a1b2c3d4e5f6a7b8 [REDACTED]>
    

    The hash= value is a short, non-reversible fingerprint derived from the public verification-key hash (which is already public on-chain), so it's safe for logs while still letting you tell two keys apart.

  • __str__ now delegates to __repr__, so both are redacted.

  • The fingerprint helper never raises — a repr that throws would break debuggers and logging.

What does not change

Deliberate export paths are untouched: to_json(), to_cbor(), and save() still return/write the real key material. A warning was added to to_json() documenting that its output contains secret material. Verification keys are unaffected.

Tests

New tests in test/pycardano/test_key.py confirm repr/str never contain the private bytes, the fingerprint is stable and public-derived, and the export methods still work.

`__repr__` and `__str__` on signing keys previously delegated to
`to_json()`, which embeds the raw CBOR hex of the private key. This
caused the secret to leak in logs, exception tracebacks, debugger
output, f-strings, and REPL echo.

Add `_IS_SECRET = True` to `SigningKey` and `ExtendedSigningKey` (and
thus all concrete payment/stake/pool subclasses). Override `__repr__` to
emit a redacted placeholder containing only the class name, key type,
and a non-reversible 16-hex-char fingerprint derived from the public
verification key hash. `__str__` delegates to the same path.

`to_json()`, `to_cbor()`, and `save()` are untouched — callers who
invoke those have opted in to exporting key material.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant