From 27e924c7cd9e712576dd6ed174f91ce2a79c223a Mon Sep 17 00:00:00 2001 From: Randall Stillwell Date: Sat, 23 May 2026 10:47:27 -0500 Subject: [PATCH] fix(auth): remove synthetic-admin bypass (Brief 2 of fix-auth-bypass) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes AGENTS.md gotcha #2: getUserFromRequest no longer returns a hardcoded { userId: 1, email: 'admin@tcgvault.com', role: 'admin' } when the Authorization header is missing or malformed. lib/permission-middleware.js - getUserFromRequest now returns null for missing/malformed Bearer headers. No console.warn, no NODE_ENV gate — the fallback is gone, period. - Token-verify path and DB lookup unchanged. pages/api/auth/verify.js - No-token branch now returns 401 instead of fetching the seed admin via `WHERE email = 'admin@tcgvault.com'`. Closes the admin-record- leak side of the same bypass. - JWT-verify branch unchanged. Known follow-up (flagged but NOT addressed in this PR): pages/api/collections/[identifier]/cards.js POST/PUT/DELETE handlers dereference user.userId without a null guard. Previously masked by the synthetic admin (anonymous-write-as-admin on collections owned by user 1 was the security hole). Now degrades to NPE → 500 instead of a clean 401. Security is improved either way; cosmetic 500-vs-401 fix lives in a separate one-line follow-up PR. Convoy: fix-auth-bypass / Brief 2 Co-authored-by: Cursor --- lib/permission-middleware.js | 4 +--- pages/api/auth/verify.js | 14 +------------- 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/lib/permission-middleware.js b/lib/permission-middleware.js index 49bd3d0..e505d43 100644 --- a/lib/permission-middleware.js +++ b/lib/permission-middleware.js @@ -10,9 +10,7 @@ export async function getUserFromRequest(req) { const authHeader = req.headers.authorization; if (!authHeader || !authHeader.startsWith('Bearer ')) { - // For development, return user ID 1 if no token (should be removed in production) - console.warn('⚠️ Development mode: Using fallback user authentication'); - return { userId: 1, email: 'admin@tcgvault.com', role: 'admin' }; + return null; } const token = authHeader.substring(7); diff --git a/pages/api/auth/verify.js b/pages/api/auth/verify.js index 7d9675d..e97bb95 100644 --- a/pages/api/auth/verify.js +++ b/pages/api/auth/verify.js @@ -22,19 +22,7 @@ export default async function handler(req, res) { const authHeader = req.headers.authorization; if (!authHeader || !authHeader.startsWith('Bearer ')) { - // For development, return admin user if no token provided - // In production, this should return 401 - const result = await sql` - SELECT id, email, role, created_at - FROM users - WHERE email = 'admin@tcgvault.com' - `; - - if (result.rows.length > 0) { - return res.status(200).json(result.rows[0]); - } else { - return res.status(401).json({ error: 'No admin user found' }); - } + return res.status(401).json({ error: 'Authentication required' }); } const token = authHeader.substring(7); -- 2.45.2