Skip to content

fix: NextJS security upgrade. - #951

Open
jonathanp-okta wants to merge 5 commits into
masterfrom
fix/next-security-upgrade
Open

fix: NextJS security upgrade.#951
jonathanp-okta wants to merge 5 commits into
masterfrom
fix/next-security-upgrade

Conversation

@jonathanp-okta

@jonathanp-okta jonathanp-okta commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

✏️ Changes

This upgrades next from 14.2.35 to 16.3.3 (with eslint-config-next and @next/mdx/@next/third-parties bumped in lockstep) to patch . The branch history shows the move was staged through 15.5.24 first (e3655c7) before continuing to 16.3.3 (48432f8, d9bccc9) — landing on the current major in one PR rather than opening a second migration shortly after. React stays on 18.3.1 throughout: 16.3.3 accepts ^18.2.0 || ^19.0.0 as a peer, so this is not a React 19 migration, and none of the direct dependencies (react-select, react-aria-components, react-markdown) pin react@^18 only — a future React 19 move stays unblocked.

Next 16 defaults to Turbopack, which broke @next/mdx: its loader registers as a plain top-level webpack rule with no App Router layer, so .mdx modules picked up node_modules' JSX runtime instead of Next's precompiled one and crashed in dev with ReactCurrentDispatcher of undefined. dev/build now pass --webpack explicitly, and next.config.mjs aliases react/jsx-runtime/react/jsx-dev-runtime to Next's compiled copies for the .mdx rule specifically (see the comment in next.config.mjs).

next lint was removed in Next 16.0, so lint now runs eslint . directly. Bumping eslint from ^8 to ^9 in the same PR meant ESLint's flat-config default would have silently ignored the legacy .eslintrc.jsoneslint.config.mjs replaces it as a direct re-export of eslint-config-next/core-web-vitals (confirmed to ship real flat-config arrays in v16, no FlatCompat shim needed), with two App Router-specific rule overrides carried over with their rationale in a comment. next-env.d.ts picked up a generated route-types reference (.next/dev/types/...) that Next writes on every dev/build and is committed so contributors don't get a dirty tree; tsconfig.json was updated to include that path and switched jsx to react-jsx / added target: ES2017 to match Next 16's expectations. next.config.mjs also sets agentRules: false so next dev stops writing AGENTS.md/CLAUDE.md into the tree.

Route/layout files were updated for Next 16's async params/searchParams/cookies()/headers() (all now return Promises) — PageProps/PageMetadataProps types, [language] layout and pages, not-found.tsx, and the language/theme cookie services. src/middleware.ts was renamed to src/proxy.ts (function renamed middlewareproxy) to match Next 16's rename of the convention. A handful of client components (footer, debugger-picker, mobile-header, the decoder/encoder input controls, card-toolbar-description-button) had useEffect-based "copy a prop/browser value into local state" patterns rewritten to sync during render instead (a new useClientValue hook covers the browser-only-value case); footer.component.tsx's react-select also gained an explicit instanceId so its generated DOM ids don't disagree between SSR and the client's first render.

preview.yaml, preview-community.yaml, and production.yaml also gained permissions: { contents: read, id-token: write } and two new steps before "Deploy on Vercel": a JFrog CLI setup that exchanges GitHub's OIDC token for short-lived Artifactory credentials (atko-cic provider), and a step that mints an .npmrc fragment into $RUNNER_TEMP from those credentials. The fragment is passed to vercel deploy as --build-env NPM_RC=..., which takes precedence over Vercel's project-level NPM_RC — the actual npm install for the deploy runs on Vercel's build machine, not the Actions runner, so that project-level value was the only credential in play and is what was producing npm error code E401. The credentials never touch the repo tree. The one substantive comment kept (# Artifactory credentials for the @a0 scope) is functional, not explanatory: Artifactory's response starts with @a0:registry=..., and the Vercel CLI reads a --build-env value starting with @ as a reference to a stored secret, so that line exists purely to keep the first character from being @.

Details worth a reviewer's attention:

  • React stays on 18.3.1. No dependency in this diff pins react@^18 only, so this doesn't block a later React 19 move.
  • --webpack is not cosmetic. Removing it would re-enable Turbopack and reintroduce the MDX JSX-runtime crash described above.
  • next-env.d.ts and the lockfile are committed on purpose — both are generated but need to be in the tree so CI and other contributors don't see a dirty diff after their first build.

🔮 Type of Change

Dependency/build-tooling patch plus the App Router API changes it forced. No product surface, no intentional runtime/behavior changes, no public API changes — the render-timing and react-select fixes are defensive corrections surfaced while QAing the upgrade, not new features.

  • Standard
  • Emergency
  • Significant

🔗 References

  • I added at least one link explaining why this change is needed.

📖 Documentation

No update needed — the only public-facing entry point (npm run lint) still means "lint the project"; its implementation changed but not its contract.

  • I reflected this change in the documentation, or explained why no update is needed.

🎯 Testing

  • npm run build (after rm -rf .next) — exit 0. ✓ Compiled successfully in 8.7s, ✓ Generating static pages using 9 workers (23/23) in 274ms, 23 App Router routes.
  • npm run lint (eslint .) — exit 0, zero findings.
  • npx vitest run — 11 files, 102 tests, all passing, 577ms.
  • npm run dev✓ Ready in 221ms; GET /200 (next.js: 7.4s, proxy.ts: 94ms, generate-params: 740ms, application-code: 347ms), no compile or console errors in the dev log.
  • npm auditnext no longer appears; 16 unrelated advisories remain (babel, vitest/vite, esbuild, nanoid, node-forge, svgo, yaml, etc.) and are out of scope here.

Gaps a reviewer should know about:

  • Playwright's browser suite (tests.yaml) was not re-run in this pass — CI will exercise it.

  • production.yaml only triggers on push to master/production (or schedule/workflow_dispatch), so its deploy path — including the new JFrog steps — is unverified by this PR directly; it runs for the first time on merge.

  • I could not find the advisory's patched-versions field in this repo/session — please confirm 16.3.3 is listed before merging.

  • I described how I tested these changes.

  • This change has test coverage, or I explained why it does not.

🚀 Deployment

Deployable at any time. 16.3.3 raises the Node floor to >=20.9.0 (up from 14.x's lower floor); tests.yaml/production.yaml already run Node 22, so this isn't a blocker, but it's worth confirming Vercel's project-level Node setting is ≥20.9 too — engines.node was deliberately left untouched (an open-ended range would let Vercel silently resolve to whatever the latest major is at deploy time). The atko-cic OIDC provider must already trust this repo, or the "Setup JFrog CLI" step fails outright — worth a quick check with JFrog admin access before merging if this hasn't been exercised yet.

  • This change can support multiple releases serving traffic at the same time.
  • This can be deployed at any time, or I listed the prerequisites.

🔥 Rollback

Revert this PR's commit(s) to return to next@14.2.35. Rollback restores a previously-working state (no new prod-only behavior was introduced ahead of this PR), so there's no residual-risk window — the deploy-workflow permissions/JFrog steps are additive and safe to leave in place even if the next bump itself were reverted.

  • I explained the rollback and recovery process.

@github-actions

Copy link
Copy Markdown

Preview URL https://next-jwt-ouc57bwdm-okta.vercel.app

@github-actions

Copy link
Copy Markdown

Preview URL https://next-jwt-ey912uwk2-okta.vercel.app

@github-actions

Copy link
Copy Markdown

Preview URL https://next-jwt-3u1zkjzwp-okta.vercel.app

@jonathanp-okta jonathanp-okta self-assigned this Aug 29, 2026
@jonathanp-okta jonathanp-okta added enhancement dependencies Pull requests that update a dependency file labels Aug 29, 2026
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown

Preview URL https://next-jwt-5utyyy7ri-okta.vercel.app

@jonathanp-okta
jonathanp-okta marked this pull request as ready for review September 1, 2026 06:20
Comment thread scripts/oidc-install.mjs
@@ -0,0 +1,104 @@
#!/usr/bin/env node

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why do we need this file? jwt doesn't use jfrog.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file enhancement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants