Skip to content

Inbound webhook secrets stored in plaintext and replayable signatures #65

Description

@santoshkumarradha

Summary

  • Inbound webhook triggers persist signing secrets in plaintext and echo them back in API responses. CreateTrigger sets SecretHash to the raw secret and returns it, and RotateSecret does the same on every rotation.
  • Signature verification accepts any timestamp; there is no freshness check or replay protection, so a captured body + signature can be replayed indefinitely.

Impact

  • Anyone with database/backup access (or logs of the creation response) can recover every webhook secret and forge requests. There is no hashing/encryption to limit blast radius.
  • Because timestamps are not validated, an intercepted webhook can be replayed forever as long as the body/signature pair is known, bypassing idempotency TTLs.

Evidence

  • control-plane/internal/handlers/webhook_triggers.go:104-151 stores SecretHash: secret and returns "secret": <raw> in the creation response; RotateSecret returns the raw secret as well.
  • control-plane/internal/webhooks/signature.go:26-37 validates the HMAC but never enforces timestamp age/skew, and ReceiveWebhook trusts whatever timestamp is provided (webhook_triggers.go:479-488).

Recommendation

  • Store webhook secrets hashed or envelope-encrypted; avoid returning them after creation/rotation (surface only once or offer a short-lived token retrieval endpoint guarded by auth/audit).
  • Enforce timestamp freshness (e.g., 5–10 minute skew window) and reject stale or non-numeric timestamps; consider adding nonce-based replay protection.
  • Add migrations/tests to cover secret-at-rest handling and replay rejection so regressions are caught.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:control-planeControl plane server functionalitybugSomething isn't workinghelp wantedExtra attention is neededsecuritySecurity vulnerability

    Type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions