Skip to content

The 8h localStorage HMAC is accepted without re-checking the GitHub session #70

Open

Description

@mashkovd

Context

/api/submit authenticates callers with an HMAC over the GitHub login: handleFormSubmit (cloudflare-worker/index.js:785-789) requires github_auth.login + github_auth.sig and verifies with hmacVerify(login, sig, GITHUB_OAUTH_HMAC_KEY). The signature is minted once at OAuth callback (index.js:588) and cached client-side in localStorage by app/composables/useAuth.ts with AUTH_TTL = 8 * 60 * 60 * 1000.

Nothing re-checks that the underlying GitHub session is still valid. For up to 8 hours after the user's actual GitHub session ends — or after the mctl_auth blob is copied off the machine — that value keeps working against /api/submit. The signature has no expiry of its own either: it covers only the login string, so the 8h bound is enforced entirely by the client that holds it. A copied blob can simply have its exp rewritten.

Raised while scoping #66 and deliberately left out of it, because the fix is a different shape than "add Turnstile". Note #66's operator decision extends this same credential to GET /api/github/check-team, so it now gates two endpoints rather than one — which strengthens the case for fixing it in one place instead of inventing a second, stronger gate for the lesser endpoint.

Expected direction

Any one of these closes it; the first is smallest:

  • Put an expiry inside the signed payload — sign login|exp rather than login, and reject server-side once exp passes. The client can no longer extend its own credential by editing localStorage, and the 8h bound becomes real.
  • Or bind the signature to the server-side OAuth session and re-check that session on submit.
  • Or drop the client-held credential entirely and authenticate submit from the __gh_session cookie.

Acceptance criteria

  • A mctl_auth value with a locally edited exp is rejected once the server-side expiry passes.
  • The signed material is no longer a bare, indefinitely-valid login string.
  • /api/submit and /api/github/check-team keep working for a normally signed-in user.

Follow-up from the 2026-08 platform audit (#66).

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

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions