Skip to content

A hook secret that will not decrypt degrades to unsigned delivery #715

Description

@rainmanjam

From the poka-yoke audit of 2026-09-04. Lens: motion-step. Today: rung 3. Device reaches: rung 1 (Control). Silent.

The mistake available

Restore a backup with a different secret.key, or rotate the key.

internal/db/hooks.go:58:

if plain, err := box.Open(sealed); err == nil {
    h.Secret = plain
}
// err != nil: the row loads with an empty secret

internal/hooks/dispatch.go:602 then signs with nothing, and the POST goes out
unsigned.

What happens

The receiver cannot distinguish an unsigned delivery from a forgery. The signing
secret is the only thing that made the webhook trustworthy, and its absence is
indistinguishable, at the far end, from a hook that never had one.

internal/db/platforms.go:52 handles the identical situation the other way and
fails loud — so the two halves of the same decision disagree.

Today

Rung 3, weakly: hasSecret:false appears on a list nobody polls.

Device → rung 1, Control

Keep the row, set SecretUnreadable — exactly as Destination.KeyUnreadable
already does for stream keys — and have the dispatcher refuse to deliver a
hook whose secret is unreadable, raising an alert.

That makes "unsigned delivery" unreachable rather than merely visible. The
precedent is in the same package and the field naming already exists.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions