Skip to content

Threat Model — commercial SaaS surfaces (STRIDE)

Read in your language: English · Português · Español

audit-v6 DOCS-ARCH: SECURITY_ZTP_PREM.md covers the on-prem insider-threat model; this document covers the Internet-facing commercial surfaces. It is a living artifact — update it when a surface, data flow, or trust boundary changes.

1. Scope & trust boundaries

In scope: app.tlsstress.art (customer-app), admin.tlsstress.art (admin-console), the Cloudflare edge worker, and the on-prem → SaaS usage-report ingestion. Out of scope: the isolated NGFW test-bed data plane (operator-driven lab; separate on-prem threat model in security/THREAT_MODEL.md).

flowchart LR
    U[Customer browser] -->|TLS| E[Cloudflare edge worker]
    E -->|auth gate, rate limit, WAF| CA[customer-app]
    A[Admin] -->|TLS + MFA| AC[admin-console]
    OP[On-prem reporter] -->|signed usage report| CA
    CA --> DB[(Postgres — RLS)]
    AC --> DB
    CA --> ST[Stripe]
    ST -->|webhook| CA
    CA --> KMS[AWS KMS]

Trust boundaries: browser↔edge, edge↔customer-app, customer-app↔DB (RLS), customer-app↔Stripe, on-prem↔SaaS (signed reports), operator↔admin-console (MFA).

2. STRIDE analysis

# Threat (STRIDE) Surface Mitigation (in place) Residual / follow-up
S1 Spoofing a customer session customer-app HS256 JWT, algorithm fixed server-side (no alg-confusion), timingSafeEqual, exp/iat/iss/aud checks, per-request denylist + credential-epoch staleness (middleware + per-route)
S2 Spoofing the on-prem reporter usage ingest Signed usage report + usage_report_nonces (anti-replay) Rotate signing keys on a schedule
S3 Spoofing Stripe webhooks customer-app HMAC signature verify, fail-closed 503 when secret unset (payment and KYC after audit-v6)
T1 Tampering with the audit trail admin-console/DB WORM: DB trigger blocks UPDATE + early DELETE; SHA-256 hash chain; signed RFC-5424 export Register an IANA PEN (currently placeholder)
T2 Tampering with release images supply chain Multi-arch build + cosign keyless signing + SBOM; release now on GitHub-hosted runners; all actions SHA-pinned (audit-v6)
R1 Repudiation of admin actions admin-console admin_audit_events hash chain with actor + source IP + before/after SSO + SoD (depends on RBAC epic E1)
I1 Information disclosure cross-tenant customer-app/DB Per-query WHERE account_id; RLS tenant_isolation; withTenant() on tenant routes + CI guard test (audit-v6) Full default-deny cutover (dual DB roles)
I2 Information disclosure via headers edge/customer-app Middleware strips inbound x-admin-*/x-customer-* before setting verified identity; per-request nonce CSP with strict-dynamic
I3 Information disclosure of secrets all Fail-closed pepper/KMS; no hardcoded secrets (gitleaks gate); placeholder-secret guard rejects REPLACE_ME (audit-v6)
I4 Information disclosure — KYC/PII customer-app Stripe Identity (KYC data stays at Stripe); PII redaction in the audit log GDPR data-flow map + DPA (privacy track)
D1 Denial of service — auth brute force customer-app LRU + Postgres-backed rate limiter, fail-closed
D2 Denial of service — edge edge worker Rate limit + WAF rules; SLO rate cap Edge rate-limit fails open on DO error (tracked)
D3 Denial of service — oversized body customer-app/dashboard readJson() streams with a byte cap (audit-v6 — chunked-encoding bypass fixed)
E1 Elevation of privilege — IDOR refund customer-app Refund route verifies charge.customer == session account before refunding; MFA-gated
E2 Elevation of privilege — KYC self-verify customer-app KYC webhook fail-closed on unset secret (audit-v6) — a forged event can no longer self-verify
E3 Elevation of privilege — K8s on-prem control plane pie-pa-executor pods/exec namespaced; privileged host DaemonSets isolated to dut-system; dashboard hostPath removed (audit-v6) web-agents stays PSA privileged — the agents' DSCP/policy-routing init containers need NET_ADMIN/NET_RAW, which baseline rejects at admission (audit-v7 revert)

3. Assumptions

  • The Cloudflare edge terminates TLS and is the first WAF/rate-limit layer.
  • AWS KMS and Stripe are trusted third parties; their compromise is out of scope.
  • Postgres is reachable only from the app tier (PgBouncer); not Internet-exposed.

4. Open items feeding the risk register

IANA PEN registration · mTLS/CA-bundle for audit forwarding · SSO + SoD (RBAC E1) · GDPR data-flow map + DPA · full RLS default-deny cutover · edge rate-limit fail-closed. These are tracked in the launch go/no-go and the remediation plan.