Security Advisory: Migration Endpoint Falls Back to NEXTAUTH_SECRET
Security Advisory: Migration Endpoint Falls Back to NEXTAUTH_SECRET
Version: 1.0.396
Severity: High
Framework: ISO 27001
Affected file: src/app/api/migrate/route.ts
Overview
A compliance audit identified a security misconfiguration in the /api/migrate endpoint. The endpoint authenticates incoming requests using the following logic:
MIGRATION_SECRET ?? NEXTAUTH_SECRET
When the MIGRATION_SECRET environment variable is not set, the endpoint silently accepts NEXTAUTH_SECRET as a valid authentication token. This behaviour was unintentional and widens the attack surface of a production system significantly.
What Is the Risk?
1. Expanded Blast Radius of a NEXTAUTH_SECRET Leak
NEXTAUTH_SECRET is the signing key for all user session tokens. Its exposure is already serious — an attacker with access to it can forge arbitrary session cookies. The fallback behaviour means the same secret also grants the ability to trigger database schema migrations over HTTP, compounding the impact of any leak substantially.
2. No Visibility Into the Insecure Configuration
Because the fallback is silent, operators have no way to know — from logs, startup output, or monitoring — whether a dedicated MIGRATION_SECRET is actually in use. A production system could be running in the insecure configuration indefinitely without any indication.
3. High Inherent Risk of HTTP-Triggered Migrations
Running arbitrary schema migrations via an HTTP endpoint is already a high-risk pattern in production environments. Coupling that endpoint to the session signing secret multiplies the risk further.
Recommended Remediation
Step 1 — Set a Dedicated MIGRATION_SECRET
Generate a strong, unique secret for migration endpoint authentication:
openssl rand -hex 32
Set this as the MIGRATION_SECRET environment variable in your production environment. Do not reuse NEXTAUTH_SECRET.
Step 2 — Remove the Fallback in Code
The fallback must be removed from src/app/api/migrate/route.ts. The endpoint should refuse to operate if MIGRATION_SECRET is not explicitly configured:
// Before (insecure)
const secret = process.env.MIGRATION_SECRET ?? process.env.NEXTAUTH_SECRET;
// After (required)
const secret = process.env.MIGRATION_SECRET;
if (!secret) {
throw new Error(
'MIGRATION_SECRET is not set. Refusing to expose migration endpoint without a dedicated secret.'
);
}
Step 3 — Assert Secret Separation at Startup
Add a startup assertion to detect accidental reuse:
if (
process.env.MIGRATION_SECRET &&
process.env.MIGRATION_SECRET === process.env.NEXTAUTH_SECRET
) {
throw new Error(
'MIGRATION_SECRET must not equal NEXTAUTH_SECRET. Use a separate, unique secret for migration authentication.'
);
}
Step 4 — Restrict Network Access (Recommended)
Apply IP allowlisting to the /api/migrate route so it is only reachable from your CI/CD infrastructure or a trusted internal network. This limits exposure even if the secret were leaked.
Step 5 — Consider Removing the HTTP Endpoint Entirely (Best Practice)
The most secure posture is to remove the /api/migrate HTTP endpoint altogether and run schema migrations exclusively as part of your CI/CD pipeline (e.g. a prisma migrate deploy step before the application starts). This eliminates the attack surface entirely.
Checklist for Production Operators
-
MIGRATION_SECRETis set to a unique value in all production environments -
MIGRATION_SECRETdoes not equalNEXTAUTH_SECRET - The
NEXTAUTH_SECRETfallback has been removed fromsrc/app/api/migrate/route.ts - A startup assertion validates secret separation
- Network access to
/api/migrateis restricted to trusted sources, or the endpoint has been removed
References
- ISO 27001 — A.9 Access Control
- ISO 27001 — A.14 System Acquisition, Development and Maintenance
- OWASP: Secrets Management