Skip to content

security(webhooks): fail closed when no HMAC secret (closes #99)#120

Merged
imran31415 merged 1 commit into
mainfrom
security/webhook-fail-closed
Jun 20, 2026
Merged

security(webhooks): fail closed when no HMAC secret (closes #99)#120
imran31415 merged 1 commit into
mainfrom
security/webhook-fail-closed

Conversation

@umi-appcoder

@umi-appcoder umi-appcoder Bot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

What

Makes webhook signature verification fail closed when no HMAC secret is configured. Closes #99 — PR 2 of the reliability-hardening series. (Security)

Why

verify_signature() returned True for a webhook with no hmac_secret ("open mode"). create() auto-mints a secret, but a hand-written / migrated config — or one whose secret was cleared directly on disk — was silently unauthenticated, so anonymous POSTs could spawn an AI assistant with tool access. That's an RCE-adjacent exposure.

Changes

  • verify_signature now fails closed (returns False, logs the reason) when no secret is set.
  • KC_ALLOW_UNSIGNED_WEBHOOKS=1 — explicit opt-in to restore open mode for local/testing (off by default).
  • _public_view exposes an unsigned flag so the dashboard can warn that a webhook is secret-less and will reject POSTs.

The update path already preserves the prior secret, so a normal edit can't clear it — this specifically closes the hand-edited-config / migration gap.

Tests

tests/server_test.py: fail-closed without secret, open-mode opt-in, KC_ALLOW_UNSIGNED_WEBHOOKS parsing, and the public-view unsigned flag (webhook suite 18 → 22). Full Python suite 470, OK.

Closes #99

🤖 Generated with Claude Code

verify_signature() previously returned True for a webhook with no
hmac_secret ("open mode"). create() auto-mints a secret, but a
hand-written / migrated config (or one whose secret was cleared on disk)
was silently unauthenticated — anonymous POSTs could spawn an AI
assistant with tool access.

- verify_signature now FAILS CLOSED (returns False, logs why) when no
  secret is configured.
- KC_ALLOW_UNSIGNED_WEBHOOKS=1 is an explicit opt-in for local/testing.
- _public_view exposes an `unsigned` flag so the dashboard can warn that
  a webhook is secret-less and will reject POSTs.

The update path already preserves the prior secret, so normal edits
can't clear it; this closes the hand-edited-config gap.

Tests (tests/server_test.py): fail-closed without secret, open-mode
opt-in, env parsing, and the public-view unsigned flag (webhook suite
18 -> 22). Full suite 470, OK.

Closes #99
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@imran31415 imran31415 merged commit d1379e5 into main Jun 20, 2026
7 checks passed
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.

security(webhooks): fail closed when no HMAC secret (close open-mode)

1 participant