Skip to content

red-team: leak a credential past sanitize_reason in a non-URL shape #21

Description

@hellno

Daemon reason/error strings cross the trust boundary into agent transcripts that leave
the machine. To keep RPC API keys out of them, sanitize_reason
(crates/deckard-signerd/src/config.rs) scrubs every whitespace-delimited token
containing ://
down to scheme://host[:port] before the reason is truncated and
returned. The T9 transcript allowlist scan is the backstop.

The claim to attack

  • For realistic transport-error shapes (alloy/reqwest echoing the full request URL, with
    the key in the path/query/userinfo), the URL-token scrub catches the credential — this
    is unit-tested and canary-tested end to end.

Where the code is

  • crates/deckard-signerd/src/config.rssanitize_reason (token-based URL scrub),
    redact_url.
  • crates/deckard-signerd/src/daemon.rsone_line (the wrapper that runs
    sanitize_reason then truncates to 160 chars on every broadcast_failed / signer-error
    reason), and the broadcast_failed: {…} / signer_error: {…} / railgun_keys: {…} call
    sites that feed it arbitrary upstream error text.

What a successful finding looks like

  • A realistic transport/RPC/library error whose text carries the credential in a shape
    with no :// in the same whitespace token — so the scrub leaves it untouched — and
    that still gets surfaced in a reason. Examples worth probing: a bare
    Authorization: Bearer <token> header echoed in an error, a key in a JSON error body,
    a host=…&apikey=…-style query fragment split onto its own line, an error that puts the
    URL after a newline that one_line discards but with the key duplicated elsewhere, or a
    proxy/DNS error format that prints user:pass@host without the scheme.
  • Show the leak reaches a tool transcript (i.e. it also slips the T9 allowlist scan, or
    argue why the scan wouldn't catch that shape).

Severity framing

High if reproducible against a real RPC provider's error text — a leaked API key is a
funds-adjacent privacy/cost compromise. The fix is likely an allowlist-of-shapes or an
entropy/secret-pattern scrub in addition to the URL-token rule; a good finding tells us
which shape to add.

Metadata

Metadata

Assignees

No one assigned

    Labels

    red-teamInvitation to attack a stated security claimsecuritySecurity-relevant

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions