Skip to content

Encryption in Transit

Statement

ClaimGuard's encryption-in-transit story is TLS end-to-end on every documented external path. There are two parallel public HTTPS ingresses today, both terminating TLS with managed certificates:

  • User-facing UI (canonical today): https://claim-guard.dtectvision.ai, served by nginx on the application VM with a Let's Encrypt certificate (Certbot-managed, auto-renewing). Nginx serves the built Vite dist/ for the static UI and proxies /api/ to the Node backend on loopback (loopback only). HTTP (:80) on the same hostname 301-redirects to HTTPS.
  • API-only ingress (parallel): https://app.dtectvision.ai, served by a GCP global external HTTPS Load Balancer with a Google-managed certificate (ACTIVE since 2026-05-03). HTTP (:80) on the same LB IP <LB_IP> 301-redirects to HTTPS (added 2026-05-04). The LB applies an attached Cloud Armor security policy (per-IP rate limit + Adaptive Protection L7-DDoS defense). The LB hits the same Node backend; GET / returns 404 because the LB does not serve the SPA — it is intentionally the API path.
  • Outbound from the application: every outbound flow — to GCP control-plane services, to GCS, to the internal analysis services, to operator- configured webhooks — uses TLS with system-trust-store certificate validation. Internal traffic between the Node backend and the Python tools never leaves the VM.
  • Future canonical: app.claim-guard.ai is the intended user-facing URL once the claim-guard.ai domain is acquired. Until then, claim-guard.dtectvision.ai is the URL prospects and customers should use.

The status below is partial only because the MODERN (TLS 1.2+) SSL policy has not yet been attached to the LB target HTTPS proxy — the LB defaults to the GCP COMPATIBLE profile which still permits TLS 1.0/1.1 ciphers.

Implementation

What's TLS today

Flow Direction TLS posture
User browser → claim-guard.dtectvision.ai Inbound to nginx on VM Let's Encrypt cert, HTTP→HTTPS 301 redirect, HSTS one-year.
Caller → app.dtectvision.ai (API ingress) Inbound to GCP HTTPS LB Google-managed cert, HTTP→HTTPS 301 redirect, Cloud Armor (rate limit + Adaptive DDoS), HSTS one-year.
LB → backend VM (LB-internal hop) Google internal network Plain HTTP between LB and NEG; runs inside Google's network, not the public internet.
nginx → Node backend (loopback only) Loopback on the VM Not TLS — same-host, never leaves the VM.
GCP control plane (Secret Manager, Cloud Logging, Compute, GCS) Outbound from VM TLS, Google-issued certificates, validated against system trust store.
internal analysis service (the configured analysis model) Outbound from VM (an internal analysis service) TLS, system trust store. See AI transparency.
Operator webhooks (SUPPORT_WEBHOOK_URL) Outbound from Node backend Wrapped by the outbound-HTTP wrapper. Enforces TLS for https:// URLs, blocks private/link-local/CGNAT ranges, refuses redirects by default. See SAST.
the image-analysis service → an internal peer VM Outbound to a separate VM Plain HTTP today (not TLS). The peer is the a peer VM (FastAPI image-analysis services). Cross-VM trust boundary; tracked as a follow-up to migrate behind an internal HTTPS endpoint or VPC-private network.
Internal: Node ↔ Python tools (an internal analysis service, content-provenance service, metadata-extraction service, etc.) Loopback (127.0.0.1) on the VM Not TLS — same-host, never leaves the VM. Documented as a deliberate design choice in docs/security/PROTOCOL.md §4.
Internal: Node ↔ Postgres Loopback on the VM Same as above — same-host. Postgres listens on local socket; no external network exposure.

What's not TLS today

  • internal tool ports on the VM IP are still reachable unauthenticated over plain TCP from 0.0.0.0/0 via the the internal-tool firewall rule. These are FastAPI internal tool ports (internal analysis service, the image-analysis service) that the application calls over loopback only; nothing legitimate connects to them externally. Tightening this rule is the residual the firewall-narrowing step follow-up.
  • No other plain-HTTP ingress. The the dev-server firewall rule firewall rule (the dev-server port world-open) was deleted 2026-05-04. The the application backend port was removed from the internal-tool firewall rule 2026-05-04, so the backend is no longer reachable directly via plain TCP on the VM IP.

Front-door hardening — what's in place 2026-05-04

For https://claim-guard.dtectvision.ai (nginx + Let's Encrypt):

  • HTTPS via Let's Encrypt cert (auto-renewed by Certbot).
  • HTTP (:80) → HTTPS (:443) 301 redirect at the nginx layer.
  • Static UI served from the built dist/; /api/ reverse-proxied to the Node backend on loopback loopback only.
  • Application-set headers (helmet): HSTS one-year + includeSubDomains, CSP default-src 'none'; frame-ancestors 'none', referrer-policy no-referrer, X-Content-Type-Options nosniff, COOP same-origin.

For https://app.dtectvision.ai (GCP HTTPS LB + Google-managed cert):

  • Google-managed certificate ACTIVE.
  • HTTP (:80) → HTTPS (:443) 301 redirect at the LB (<REDIRECT_URLMAP> + <HTTP_PROXY>, added 2026-05-04).
  • Backend zonal NEG points at the VM on an internal application port. Health check on /health. Firewall rule allow-lb-health restricts that port to GCP's LB source ranges (130.211.0.0/22, 35.191.0.0/16).
  • Cloud Armor security policy the Cloud Armor policy attached to the backend service:
  • Per-IP rate limit: 200 req/min, 5-minute ban on breach.
  • Adaptive Protection (Layer-7 DDoS defense, ML-scored) enabled.
  • Default rule: allow.
  • Same application-set headers (helmet) reach the browser through the LB hop.

the firewall-narrowing step — substantially closed; residue tracked

The world-open dev/internal port surface that the firewall-narrowing step was scoped to address has been narrowed substantially:

  • the dev-server firewall rule (the dev-server port): deleted 2026-05-04.
  • the internal-tool firewall rule: direct backend port removed 2026-05-04; rule now only allows the narrowed internal-tool ports.
  • an internal-tools firewall rule (an internal tool port, 9998, 8737, 5678): still in place, deferred pending operator confirmation that no external client uses these ports directly.
  • The two FastAPI tool ports (9996/9997) on the VM IP are the remaining 0.0.0.0/0 ingress that the firewall-narrowing step still has to address.

TLS versions and ciphers

  • Let's Encrypt cert on nginx uses the default Certbot configuration; cipher set follows Mozilla "intermediate".
  • GCP-managed cert on the LB uses the custom the MODERN-profile SSL policy SSL policy (MODERN profile, min_tls_version=TLS_1_2), attached to the LB HTTPS proxy 2026-05-06. TLS 1.0 and 1.1 are refused at the LB.
  • System-trust-store outbound uses Node.js / Python defaults, which require TLS 1.2+ and reject weak ciphers.

Certificate management

  • claim-guard.dtectvision.ai: Let's Encrypt via Certbot, auto-renewing on the VM. Certificate path: /etc/letsencrypt/live/claim-guard.dtectvision.ai/.
  • app.dtectvision.ai: Google-managed certificate on the LB, auto-renewed; no certificate handling in our codebase or operator procedures.
  • Outbound: the system trust store on the VM is the source of truth; we do not pin a certificate or maintain a custom root list.

Status

implemented — verified 2026-05-06.

What's in place:

  • Two parallel public HTTPS ingresses, both with HTTP→HTTPS 301 redirect, both with HSTS one-year + includeSubDomains:
  • claim-guard.dtectvision.ai (nginx + Let's Encrypt) — canonical user URL today.
  • app.dtectvision.ai (HTTPS LB + Google-managed cert) — API ingress, with Cloud Armor (rate limit + Adaptive L7-DDoS protection) attached to the backend service and the MODERN-profile SSL policy SSL policy (MODERN profile, TLS 1.2 floor) attached to the target HTTPS proxy 2026-05-06.
  • TLS for every outbound flow (GCP, the analysis service, operator webhooks).
  • the outbound-HTTP wrapper enforces TLS for outbound https:// URLs.
  • Internal traffic stays on loopback — no plaintext network hop between the Node backend, the Python tools, and Postgres.

Known gaps

  • internal tool ports on the VM IP are still world-open via the internal-tool firewall rule. These are FastAPI tool ports nothing external should reach. Roadmap.
  • the image-analysis service → a peer VM at an internal peer VM is plain HTTP across VMs (cross-VM trust boundary). Roadmap.
  • No /.well-known/security.txt at the application root yet (cross-listed on Vulnerability disclosure).

Roadmap

  • Narrow the internal-tool firewall rule further (or move the FastAPI tool services to bind on 127.0.0.1 and delete the rule entirely).
  • Migrate the image-analysis service ↔ a peer VM to TLS or to a VPC-private network hop.
  • /.well-known/security.txt at the application root.
  • Future: cut over to the new domain once app.claim-guard.ai is provisioned (DNS + cert).