You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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.
Summary
CreateTriggersetsSecretHashto the raw secret and returns it, andRotateSecretdoes the same on every rotation.Impact
Evidence
control-plane/internal/handlers/webhook_triggers.go:104-151storesSecretHash: secretand returns"secret": <raw>in the creation response;RotateSecretreturns the raw secret as well.control-plane/internal/webhooks/signature.go:26-37validates the HMAC but never enforces timestamp age/skew, andReceiveWebhooktrusts whatever timestamp is provided (webhook_triggers.go:479-488).Recommendation