From 77a8170a6e8e34e981acc9137fe96bc2619324e7 Mon Sep 17 00:00:00 2001 From: Benjamin Admin Date: Thu, 26 Feb 2026 15:55:09 +0100 Subject: [PATCH] Fix proxy UUID validation: reject non-UUID tenant/user IDs and use defaults The training API client sends X-Tenant-ID: "default" which the proxy was forwarding as-is, causing the backend to return 0 results. Now both proxies validate that tenant/user IDs match UUID format before forwarding, falling back to the configured defaults. Co-Authored-By: Claude Opus 4.6 --- admin-compliance/app/(sdk)/sdk/academy/new/page.tsx | 2 +- .../app/api/sdk/v1/academy/[[...path]]/route.ts | 6 ++++-- .../app/api/sdk/v1/training/[[...path]]/route.ts | 8 ++++++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/admin-compliance/app/(sdk)/sdk/academy/new/page.tsx b/admin-compliance/app/(sdk)/sdk/academy/new/page.tsx index 9d9f1ba..5588b0f 100644 --- a/admin-compliance/app/(sdk)/sdk/academy/new/page.tsx +++ b/admin-compliance/app/(sdk)/sdk/academy/new/page.tsx @@ -32,7 +32,7 @@ export default function NewCoursePage() { // AI generation state - module selection const [trainingModules, setTrainingModules] = useState([]) const [selectedModuleId, setSelectedModuleId] = useState('') - const [modulesLoading, setModulesLoading] = useState(false) + const [modulesLoading, setModulesLoading] = useState(true) // Load training modules on mount useEffect(() => { diff --git a/admin-compliance/app/api/sdk/v1/academy/[[...path]]/route.ts b/admin-compliance/app/api/sdk/v1/academy/[[...path]]/route.ts index 63b0a78..e54c521 100644 --- a/admin-compliance/app/api/sdk/v1/academy/[[...path]]/route.ts +++ b/admin-compliance/app/api/sdk/v1/academy/[[...path]]/route.ts @@ -30,11 +30,13 @@ async function proxyRequest( } // Forward identity headers for RBAC context + // Only use client-provided values if they look like UUIDs + const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i const userHeader = request.headers.get('x-user-id') - headers['X-User-ID'] = userHeader || '00000000-0000-0000-0000-000000000001' + headers['X-User-ID'] = (userHeader && uuidRegex.test(userHeader)) ? userHeader : '00000000-0000-0000-0000-000000000001' const tenantHeader = request.headers.get('x-tenant-id') - headers['X-Tenant-ID'] = tenantHeader || (process.env.DEFAULT_TENANT_ID || '9282a473-5c95-4b3a-bf78-0ecc0ec71d3e') + headers['X-Tenant-ID'] = (tenantHeader && uuidRegex.test(tenantHeader)) ? tenantHeader : (process.env.DEFAULT_TENANT_ID || '9282a473-5c95-4b3a-bf78-0ecc0ec71d3e') const fetchOptions: RequestInit = { method, diff --git a/admin-compliance/app/api/sdk/v1/training/[[...path]]/route.ts b/admin-compliance/app/api/sdk/v1/training/[[...path]]/route.ts index c9cfd43..f448906 100644 --- a/admin-compliance/app/api/sdk/v1/training/[[...path]]/route.ts +++ b/admin-compliance/app/api/sdk/v1/training/[[...path]]/route.ts @@ -33,8 +33,12 @@ async function proxyRequest( } // Forward identity headers with defaults for RBAC context - headers['X-User-ID'] = request.headers.get('x-user-id') || '00000000-0000-0000-0000-000000000001' - headers['X-Tenant-ID'] = request.headers.get('x-tenant-id') || (process.env.DEFAULT_TENANT_ID || '9282a473-5c95-4b3a-bf78-0ecc0ec71d3e') + // Only use client-provided values if they look like UUIDs + const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i + const clientUserId = request.headers.get('x-user-id') + const clientTenantId = request.headers.get('x-tenant-id') + headers['X-User-ID'] = (clientUserId && uuidRegex.test(clientUserId)) ? clientUserId : '00000000-0000-0000-0000-000000000001' + headers['X-Tenant-ID'] = (clientTenantId && uuidRegex.test(clientTenantId)) ? clientTenantId : (process.env.DEFAULT_TENANT_ID || '9282a473-5c95-4b3a-bf78-0ecc0ec71d3e') const fetchOptions: RequestInit = { method,