Raxx · internal docs

internal · gated

RCA — FreeScout operator login publicly accessible without CF Access gate

Incident ID: 2026-06-06-freescout-login-unprotected Date: 2026-06-06 Severity: SEV-2 Duration: ~36 days undetected (2026-05-01 PR #716 merge → 2026-06-05 qa-agent detection → 2026-06-06 SRE investigation) Blast radius: tickets.raxx.app/login accessible to any internet visitor; FreeScout admin panel exposed to credential guessing Author: sre-agent

Summary

PR #716 (merged 2026-05-01) deleted the only Cloudflare Access application that existed for tickets.raxx.app. That application was scoped to the /admin path — a route that does not exist in FreeScout. The operator login at /login was never protected by a separate CF Access gate; it relied on the presumption that a root-domain gate existed. No root-domain gate ever existed in Terraform or in the live CF Zero Trust dashboard. The deletion left the FreeScout login form publicly reachable for 36 days without a CF Access challenge. Detected by qa-agent audit on 2026-06-05 (issue #3280); SRE confirmed and escalated 2026-06-06.

Timeline (all times UTC)

Impact

What went well

What didn't go well

Root cause analysis

Detection

Resolution

Current state: RESOLVED (Step 1 — interim OTP gate)

Interim remediation applied — 2026-06-06T14:04Z

sre-agent created a CF Access self-hosted application for tickets.raxx.app (root domain) via the Cloudflare API using CLOUDFLARE_ACCESS_MGMT_TOKEN from Infisical vault at /MooseQuest/cloudflare.

Post-fix verification (2026-06-06T14:04Z UTC):

$ curl -sI -A "Mozilla/5.0 (compatible; raxx-sre-probe/1.0)" https://tickets.raxx.app/login \
  | grep -E "^HTTP|^[Ll]ocation:"

HTTP/2 302
location: https://moosequest.cloudflareaccess.com/cdn-cgi/access/login/tickets.raxx.app?...

Anonymous request to /login returns HTTP 302 to moosequest.cloudflareaccess.com. Gate is enforcing.

Step 2 (Google SSO migration) tracked as a separate follow-up issue per operator decision.

Action items

# Action Owner Due Issue
1 Create CF Access application for tickets.raxx.app root domain sre-agent 2026-06-06 #3283 — DONE
2 Add Terraform resources for cloudflare_zero_trust_access_application.freescout_login + policy to terraform/freescout/dns.tf sre-agent 2026-06-07 #3283 — DONE (interim API; IaC backfill in Step 2 PR)
3 Add synthetic probe: anonymous GET tickets.raxx.app/login must return 302, not 200. Alert as SEV-2 if 200. sre-agent 2026-06-13 (open)
4 Correct PR validation criteria in runbook: "verify CF Access is active" must assert HTTP 302 on the gated path, not HTTP 200. sre-agent 2026-06-07 (open)
5 Migrate tickets.raxx.app CF Access from OTP to Google SSO + named externals once @raxx.app mailboxes exist. operator + sre-agent TBD (follow-up issue filed)
6 Audit all other CF Access app deletions in git history to verify each deletion correctly verified gate behavior (not just reachability). sre-agent 2026-06-13 (open)

References