• fix(security): authenticate /raft/forward (HMAC), add Content-Security-Policy
    Build and Push Docker Image / build-and-push (push) Failing after 53s
    Release / version (push) Successful in 25s
    Release / frontend (push) Failing after 24s
    Release / linux (amd64) (push) Skipped
    Release / linux (arm64) (push) Skipped
    Release / windows (push) Skipped
    Release / macos (push) Skipped
    Release / release (push) Skipped

    LastSkywalker released this 2026-08-31 23:04:59 +03:00

    Two findings from the security review of the gateway/app/controller surfaces.

    1. /raft/forward applied an arbitrary replicated Command with NO auth (only a
      rate limit) — anyone able to reach the leader's HTTP port could submit
      CmdUserUpsert{Role:ADMIN}, CmdConfigSet, CmdGatewayRouteUpsert, … i.e. take
      over the cluster (and, via a gateway route into the docker network, pivot
      further). The sibling off-Raft endpoints (metric stream, bridge) were already
      HMAC-signed; forwarding was the gap.

      Followers now sign forwards with the cluster-shared secret (ts-bound
      HMAC-SHA256, forwardauth.go). The leader verifies every present signature.
      Rolling-upgrade safe: an UNSIGNED forward is rejected only once EVERY voter
      advertises CapForwardHMAC in peer_node_advertise — until then the leader is
      permissive (with a throttled warning), so a mixed-version cluster or a bridge
      hub/spoke stays writable, then auto-enforces when the last old voter upgrades.
      No manual flag, no permanent gap. Verified live on a 2-node cluster: signed
      follower forwards work; unsigned + wrong-signature CmdUserUpsert{ADMIN} both
      401 and create no user; enforcement flips on automatically once both voters
      advertise the capability.

    2. No CSP. Added one tuned to what the SPA loads: script/connect 'self' (no
      third-party JS/XHR), inline style allowed (Recharts/Tailwind), https images
      for the wallpaper/icon CDNs, frame-ancestors/object-src locked down. Swagger
      UI exempt (needs an inline bootstrap script).

    Docs: ARCHITECTURE gains an "Inter-node auth" note incl. the standing rule that
    the app/Raft ports stay private and only the gateway's 80/443 face the internet.

    Co-Authored-By: Claude Fable 5 noreply@anthropic.com

    Downloads