Downgrade removes access to premium features
Why it matters
If your webhook handler doesn't process customer.subscription.updated events for downgrades and cancellations, plan data in your database goes stale — canceled subscribers retain premium access indefinitely. OWASP A01 (Broken Access Control) and CWE-284 (Improper Access Control) apply, plus ISO 25010 functional correctness: the system doesn't do what it claims. The cancel_at_period_end case is the most commonly missed: Stripe sends an updated event when a subscription is scheduled to cancel, not a deleted event — only the deleted event fires when cancellation actually completes.
Severity rationale
High because unhandled downgrade and cancellation webhooks leave former paid users with permanent premium access after their subscription ends.
Remediation
Handle both customer.subscription.updated and customer.subscription.deleted in your webhook handler, and update both the plan field and subscription status on every event.
case 'customer.subscription.updated':
case 'customer.subscription.deleted': {
const subscription = event.data.object
const status = subscription.status
const planKey = subscription.items.data[0]?.price.lookup_key ?? 'free'
await db.user.update({
where: { stripe_customer_id: subscription.customer as string },
data: {
plan: ['active', 'trialing'].includes(status) ? planKey : 'free',
subscription_status: status,
subscription_ends_at: new Date(subscription.current_period_end * 1000)
}
})
break
}
Also handle the cancel_at_period_end: true case in customer.subscription.updated — Stripe sends this event when a customer schedules a cancellation but access should continue until current_period_end.
DetectionPro
The detection method for this pattern is part of AuditBuffet Pro.
The full method (what to look for, pass and fail conditions, and how results get reported) ships inside the Billing & Payments Audit. The pattern definition, severity rationale, and remediation remain openly licensed under CC-BY-4.0.
External references
- cwe · CWE-284 — Improper Access Control
- owasp:2021 · A01 — Broken Access Control
- iso-25010:2011 · functional-correctness — Functional Correctness — subscription state transitions produce correct access outcomes
Taxons
History
- 2026-04-18·v1.0.0·Initial import from saas-billing·automated