diff options
| author | Fuwn <[email protected]> | 2026-02-08 09:21:50 -0800 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2026-02-08 09:21:50 -0800 |
| commit | 396c3f450e0f17b77478a0525029aa2534e764a9 (patch) | |
| tree | ac6d5f30c4cac6a7e9d07045d15b8388cd19791d /apps/web/app/api/account/data | |
| parent | security: harden database functions and policies (diff) | |
| download | asa.news-396c3f450e0f17b77478a0525029aa2534e764a9.tar.xz asa.news-396c3f450e0f17b77478a0525029aa2534e764a9.zip | |
security: harden API routes
- Add rate limiting to /api/share (30/min), /api/export (5/hr),
/api/account/data (3/day)
- Add client-side 30s throttle to forgot-password form
- Remove immediate tier upgrade on plan change; let invoice.paid
webhook handle tier promotion to prevent free upgrades on payment
failure
- Add SSRF validation to webhook URLs: block localhost, private IPs,
link-local, and metadata endpoints
- Log Stripe webhook signature verification errors instead of
swallowing silently
- Mask webhook secret in GET response (show first/last 4 chars only)
- Add error logging to API key last_used_at update
- Remove internal error message leaking from checkout session route
Diffstat (limited to 'apps/web/app/api/account/data')
| -rw-r--r-- | apps/web/app/api/account/data/route.ts | 6 |
1 files changed, 6 insertions, 0 deletions
diff --git a/apps/web/app/api/account/data/route.ts b/apps/web/app/api/account/data/route.ts index bec6ab9..f3a61ec 100644 --- a/apps/web/app/api/account/data/route.ts +++ b/apps/web/app/api/account/data/route.ts @@ -1,5 +1,6 @@ import { NextResponse } from "next/server" import { createSupabaseServerClient } from "@/lib/supabase/server" +import { rateLimit } from "@/lib/rate-limit" export async function GET() { const supabaseClient = await createSupabaseServerClient() @@ -11,6 +12,11 @@ export async function GET() { return NextResponse.json({ error: "not authenticated" }, { status: 401 }) } + const rateLimitResult = rateLimit(`gdpr-export:${user.id}`, 3, 86_400_000) + if (!rateLimitResult.success) { + return NextResponse.json({ error: "too many requests" }, { status: 429 }) + } + const [ profileResult, subscriptionsResult, |