Security: admin role on every admin route
Two admin routes let any registered user read your subscribers' and customers' emails. If you have a project in production, apply it even if you are not touching anything else.
This release closes a security hole in the boilerplate itself and fixes blog posts with code blocks. If you have a project in production built with CREA.MBA, apply it now.
Admin routes that only asked for a session
GET /api/admin/newsletter and GET /api/admin/subscriptions checked that there was a session, but
not that the user was an admin. Any registered user of your app could read the email of every
newsletter subscriber and of your customers, with their purchases and subscriptions. They now
answer 403.
On top of that, all of api/admin/** now uses a single admin check with consistent answers: 401
without a session, 403 with a session and no admin role. The admin post pages are now protected on
the server too, not only in the browser. And a test walks every admin route and fails if a new one
does not return 403 to a non-admin: an unguarded endpoint no longer passes bun run test.
Posts with code blocks
Since 2.1.0, any blog post with a code block answered with a 500 error. The syntax highlighter reads the current time while it renders each line, and Next 16 with Cache Components does not allow that. The highlighted output is now cached and those posts load again.
If you already have a project
- Copy
src/lib/auth/roles.tsandsrc/lib/auth/admin-guard.tsinto your project. - In
src/app/api/admin/newsletter/route.tsandsrc/app/api/admin/subscriptions/route.ts, wrap theGETwithwithAdmin. If you cannot copy files, the minimal fix is changingif (!session)toif (!session || session.user.role !== 'admin')and returning 403. - Review your own admin routes:
grep -rn "getSession" src/app/api/admin. - Copy
src/lib/auth/admin-guard.test.tsand runbun run test. It tells you if any admin route is still unguarded. - For posts with code, add
'use cache'andcacheLife('max')at the top ofmarkdownToHtml. rm -rf .next && bun run buildlocally before deploying.
No migrations and no new environment variables. The full detail is in the repo's CHANGELOG.md.