Input validation
Description
The commit fixes an input validation bug in cacheHandlers keys. Previously the validation used /[a-z-]/ which only required at least one lowercase letter or hyphen anywhere in the key, so keys containing digits, underscores, dots, or other characters could slip through (e.g., 'abc123', 'abc_def', 'handler!'). The patch anchors the regex with /^[a-z-]+$/, ensuring the entire key consists only of lowercase letters and hyphens. This reduces misconfiguration risk and potential edge-case behavior stemming from malformed handler names.
Commit Details
Author: Partha Shankar
Date: 2026-07-02 16:12 UTC
Message:
fix(config): correctly validate cacheHandlers names (#95358)
## What?
The current `cacheHandlers` validation uses `/[a-z-]/`, which only
checks whether a key contains at least one lowercase letter or hyphen.
As a result, invalid keys such as `abc123`, `abc_123`, `abc.def`, and
`handler!` are accepted even though they contain characters outside the
documented allowed set.
## Why?
The validation error states that handler names must only contain `a-z`
and `-`, but the current implementation does not enforce that constraint
because the regex is not anchored.
## How?
- Replace `/[a-z-]/` with `/^[a-z-]+$/` so the entire handler name is
validated.
- Add regression tests covering both valid and invalid handler names.
## Testing
- Added regression tests in `packages/next/src/server/config.test.ts`.
<!-- NEXT_JS_LLM_PR -->
Triage Assessment
Vulnerability Type: Input validation
Confidence: MEDIUM
Reasoning:
The commit fixes an input validation issue by anchoring the regex for cacheHandlers keys, preventing invalid names that could enable misconfiguration or edge-case behavior. While not a classic exploit like XSS/SQLi, it tightens security-relevant config validation and reduces risk of improper handler naming.
Verification Assessment
Vulnerability Type: Input validation
Confidence: MEDIUM
Affected Versions: 16.2.x before the fix (e.g., 16.2.2 and earlier in the 16.2 line)
Code Diff
diff --git a/packages/next/src/server/config.test.ts b/packages/next/src/server/config.test.ts
index 6ba5362ceb5..75d6905e51e 100644
--- a/packages/next/src/server/config.test.ts
+++ b/packages/next/src/server/config.test.ts
@@ -192,4 +192,45 @@ describe('loadConfig', () => {
expect(result.experimental.externalProxyRewritesResolve).toBe(true)
})
})
+
+ describe('cacheHandlers validation', () => {
+ it('should reject invalid keys', async () => {
+ const invalidKeys = [
+ 'abc123',
+ 'abc_123',
+ 'abc.def',
+ 'handler!',
+ '123handler',
+ 'handler123',
+ ]
+
+ for (const key of invalidKeys) {
+ await expect(
+ loadConfig(PHASE_PRODUCTION_BUILD, __dirname, {
+ customConfig: {
+ cacheHandlers: {
+ [key]: __filename,
+ },
+ },
+ })
+ ).rejects.toThrow(/key must only use characters a-z and -/)
+ }
+ })
+
+ it('should accept valid keys', async () => {
+ const result = await loadConfig(PHASE_PRODUCTION_BUILD, __dirname, {
+ customConfig: {
+ cacheHandlers: {
+ abc: __filename,
+ 'valid-handler': __filename,
+ 'abc-def': __filename,
+ },
+ },
+ })
+ expect(result.cacheHandlers).toBeDefined()
+ expect(result.cacheHandlers?.['abc']).toBeDefined()
+ expect(result.cacheHandlers?.['valid-handler']).toBeDefined()
+ expect(result.cacheHandlers?.['abc-def']).toBeDefined()
+ })
+ })
})
diff --git a/packages/next/src/server/config.ts b/packages/next/src/server/config.ts
index 5a775c35480..559fb502c42 100644
--- a/packages/next/src/server/config.ts
+++ b/packages/next/src/server/config.ts
@@ -1408,7 +1408,7 @@ function assignDefaultsAndValidate(
}
if (result.cacheHandlers) {
- const allowedHandlerNameRegex = /[a-z-]/
+ const allowedHandlerNameRegex = /^[a-z-]+$/
if (typeof result.cacheHandlers !== 'object') {
throw new Error(