Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions packages/@apphosting/adapter-nextjs/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@apphosting/adapter-nextjs",
"version": "14.0.20",
"version": "14.0.19",
"main": "dist/index.js",
"description": "Experimental addon to the Firebase CLI to add web framework support",
"repository": {
Expand Down Expand Up @@ -61,7 +61,7 @@
"@types/tmp": "*",
"mocha": "*",
"next": "~14.0.0",
"semver": "*",
"semver": "^7.7.3",
"tmp": "*",
"ts-mocha": "*",
"ts-node": "*",
Expand Down
2 changes: 2 additions & 0 deletions packages/@apphosting/adapter-nextjs/src/bin/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
validateOutputDirectory,
getAdapterMetadata,
exists,
checkNextJSVersion,
} from "../utils.js";
import { join } from "path";
import { getBuildOptions, runBuild } from "@apphosting/common";
Expand All @@ -24,6 +25,7 @@ process.env.NEXT_PRIVATE_STANDALONE = "true";
// Opt-out sending telemetry to Vercel
process.env.NEXT_TELEMETRY_DISABLED = "1";

checkNextJSVersion(process.env.FRAMEWORK_VERSION);
const nextConfig = await loadConfig(root, opts.projectDirectory);

/**
Expand Down
54 changes: 54 additions & 0 deletions packages/@apphosting/adapter-nextjs/src/utils.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,60 @@ import path from "path";
import os from "os";
import { RoutesManifest, MiddlewareManifest } from "../src/interfaces.js";

describe("block vulnerable nextjs versions", () => {
it("check for vulnerable versions", async () => {
const { checkNextJSVersion } = await importUtils;

assert.throws(() => {
checkNextJSVersion("15.0.0");
});

assert.doesNotThrow(() => {
checkNextJSVersion(undefined);
});

assert.doesNotThrow(() => {
checkNextJSVersion("15.0.5");
});

assert.throws(() => {
checkNextJSVersion("15.4.7");
});

assert.doesNotThrow(() => {
checkNextJSVersion("15.4.8");
});

assert.doesNotThrow(() => {
checkNextJSVersion("14.0.12");
});

assert.throws(() => {
checkNextJSVersion("14.3.0-canary.77");
});

assert.throws(() => {
checkNextJSVersion("14.3.0-canary.78");
});

assert.doesNotThrow(() => {
checkNextJSVersion("14.3.0-canary.76");
});

assert.throws(() => {
checkNextJSVersion("15.0.0-canary.2");
});

assert.throws(() => {
checkNextJSVersion("16.0.6");
});

assert.doesNotThrow(() => {
checkNextJSVersion("16.0.7");
});
});
});

describe("manifest utils", () => {
let tmpDir: string;
let distDir: string;
Expand Down
16 changes: 16 additions & 0 deletions packages/@apphosting/adapter-nextjs/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import fsExtra from "fs-extra";
import semVer from "semver";
import { createRequire } from "node:module";
import { join, dirname, relative, normalize } from "path";
import { fileURLToPath } from "url";
Expand All @@ -17,6 +18,21 @@ import { OutputBundleConfig, updateOrCreateGitignore } from "@apphosting/common"
// fs-extra is CJS, readJson can't be imported using shorthand
export const { copy, exists, writeFile, readJson, readdir, readFileSync, existsSync, ensureDir } =
fsExtra;
export const { satisfies } = semVer;

const SAFE_NEXTJS_VERSIONS =
">=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";
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit, <14.3.0-canary.77 will match all the 14.3.0 range due to limitations matching canary with semver. That's fine. Safer.


export function checkNextJSVersion(version: string | undefined) {
if (!version) {
return;
}
if (!satisfies(version, SAFE_NEXTJS_VERSIONS)) {
throw new Error(
`CVE-2025-55182: Vulnerable Next version ${version} detected. Deployment blocked. Update your app's dependencies to a patched Next.js version and redeploy: https://nextjs.org/blog/CVE-2025-66478#fixed-versions`,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The error message contains placeholder CVE numbers and a broken link. This will be confusing for users who encounter this error. Please replace CVE-2025-55182 and CVE-2025-66478 with the actual CVE identifier for the vulnerability being addressed. The URL https://nextjs.org/blog/CVE-2025-66478#fixed-versions is also incorrect and should be updated to point to the official security advisory.

If a specific CVE is not yet available, I suggest using a more generic but still helpful message.

Suggested change
`CVE-2025-55182: Vulnerable Next version ${version} detected. Deployment blocked. Update your app's dependencies to a patched Next.js version and redeploy: https://nextjs.org/blog/CVE-2025-66478#fixed-versions`,
`Vulnerable Next.js version ${version} detected. Deployment blocked due to a security vulnerability. Please update your app's dependencies to a patched Next.js version and redeploy. For more information, see the Next.js security advisories.`

);
}
}

// Loads the user's next.config.js file.
export async function loadConfig(root: string, projectRoot: string): Promise<NextConfigComplete> {
Expand Down