From ff1f3e0aa3735e130006b34c29ab9455e31cf41f Mon Sep 17 00:00:00 2001 From: xyz <2523269+antojoseph@users.noreply.github.com> Date: Thu, 30 Apr 2026 17:43:30 -0400 Subject: [PATCH] security: remove client-controlled x-coordinator-url (SSRF) All five console API proxy routes read x-coordinator-url from the request and forwarded Privy session tokens or cookies to that arbitrary URL. An attacker could exfiltrate bearer tokens to any server they control. Remove the header read; always use DEFAULT_COORD (the server-side env var). --- console-ui/src/app/api/payments/stripe/checkout/route.ts | 2 +- console-ui/src/app/api/payments/stripe/onboard/route.ts | 2 +- console-ui/src/app/api/payments/stripe/status/route.ts | 2 +- console-ui/src/app/api/payments/withdraw/stripe/route.ts | 2 +- console-ui/src/app/api/telemetry/route.ts | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/console-ui/src/app/api/payments/stripe/checkout/route.ts b/console-ui/src/app/api/payments/stripe/checkout/route.ts index 9668fcfa..4ff76527 100644 --- a/console-ui/src/app/api/payments/stripe/checkout/route.ts +++ b/console-ui/src/app/api/payments/stripe/checkout/route.ts @@ -7,7 +7,7 @@ import { NextRequest, NextResponse } from "next/server"; const DEFAULT_COORD = process.env.NEXT_PUBLIC_COORDINATOR_URL || "https://api.darkbloom.dev"; export async function POST(req: NextRequest) { - const coordUrl = req.headers.get("x-coordinator-url") || DEFAULT_COORD; + const coordUrl = DEFAULT_COORD; let authHeader = req.headers.get("authorization") || ""; if (!authHeader) { diff --git a/console-ui/src/app/api/payments/stripe/onboard/route.ts b/console-ui/src/app/api/payments/stripe/onboard/route.ts index 8735517f..8dfe3add 100644 --- a/console-ui/src/app/api/payments/stripe/onboard/route.ts +++ b/console-ui/src/app/api/payments/stripe/onboard/route.ts @@ -7,7 +7,7 @@ import { NextRequest, NextResponse } from "next/server"; const DEFAULT_COORD = process.env.NEXT_PUBLIC_COORDINATOR_URL || "https://api.darkbloom.dev"; export async function POST(req: NextRequest) { - const coordUrl = req.headers.get("x-coordinator-url") || DEFAULT_COORD; + const coordUrl = DEFAULT_COORD; let authHeader = req.headers.get("authorization") || ""; if (!authHeader) { diff --git a/console-ui/src/app/api/payments/stripe/status/route.ts b/console-ui/src/app/api/payments/stripe/status/route.ts index 0bd26c5d..25a5b9d7 100644 --- a/console-ui/src/app/api/payments/stripe/status/route.ts +++ b/console-ui/src/app/api/payments/stripe/status/route.ts @@ -6,7 +6,7 @@ import { NextRequest, NextResponse } from "next/server"; const DEFAULT_COORD = process.env.NEXT_PUBLIC_COORDINATOR_URL || "https://api.darkbloom.dev"; export async function GET(req: NextRequest) { - const coordUrl = req.headers.get("x-coordinator-url") || DEFAULT_COORD; + const coordUrl = DEFAULT_COORD; let authHeader = req.headers.get("authorization") || ""; if (!authHeader) { diff --git a/console-ui/src/app/api/payments/withdraw/stripe/route.ts b/console-ui/src/app/api/payments/withdraw/stripe/route.ts index 5f58de33..ca54cde3 100644 --- a/console-ui/src/app/api/payments/withdraw/stripe/route.ts +++ b/console-ui/src/app/api/payments/withdraw/stripe/route.ts @@ -7,7 +7,7 @@ import { NextRequest, NextResponse } from "next/server"; const DEFAULT_COORD = process.env.NEXT_PUBLIC_COORDINATOR_URL || "https://api.darkbloom.dev"; export async function POST(req: NextRequest) { - const coordUrl = req.headers.get("x-coordinator-url") || DEFAULT_COORD; + const coordUrl = DEFAULT_COORD; let authHeader = req.headers.get("authorization") || ""; if (!authHeader) { diff --git a/console-ui/src/app/api/telemetry/route.ts b/console-ui/src/app/api/telemetry/route.ts index 956b7cb2..2240f557 100644 --- a/console-ui/src/app/api/telemetry/route.ts +++ b/console-ui/src/app/api/telemetry/route.ts @@ -11,7 +11,7 @@ const MAX_BODY = 64 * 1024; export const runtime = "nodejs"; export async function POST(req: NextRequest) { - const coordUrl = req.headers.get("x-coordinator-url") || DEFAULT_COORD; + const coordUrl = DEFAULT_COORD; // Read with explicit size cap. const raw = await req.text();