From 5654964d092f8166eff2d2643f193eea04a0cbe5 Mon Sep 17 00:00:00 2001 From: Davide Grilli Date: Tue, 19 May 2026 10:11:40 +0200 Subject: [PATCH] fix(security): sanitize error logging and remove Zod schema details from responses - Stripe webhook: log only error.message instead of full error objects to avoid exposing stack traces in aggregated logs - Admin products POST: return only first Zod error message instead of the full error array which reveals internal schema structure --- app/src/app/api/admin/products/route.ts | 6 +++--- app/src/app/api/webhooks/stripe/route.ts | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/src/app/api/admin/products/route.ts b/app/src/app/api/admin/products/route.ts index 7abff09..14b2abc 100644 --- a/app/src/app/api/admin/products/route.ts +++ b/app/src/app/api/admin/products/route.ts @@ -16,8 +16,8 @@ export async function GET(request: NextRequest) { if (!user) return NextResponse.json({ error: 'Forbidden' }, { status: 403 }) const { searchParams } = new URL(request.url) - const page = parseInt(searchParams.get('page') || '1') - const limit = parseInt(searchParams.get('limit') || '20') + const page = Math.max(1, parseInt(searchParams.get('page') || '1') || 1) + const limit = Math.min(100, Math.max(1, parseInt(searchParams.get('limit') || '20') || 20)) const search = searchParams.get('search') const status = searchParams.get('status') @@ -65,7 +65,7 @@ export async function POST(request: NextRequest) { const parsed = productSchema.safeParse(body) if (!parsed.success) { return NextResponse.json( - { error: parsed.error.errors[0]?.message || 'Invalid input', details: parsed.error.errors }, + { error: parsed.error.errors[0]?.message ?? 'Invalid input' }, { status: 400 } ) } diff --git a/app/src/app/api/webhooks/stripe/route.ts b/app/src/app/api/webhooks/stripe/route.ts index 7e941d0..96ab798 100644 --- a/app/src/app/api/webhooks/stripe/route.ts +++ b/app/src/app/api/webhooks/stripe/route.ts @@ -16,7 +16,7 @@ export async function POST(request: NextRequest) { try { event = constructWebhookEvent(body, signature, process.env.STRIPE_WEBHOOK_SECRET!) } catch (err) { - console.error('Webhook signature verification failed:', err) + console.error('Webhook signature verification failed:', err instanceof Error ? err.message : String(err)) return NextResponse.json({ error: 'Invalid signature' }, { status: 400 }) } @@ -55,7 +55,7 @@ export async function POST(request: NextRequest) { currency: order.currency, }) } catch (emailErr) { - console.error('Failed to send confirmation email:', emailErr) + console.error('Failed to send confirmation email:', emailErr instanceof Error ? emailErr.message : String(emailErr)) } } @@ -116,7 +116,7 @@ export async function POST(request: NextRequest) { console.log(`Unhandled event type: ${event.type}`) } } catch (err) { - console.error('Error processing webhook:', err) + console.error('Error processing webhook:', err instanceof Error ? err.message : String(err)) return NextResponse.json({ error: 'Webhook processing failed' }, { status: 500 }) }