Skip to content

Security: server-side WebAuthn challenges; verify gateway TLS in the CLI - #23

Open
ndbroadbent wants to merge 1 commit into
nathan/security-authzfrom
nathan/security-webauthn
Open

ndbroadbent wants to merge 1 commit into
nathan/security-authzfrom
nathan/security-webauthn

Conversation

@ndbroadbent

Copy link
Copy Markdown
Member

This PR is stacked on #19. It fixes RG-11 (MFA-4, CLI-1, CLI-10, MFA-13) from the 2026-10-09 audit.

WebAuthn (server)

  • Before: challenges went round-trip through the client as session_data, and the server trusted whatever came back:
    • one captured assertion was a reusable step-up proof;
    • a zeroed Expires skipped go-webauthn's expiry check.
  • Now: challenges are stored in a webauthn_challenges table.
    • Each one is bound to the user and to the session that started the ceremony.
    • Each one is single-use (DELETE … RETURNING) and expires after a few minutes.
    • The client only gets an opaque ID, in the same session_data field, so the SPA needs no change.
    • This applies to login MFA, step-up, inline WebAuthn on the proxy, and enrollment.
  • Signature counter: it's now stored and enforced, so a cloned authenticator is detected.

CLI

  • TLS verification: proxied Convox commands used stdsdk's HTTP client and websocket dialer, both of which have InsecureSkipVerify set. Anyone able to intercept the connection could capture the session token and MFA proof.
    • Both now verify certificates against the system roots.
    • Plain http:// is refused except for loopback gateways.
  • Proxy URL credentials are now URL-encoded. Before, a parse failure printed an error that included the token.
  • Inline step-up WebAuthn derives the RP ID from the configured gateway host and rejects a different RP ID sent by the server.

Testing

  • New tests:
    • challenge single-use, expiry and session binding
    • sign-counter enforcement
    • CLI TLS against untrusted and trusted test servers
    • RP ID mismatch
  • Local results:
    • task go:test, task web:test, lint and duplication checks: all pass
    • web E2E: 56/56 on fresh test DBs
    • CLI E2E: green

Migration: 20261009120000_webauthn_challenges.sql

WebAuthn (server):
- Challenges used to round-trip through the client as session_data and
  were trusted on the way back. One captured assertion could be replayed
  as a step-up proof indefinitely, and a zeroed Expires skipped
  go-webauthn's expiry check.
- Challenges now live in a webauthn_challenges table, bound to the user
  and the session that started the ceremony. They are single-use
  (DELETE ... RETURNING), expire after a few minutes, and the client only
  gets an opaque ID back in the same session_data field. This covers
  login MFA, step-up, inline WebAuthn on the proxy, and enrollment.
- The credential sign counter is stored and enforced (clone detection).

CLI:
- Every proxied Convox command went through stdsdk's http.Client and
  websocket dialer, which set InsecureSkipVerify. A man-in-the-middle
  with any certificate got the session token and MFA proof from the
  Basic auth header. Both now verify certificates against the system
  roots, and plain http:// is refused except for loopback gateways.
- The rack-proxy URL's credentials are URL-encoded, so inline WebAuthn
  data can't break parsing (the parse error used to echo the token).
- Inline step-up WebAuthn derives the RP ID from the configured gateway
  host and rejects a different RP ID sent by the server.
@coderabbitai

coderabbitai Bot commented Oct 9, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Essentials
  • Run ID: 8ca2cb7a-e5b1-40a0-92bf-ffb28b18a914

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@deepsource-io

deepsource-io Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

DeepSource Code Review

We reviewed changes in f1ccd58...cd8e7df on this pull request. Below is the summary for the review, and you can see the individual issues we found as inline review comments.

See full review on DeepSource ↗

PR Report Card

Overall Grade   Security  

Reliability  

Complexity  

Hygiene  

Code Review Summary

Analyzer Status Updated (UTC) Details
JavaScript Oct 9, 2026 5:03a.m. Review ↗
Go Oct 9, 2026 5:03a.m. Review ↗

Important

AI Review is run only on demand for your team. We're only showing results of static analysis review right now. To trigger AI Review, comment @deepsourcebot review on this thread.

This branch has not been deployed

No deployments
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.

1 participant