From 67fd0b3a9fc9e6b50389f647b6fd7e2ae3dcd498 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sat, 25 Apr 2026 06:12:05 +0000 Subject: [PATCH] fix(security): sanitize API pagination parameters Fixed pagination security in API routes by safely parsing 'limit' and 'offset' query parameters. Previous implementation parsed them using 'parseInt' without 'isNaN' checks, allowing 'NaN' or negative numbers to be passed to Supabase's '.range()' and '.limit()' functions, risking runtime errors. This fix enforces safe bounds and default values. Co-authored-by: Shreyassp002 <96625037+Shreyassp002@users.noreply.github.com> --- src/app/api/transactions/history/route.ts | 4 +++- src/app/api/transactions/route.ts | 4 +++- src/app/api/v1/payment-links/route.ts | 9 +++++++-- src/app/api/v1/transactions/route.ts | 9 +++++++-- 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/app/api/transactions/history/route.ts b/src/app/api/transactions/history/route.ts index 62875f3..7c2bdb3 100644 --- a/src/app/api/transactions/history/route.ts +++ b/src/app/api/transactions/history/route.ts @@ -20,7 +20,9 @@ export async function GET(req: NextRequest) { const supabase = createServerClient() const { searchParams } = new URL(req.url) - const limit = Math.min(parseInt(searchParams.get('limit') || '50'), 100) + + const rawLimit = parseInt(searchParams.get('limit') || '50') + const limit = isNaN(rawLimit) || rawLimit < 1 ? 50 : Math.min(rawLimit, 100) // 1. Fetch Sent Transactions (where customer_wallet = walletAddress) const { data: sentTransactions, error: sentError } = await supabase diff --git a/src/app/api/transactions/route.ts b/src/app/api/transactions/route.ts index b619eb7..395ec9f 100644 --- a/src/app/api/transactions/route.ts +++ b/src/app/api/transactions/route.ts @@ -19,7 +19,9 @@ export async function GET(req: NextRequest) { const supabase = createServerClient() const { searchParams } = new URL(req.url) const paymentLinkId = searchParams.get('payment_link_id') - const limit = Math.min(parseInt(searchParams.get('limit') || '50'), 100) + + const rawLimit = parseInt(searchParams.get('limit') || '50') + const limit = isNaN(rawLimit) || rawLimit < 1 ? 50 : Math.min(rawLimit, 100) // eslint-disable-next-line @typescript-eslint/no-explicit-any let query = (supabase.from('transactions') as any) diff --git a/src/app/api/v1/payment-links/route.ts b/src/app/api/v1/payment-links/route.ts index 03280f8..65cc195 100644 --- a/src/app/api/v1/payment-links/route.ts +++ b/src/app/api/v1/payment-links/route.ts @@ -183,8 +183,13 @@ export async function GET(req: NextRequest) { } const { searchParams } = new URL(req.url) - const limit = Math.min(parseInt(searchParams.get('limit') || '10'), 100) - const offset = parseInt(searchParams.get('offset') || '0') + + // Parse pagination parameters securely to avoid NaN or negative values + const rawLimit = parseInt(searchParams.get('limit') || '10') + const limit = isNaN(rawLimit) || rawLimit < 1 ? 10 : Math.min(rawLimit, 100) + + const rawOffset = parseInt(searchParams.get('offset') || '0') + const offset = isNaN(rawOffset) || rawOffset < 0 ? 0 : rawOffset // eslint-disable-next-line @typescript-eslint/no-explicit-any const supabase = createServerClient() as any diff --git a/src/app/api/v1/transactions/route.ts b/src/app/api/v1/transactions/route.ts index 9beab7e..25cdb21 100644 --- a/src/app/api/v1/transactions/route.ts +++ b/src/app/api/v1/transactions/route.ts @@ -10,8 +10,13 @@ export async function GET(req: NextRequest) { } const { searchParams } = new URL(req.url) - const limit = Math.min(parseInt(searchParams.get('limit') || '10'), 100) - const offset = parseInt(searchParams.get('offset') || '0') + + const rawLimit = parseInt(searchParams.get('limit') || '10') + const limit = isNaN(rawLimit) || rawLimit < 1 ? 10 : Math.min(rawLimit, 100) + + const rawOffset = parseInt(searchParams.get('offset') || '0') + const offset = isNaN(rawOffset) || rawOffset < 0 ? 0 : rawOffset + const status = searchParams.get('status') const paymentLinkId = searchParams.get('payment_link_id')