securityengineering
Threat Model Writing
Create STRIDE-based threat models with asset identification, threat actor enumeration, attack surface mapping, risk scoring, and a prioritized mitigation matrix — producing a living security document.
threat-modelingSTRIDEsecurityrisk-assessmentattack-surface
Works well with agents
Works well with skills
threat-model-writing/
payment-flow.md
Markdown| 1 | # Payment Processing Flow — STRIDE Threat Model |
| 2 | |
| 3 | ## 1. System Overview |
| 4 | |
| 5 | The checkout flow accepts payment details from a React SPA, submits them to a backend API (Node.js), which creates a PaymentIntent via Stripe's API and records the transaction in PostgreSQL. Webhook callbacks from Stripe confirm or reject charges asynchronously. |
| 6 | |
| 7 | ``` |
| 8 | Browser → (HTTPS) → API Gateway → (internal TLS) → Payment API → (TLS) → Stripe |
| 9 | ↓ |
| 10 | PostgreSQL (RDS) |
| 11 | Stripe → (webhook HTTPS) → Payment API |
| 12 | ``` |
| 13 | |
| 14 | ## 2. Assets |
| 15 | |
| 16 | | Asset | Confidentiality | Integrity | Availability | Notes | |
| 17 | |-------|----------------|-----------|--------------|-------| |
| 18 | | Card details (transient) | Critical | Critical | N/A | Never stored; passed directly to Stripe via client-side SDK | |
| 19 | | Stripe secret keys | Critical | Critical | High | Stored in AWS Secrets Manager | |
| 20 | | Payment records | High | Critical | High | Order amounts, status, customer ID | |
| 21 | | Webhook signing secret | Critical | Critical | High | Validates Stripe callback authenticity | |
| 22 | | Session tokens | High | High | Medium | JWT, 15-min expiry, HttpOnly cookies | |
| 23 | |
| 24 | ## 3. Threat Actors |
| 25 | |
| 26 | - **External unauthenticated** — Automated scanners, carders testing stolen card numbers at scale |
| 27 | - **External authenticated** — Malicious user with a valid account attempting price manipulation or refund fraud |
| 28 | - **Insider** — Engineer or support agent with production database access |
| 29 | - **Supply chain** — Compromised npm dependency in the payment API |
| 30 | |
| 31 | ## 4. Attack Surface |
| 32 | |
| 33 | - Public endpoint: `POST /v1/payments` (accepts amount, currency, payment method token) |
| 34 | - Stripe webhook endpoint: `POST /webhooks/stripe` (accepts signed payloads) |
| 35 | - Admin dashboard: internal tool for viewing payment records and issuing refunds |
| 36 | - CI/CD pipeline: deploys payment service; has access to Stripe keys during build |
| 37 | |
| 38 | ## 5. STRIDE Threat Matrix |
| 39 | |
| 40 | | ID | Category | Threat | Attack Scenario | Component | |
| 41 | |----|----------|--------|-----------------|-----------| |
| 42 | | S-1 | Spoofing | Forged webhook | Attacker sends fake Stripe webhook to `POST /webhooks/stripe` without valid signature, marking unpaid orders as paid | Payment API | |
| 43 | | T-1 | Tampering | Price manipulation | Authenticated user modifies `amount_cents` in the `POST /v1/payments` request body to pay $0.01 for a $99 item | Payment API | |
| 44 | | T-2 | Tampering | Replay attack | Attacker replays a captured payment request to trigger duplicate charges | Payment API | |
| 45 | | R-1 | Repudiation | Unlogged refund | Support agent issues a refund via admin dashboard with no audit trail | Admin Dashboard | |
| 46 | | I-1 | Info Disclosure | Error stack trace | Payment failure returns Stripe API key fragment in verbose error message to browser | API Gateway | |
| 47 | | D-1 | Denial of Service | Webhook flooding | Attacker sends 50k fake webhook requests/sec, exhausting API server threads | Payment API | |
| 48 | | E-1 | Elevation | IDOR on refunds | User changes `payment_id` in refund request to access another user's payment record | Payment API | |
| 49 | |
| 50 | ## 6. Risk Scoring |
| 51 | |
| 52 | | Threat ID | Likelihood | Impact | Risk Score | Priority | |
| 53 | |-----------|-----------|--------|------------|----------| |
| 54 | | T-1 | 5 | 5 | 25 | Critical | |
| 55 | | S-1 | 4 | 5 | 20 | Critical | |
| 56 | | E-1 | 4 | 4 | 16 | Critical | |
| 57 | | I-1 | 3 | 4 | 12 | High | |
| 58 | | R-1 | 3 | 3 | 9 | High | |
| 59 | | D-1 | 3 | 3 | 9 | High | |
| 60 | | T-2 | 2 | 4 | 8 | High | |
| 61 | |
| 62 | ## 7. Mitigations |
| 63 | |
| 64 | | Threat ID | Mitigation | Control Type | Status | |
| 65 | |-----------|-----------|--------------|--------| |
| 66 | | T-1 | Server-side price validation: compare `amount_cents` against cart total from database before creating PaymentIntent | Preventive | Complete | |
| 67 | | S-1 | Verify Stripe webhook signature using `stripe.webhooks.constructEvent()` with the signing secret | Preventive | Complete | |
| 68 | | E-1 | Enforce ownership check: `WHERE payment.user_id = current_user.id` on all payment queries | Preventive | In progress | |
| 69 | | I-1 | Structured error responses only; strip stack traces in production via error middleware | Preventive | Complete | |
| 70 | | R-1 | Immutable audit log for all refund actions with actor ID, timestamp, and reason | Detective | Not started | |
| 71 | | D-1 | Rate limit webhook endpoint to 200 req/s; validate signature before processing | Preventive | Partial | |
| 72 | | T-2 | Idempotency key required on `POST /v1/payments`; reject duplicate keys within 24h | Preventive | Complete | |
| 73 | |
| 74 | ## 8. Residual Risk |
| 75 | |
| 76 | - **Stripe account compromise**: If Stripe's systems are breached, payment data may be exposed. Accepted risk — mitigated by Stripe's PCI Level 1 compliance. Review annually. |
| 77 | - **Insider DB access**: Engineers with production read access can view payment metadata. Compensating control: query audit logging via pgAudit. Full mitigation (column-level encryption) deferred to Q2. |
| 78 |