firebase / firebase/apphosting-adapters

checkNextJSVersion blocks Next.js preview/prerelease tags (e.g. next@preview)

Open
#661 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
478
Forks
1.5k
Avg merge
3d 22h
Merged PRs (30d)
2

Description

## Summary

`checkNextJSVersion` wrongly flags safe Next.js **preview/prerelease** builds as vulnerable and blocks deployment with the `CVE-2025-55182` error.

Next.js now publishes builds under a `preview` tag (`next@preview`), which resolves to prerelease versions like `16.3.0-preview`. These should pass the safe-version check (since `16.3.0` ≥ `16.1.0`), but they are blocked.

Reference: https://nextjs.org/blog/next-16-3-instant-navigations

## Root cause

In `packages/@apphosting/adapter-nextjs/src/utils.ts`:

```ts
if (!satisfies(version, SAFE_NEXTJS_VERSIONS)) {
throw new Error(`CVE-2025-55182: Vulnerable Next version ${version} detected. ...`);
}
```

By default, semver's `satisfies()` **excludes prerelease versions** from matching a range unless the range already contains a prerelease comparator for the same `[major, minor, patch]` tuple. `SAFE_NEXTJS_VERSIONS` only has one prerelease comparator (`<14.3.0-canary.77`), so a build like `16.3.0-preview` does not satisfy `>=16.1.0` and is treated as vulnerable.

## Reproduction

With `semver@7.7.3` and the current range:

```js
const RANGE = ">=16.1.0 || ~16.0.7 || ~v15.5.7 || ~v15.4.8 || ~v15.3.6 || ~v15.2.6 || ~v15.1.9 || ~v15.0.5 || <14.3.0-canary.77";
semver.satisfies("16.3.0-preview", RANGE); // => false (wrongly blocked)
semver.satisfies("16.3.0-preview", RANGE, { includePrerelease: true }); // => true
```

In practice, deploying an app that depends on `next@preview` fails with:

```
CVE-2025-55182: Vulnerable Next version 16.3.0-preview detected. Deployment blocked. ...
```

## Expected behavior

Safe preview/prerelease builds (e.g. `16.3.0-preview`) should pass the check, while genuinely vulnerable versions — including the canary boundary (`14.3.0-canary.77+`, `15.0.0-canary.x`, `16.0.6`, `15.4.7`, etc.) — remain blocked.

## Suggested fix

Pass `{ includePrerelease: true }` to `satisfies`. Verified against `semver@7.7.3` that this only unblocks safe prereleases and leaves all existing canary/vulnerable-version checks unchanged.

| version | before | after | safe? |
|---|---|---|---|
| `16.3.0-preview` | ❌ blocked | ✅ allowed | safe |
| `14.3.0-canary.76` | ✅ allowed | ✅ allowed | safe |
| `14.3.0-canary.77` / `.78` | 🚫 blocked | 🚫 blocked | vulnerable |
| `15.0.0-canary.2` | 🚫 blocked | 🚫 blocked | vulnerable |
| `16.0.6` | 🚫 blocked | 🚫 blocked | vulnerable |

Fix submitted in #660.

Contributor guide

Open the contributing guide

Research direction

Start in packages/@apphosting/adapter-nextjs/src/utils.ts at the checkNextJSVersion semver.satisfies call and review the SAFE_NEXTJS_VERSIONS range. Verify the listed preview, canary, and vulnerable versions against the expected results; the issue notes that a fix was submitted in #660.

Written by the indexing model from the issue text.

Assessment

Tech stack
next.js, typescript
Domain
devops
Issue type
Bug
Difficulty
1/5
Estimated time
1-3 hours
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.