fix(pattern): address CVE-2025-69873 by implementing safeguards against ReDoS attacks in pattern validation#2585
Conversation
…st ReDoS attacks in pattern validation
It may a correct approach, as in this case we take part of schema from data, so technically it's data that is invalid. But I think application should still be catching exceptions rather than the validator, and some applications that differentiated these scenarios will start working differently. I think throwing exception and letting applications catch it is better - applications should be catching exceptions anyway, especially with dynamic schemas. @KsAkira10 what do you think? |
I focused only on mitigating the vulnerability, but I think the idea of leaving the exceptions for the application to handle is valid. But would that be a problem to deal with now? |
|
Not sure why, but 2 of added tests run for 54 seconds each for me, so it's not really solving the problem... What am I missing? Edit: was running the new tests with the old code, so it actually proved the fix works. |
|
merged #2586 with this commit. Thank you! |
|
@epoberezkin Thank you so much for addressing this! Do you have any plans to backport this fix to earlier versions of AJV? Specifically, we’re on "^6.12.3" and are trying to determine whether we should plan to upgrade to v8.18.0 or if a backport to v6.x.x is expected. |
What issue does this pull request resolve?
This PR resolves CVE-2025-69873: Regular Expression Denial of Service (ReDoS) vulnerability in ajv when the
$dataoption is enabled with thepatternkeyword.The vulnerability allows attackers to inject malicious regex patterns through
$datareferences that exhibit catastrophic backtracking behavior, causing complete denial of service. A single HTTP request with a payload like:{ "pattern": "^(a|a)*$", "value": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaX" }Can block the server for 44+ seconds, rendering the entire Node.js service unresponsive.
CVE Reference: https://www.cve.org/CVERecord?id=CVE-2025-69873
What changes did you make?
Core Fix -
lib/vocabularies/validation/pattern.tsAdded import:
useFuncfrom../../compile/utilto inject custom regex engines into generated codeSplit
$dataand static code paths:$datapath (previously vulnerable): Now uses the configuredopts.code.regExpengine instead of hardcodednew RegExp()usePattern()as beforeAdded try/catch protection:
.test()call ingen.try/catchGenerated Code Behavior
Before (vulnerable):
After (secure):
Test Coverage
spec/issues/cve_2025_69873_redos_attack.spec.ts(new)spec/extras/$data/pattern.json(updated)$dataTest Results: 7,610 tests passing, 0 failures
Is there anything that requires more attention while reviewing?
Key Points for Review
1. Behavioral Change
$datawould throw an unhandledSyntaxError, crashing the validatorfalse(validation failure)2. Custom Regex Engine Support
RegExpEngineimplementations (RE2, etc.) to$datapatterns$datapatterns always usednew RegExp$databehavior with the static pattern path3. Backwards Compatibility
$datapattern matching behavior is completely unchanged4. Performance Impact
$datapatterns (static path unchanged)$datapatterns: lightweight try/catch around regex execution5. Security Validation
^(a+)+$^(a|a)*$^(a|ab)*$(x+x+)+y(a*)*bImplementation Notes
usePattern()(lib/vocabularies/code.ts:93-105) for handling custom regex enginesuseFunc()to properly inject engine references into generated coderequirestatement for custom enginesSummary
This is a targeted security fix that resolves CVE-2025-69873 by:
$datapatternsThe vulnerability is structurally eliminated when using RE2, making ReDoS attacks impossible.