CVE-2026-117680 (GCVE-0-2026-117680)

Vulnerability from cvelistv5 – Published: 2026-11-01 13:29 – Updated: 2026-11-02 19:44
VLAI
Title
jsv treats regex match budget exhaustion as a non-match, bypassing patternProperties and not
Summary
Improper Check for Unusual or Exceptional Conditions vulnerability in the pattern and patternProperties keywords in lud jsv allows an unauthenticated remote attacker to bypass schema validation via a string that matches a schema regex only after heavy backtracking. JSV.Helpers.RegexExt.bounded_match?/2 runs schema regexes with a backtracking budget but calls :re.run/3 without :report_errors, so a match that exhausts the budget returns the same :nomatch as a real non-match. A key that matches a patternProperties regex is then checked against additionalProperties or not at all, and a string that matches a not subschema with a pattern is accepted. Before the budget existed, Regex.match?/2 failed the same way at Erlang's default match limit. Only schemas whose regex explores a catastrophic branch before the branch that matches are affected. The attacker controls the data, not the schema, and linear patterns never exhaust the budget. This issue affects jsv: from 0.1.0 before 0.26.2.
SSVC
Exploitation: poc Automatable: no Technical Impact: partial
CISA Coordinator · CISA-ADP (v2.0.3)
Decision recorded 2026-11-02 19:43 UTC
CWE
  • CWE-754 - Improper Check for Unusual or Exceptional Conditions
Assigner
EEF CNA under the mitre root
CNA scorecard A 97/100 over 350 records in the last 180 days details
Impacted products
Vendor Product Version CPE status
lud jsv Affected: 0.1.0 , < 0.26.2 (semver)
    cpe:2.3:a:lud:jsv:*:*:*:*:*:*:*:*
Create a notification for this product.
lud jsv Affected: 302a5d0803468f81a1cf08e3b67d8b14cee759ca , < defdb8a68ac7f218aa5dfe85190d484017cb8817 (git)
    cpe:2.3:a:lud:jsv:*:*:*:*:*:*:*:*
Create a notification for this product.
Show details on NVD website

{
  "containers": {
    "adp": [
      {
        "metrics": [
          {
            "other": {
              "content": {
                "id": "CVE-2026-117680",
                "options": [
                  {
                    "Exploitation": "poc"
                  },
                  {
                    "Automatable": "no"
                  },
                  {
                    "Technical Impact": "partial"
                  }
                ],
                "role": "CISA Coordinator",
                "timestamp": "2026-11-02T19:43:40.753996Z",
                "version": "2.0.3"
              },
              "type": "ssvc"
            }
          }
        ],
        "providerMetadata": {
          "dateUpdated": "2026-11-02T19:44:02.251Z",
          "orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
          "shortName": "CISA-ADP"
        },
        "references": [
          {
            "tags": [
              "exploit"
            ],
            "url": "https://github.com/lud/jsv/security/advisories/GHSA-cvmg-hgv6-jqcp"
          }
        ],
        "title": "CISA ADP Vulnrichment"
      }
    ],
    "cna": {
      "affected": [
        {
          "collectionURL": "https://repo.hex.pm",
          "cpes": [
            "cpe:2.3:a:lud:jsv:*:*:*:*:*:*:*:*"
          ],
          "defaultStatus": "unaffected",
          "modules": [
            "\u0027Elixir.JSV.Helpers.RegexExt\u0027",
            "\u0027Elixir.JSV.Vocabulary.V202012.Validation\u0027",
            "\u0027Elixir.JSV.Vocabulary.V202012.Applicator\u0027",
            "\u0027Elixir.JSV\u0027"
          ],
          "packageName": "jsv",
          "packageURL": "pkg:hex/jsv",
          "product": "jsv",
          "programFiles": [
            "lib/jsv/helpers/regex_ext.ex",
            "lib/jsv/vocabulary/v202012/validation.ex",
            "lib/jsv/vocabulary/v202012/applicator.ex",
            "lib/jsv.ex"
          ],
          "programRoutines": [
            {
              "name": "\u0027Elixir.JSV.Helpers.RegexExt\u0027:\u0027bounded_match?\u0027/2"
            },
            {
              "name": "\u0027Elixir.JSV.Vocabulary.V202012.Validation\u0027:validate_keyword/3"
            },
            {
              "name": "\u0027Elixir.JSV.Vocabulary.V202012.Applicator\u0027:validate_keyword/3"
            },
            {
              "name": "\u0027Elixir.JSV\u0027:validate/2"
            },
            {
              "name": "\u0027Elixir.JSV\u0027:validate/3"
            }
          ],
          "repo": "https://github.com/lud/jsv",
          "vendor": "lud",
          "versions": [
            {
              "lessThan": "0.26.2",
              "status": "affected",
              "version": "0.1.0",
              "versionType": "semver"
            }
          ]
        },
        {
          "collectionURL": "https://github.com",
          "cpes": [
            "cpe:2.3:a:lud:jsv:*:*:*:*:*:*:*:*"
          ],
          "defaultStatus": "unaffected",
          "modules": [
            "\u0027Elixir.JSV.Helpers.RegexExt\u0027",
            "\u0027Elixir.JSV.Vocabulary.V202012.Validation\u0027",
            "\u0027Elixir.JSV.Vocabulary.V202012.Applicator\u0027",
            "\u0027Elixir.JSV\u0027"
          ],
          "packageName": "lud/jsv",
          "packageURL": "pkg:github/lud/jsv",
          "product": "jsv",
          "programFiles": [
            "lib/jsv/helpers/regex_ext.ex",
            "lib/jsv/vocabulary/v202012/validation.ex",
            "lib/jsv/vocabulary/v202012/applicator.ex",
            "lib/jsv.ex"
          ],
          "programRoutines": [
            {
              "name": "\u0027Elixir.JSV.Helpers.RegexExt\u0027:\u0027bounded_match?\u0027/2"
            },
            {
              "name": "\u0027Elixir.JSV.Vocabulary.V202012.Validation\u0027:validate_keyword/3"
            },
            {
              "name": "\u0027Elixir.JSV.Vocabulary.V202012.Applicator\u0027:validate_keyword/3"
            },
            {
              "name": "\u0027Elixir.JSV\u0027:validate/2"
            },
            {
              "name": "\u0027Elixir.JSV\u0027:validate/3"
            }
          ],
          "repo": "https://github.com/lud/jsv",
          "vendor": "lud",
          "versions": [
            {
              "lessThan": "defdb8a68ac7f218aa5dfe85190d484017cb8817",
              "status": "affected",
              "version": "302a5d0803468f81a1cf08e3b67d8b14cee759ca",
              "versionType": "git"
            }
          ]
        }
      ],
      "configurations": [
        {
          "lang": "en",
          "supportingMedia": [
            {
              "base64": false,
              "type": "text/html",
              "value": "\u003cp\u003eThe schema must contain a \u003ccode\u003epattern\u003c/code\u003e or \u003ccode\u003epatternProperties\u003c/code\u003e regex that PCRE can match only after exploring a catastrophic branch first, such as a nested quantifier in an earlier alternative. Linear patterns never exhaust the budget. The attacker controls the validated data but not the schema.\u003c/p\u003e"
            },
            {
              "base64": false,
              "type": "text/markdown",
              "value": "The schema must contain a `pattern` or `patternProperties` regex that PCRE can match only after exploring a catastrophic branch first, such as a nested quantifier in an earlier alternative. Linear patterns never exhaust the budget. The attacker controls the validated data but not the schema."
            }
          ],
          "value": "The schema must contain a pattern or patternProperties regex that PCRE can match only after exploring a catastrophic branch first, such as a nested quantifier in an earlier alternative. Linear patterns never exhaust the budget. The attacker controls the validated data but not the schema."
        }
      ],
      "cpeApplicability": [
        {
          "nodes": [
            {
              "cpeMatch": [
                {
                  "criteria": "cpe:2.3:a:lud:jsv:*:*:*:*:*:*:*:*",
                  "versionEndExcluding": "0.26.2",
                  "versionStartIncluding": "0.1.0",
                  "vulnerable": true
                }
              ],
              "negate": false,
              "operator": "OR"
            }
          ],
          "operator": "AND"
        }
      ],
      "credits": [
        {
          "lang": "en",
          "type": "finder",
          "value": "Lars Hesel Christensen"
        },
        {
          "lang": "en",
          "type": "reporter",
          "value": "Lars Hesel Christensen"
        },
        {
          "lang": "en",
          "type": "remediation developer",
          "value": "Ludovic Dem"
        },
        {
          "lang": "en",
          "type": "coordinator",
          "value": "Jonatan M\u00e4nnchen / EEF"
        }
      ],
      "dateAssigned": "2026-10-30T23:20:38.000Z",
      "descriptions": [
        {
          "lang": "en",
          "supportingMedia": [
            {
              "base64": false,
              "type": "text/html",
              "value": "\u003cp\u003eImproper Check for Unusual or Exceptional Conditions vulnerability in the \u003ccode\u003epattern\u003c/code\u003e and \u003ccode\u003epatternProperties\u003c/code\u003e keywords in lud jsv allows an unauthenticated remote attacker to bypass schema validation via a string that matches a schema regex only after heavy backtracking. \u003ccode\u003eJSV.Helpers.RegexExt.bounded_match?/2\u003c/code\u003e runs schema regexes with a backtracking budget but calls \u003ccode\u003e:re.run/3\u003c/code\u003e without \u003ccode\u003e:report_errors\u003c/code\u003e, so a match that exhausts the budget returns the same \u003ccode\u003e:nomatch\u003c/code\u003e as a real non-match. A key that matches a \u003ccode\u003epatternProperties\u003c/code\u003e regex is then checked against \u003ccode\u003eadditionalProperties\u003c/code\u003e or not at all, and a string that matches a \u003ccode\u003enot\u003c/code\u003e subschema with a \u003ccode\u003epattern\u003c/code\u003e is accepted. Before the budget existed, \u003ccode\u003eRegex.match?/2\u003c/code\u003e failed the same way at Erlang\u0027s default match limit.\u003c/p\u003e\n\u003cp\u003eOnly schemas whose regex explores a catastrophic branch before the branch that matches are affected. The attacker controls the data, not the schema, and linear patterns never exhaust the budget.\u003c/p\u003e\n\u003cp\u003eThis issue affects jsv: from 0.1.0 before 0.26.2.\u003c/p\u003e"
            },
            {
              "base64": false,
              "type": "text/markdown",
              "value": "Improper Check for Unusual or Exceptional Conditions vulnerability in the `pattern` and `patternProperties` keywords in lud jsv allows an unauthenticated remote attacker to bypass schema validation via a string that matches a schema regex only after heavy backtracking. `JSV.Helpers.RegexExt.bounded_match?/2` runs schema regexes with a backtracking budget but calls `:re.run/3` without `:report_errors`, so a match that exhausts the budget returns the same `:nomatch` as a real non-match. A key that matches a `patternProperties` regex is then checked against `additionalProperties` or not at all, and a string that matches a `not` subschema with a `pattern` is accepted. Before the budget existed, `Regex.match?/2` failed the same way at Erlang\u0027s default match limit.\n\nOnly schemas whose regex explores a catastrophic branch before the branch that matches are affected. The attacker controls the data, not the schema, and linear patterns never exhaust the budget.\n\nThis issue affects jsv: from 0.1.0 before 0.26.2."
            }
          ],
          "value": "Improper Check for Unusual or Exceptional Conditions vulnerability in the pattern and patternProperties keywords in lud jsv allows an unauthenticated remote attacker to bypass schema validation via a string that matches a schema regex only after heavy backtracking. JSV.Helpers.RegexExt.bounded_match?/2 runs schema regexes with a backtracking budget but calls :re.run/3 without :report_errors, so a match that exhausts the budget returns the same :nomatch as a real non-match. A key that matches a patternProperties regex is then checked against additionalProperties or not at all, and a string that matches a not subschema with a pattern is accepted. Before the budget existed, Regex.match?/2 failed the same way at Erlang\u0027s default match limit.\n\nOnly schemas whose regex explores a catastrophic branch before the branch that matches are affected. The attacker controls the data, not the schema, and linear patterns never exhaust the budget.\n\nThis issue affects jsv: from 0.1.0 before 0.26.2."
        }
      ],
      "impacts": [
        {
          "capecId": "CAPEC-153",
          "descriptions": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eAn attacker pads a string until its match exhausts the budget, so a value under a \u003ccode\u003epatternProperties\u003c/code\u003e key skips its subschema or a string passes a \u003ccode\u003enot\u003c/code\u003e deny-list. The application then accepts input its schema should reject.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "An attacker pads a string until its match exhausts the budget, so a value under a `patternProperties` key skips its subschema or a string passes a `not` deny-list. The application then accepts input its schema should reject."
                }
              ],
              "value": "An attacker pads a string until its match exhausts the budget, so a value under a patternProperties key skips its subschema or a string passes a not deny-list. The application then accepts input its schema should reject."
            }
          ]
        }
      ],
      "metrics": [
        {
          "cvssV4_0": {
            "Automatable": "NOT_DEFINED",
            "Recovery": "NOT_DEFINED",
            "Safety": "NOT_DEFINED",
            "attackComplexity": "LOW",
            "attackRequirements": "PRESENT",
            "attackVector": "LOCAL",
            "baseScore": 2.1,
            "baseSeverity": "LOW",
            "privilegesRequired": "NONE",
            "providerUrgency": "NOT_DEFINED",
            "subAvailabilityImpact": "NONE",
            "subConfidentialityImpact": "NONE",
            "subIntegrityImpact": "NONE",
            "userInteraction": "NONE",
            "valueDensity": "NOT_DEFINED",
            "vectorString": "CVSS:4.0/AV:L/AC:L/AT:P/PR:N/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N",
            "version": "4.0",
            "vulnAvailabilityImpact": "NONE",
            "vulnConfidentialityImpact": "NONE",
            "vulnIntegrityImpact": "LOW",
            "vulnerabilityResponseEffort": "NOT_DEFINED"
          },
          "format": "CVSS",
          "scenarios": [
            {
              "lang": "en",
              "value": "GENERAL"
            }
          ]
        }
      ],
      "problemTypes": [
        {
          "descriptions": [
            {
              "cweId": "CWE-754",
              "description": "CWE-754 Improper Check for Unusual or Exceptional Conditions",
              "lang": "en",
              "type": "CWE"
            }
          ]
        }
      ],
      "providerMetadata": {
        "dateUpdated": "2026-11-01T13:29:36.681Z",
        "orgId": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
        "shortName": "EEF"
      },
      "references": [
        {
          "name": "Regex match budget exhaustion is treated as a non-match, bypassing `patternProperties` and `not`",
          "tags": [
            "vendor-advisory",
            "related"
          ],
          "url": "https://github.com/lud/jsv/security/advisories/GHSA-cvmg-hgv6-jqcp"
        },
        {
          "name": "EEF CNA record for CVE-2026-117680",
          "tags": [
            "related"
          ],
          "url": "https://cna.erlef.org/cves/CVE-2026-117680.html"
        },
        {
          "name": "OSV record EEF-CVE-2026-117680",
          "tags": [
            "related"
          ],
          "url": "https://osv.dev/vulnerability/EEF-CVE-2026-117680"
        },
        {
          "name": "Introducing commit 302a5d0 in lud/jsv",
          "tags": [
            "related"
          ],
          "url": "https://github.com/lud/jsv/commit/302a5d0803468f81a1cf08e3b67d8b14cee759ca"
        },
        {
          "name": "Fix commit defdb8a in lud/jsv",
          "tags": [
            "patch"
          ],
          "url": "https://github.com/lud/jsv/commit/defdb8a68ac7f218aa5dfe85190d484017cb8817"
        }
      ],
      "source": {
        "discovery": "EXTERNAL"
      },
      "title": "jsv treats regex match budget exhaustion as a non-match, bypassing patternProperties and not",
      "workarounds": [
        {
          "lang": "en",
          "supportingMedia": [
            {
              "base64": false,
              "type": "text/html",
              "value": "\u003cp\u003ePair \u003ccode\u003epatternProperties\u003c/code\u003e with \u003ccode\u003eadditionalProperties: false\u003c/code\u003e. A key whose match exhausts the budget is then rejected instead of accepted unchecked. Valid keys that need heavy backtracking are rejected as well.\u003c/p\u003e\n\u003cp\u003eWrite schema regexes without nested quantifiers or overlapping alternatives, and do not express deny-lists as a \u003ccode\u003enot\u003c/code\u003e subschema with a \u003ccode\u003epattern\u003c/code\u003e on untrusted input.\u003c/p\u003e"
            },
            {
              "base64": false,
              "type": "text/markdown",
              "value": "Pair `patternProperties` with `additionalProperties: false`. A key whose match exhausts the budget is then rejected instead of accepted unchecked. Valid keys that need heavy backtracking are rejected as well.\n\nWrite schema regexes without nested quantifiers or overlapping alternatives, and do not express deny-lists as a `not` subschema with a `pattern` on untrusted input."
            }
          ],
          "value": "Pair patternProperties with additionalProperties: false. A key whose match exhausts the budget is then rejected instead of accepted unchecked. Valid keys that need heavy backtracking are rejected as well.\n\nWrite schema regexes without nested quantifiers or overlapping alternatives, and do not express deny-lists as a not subschema with a pattern on untrusted input."
        }
      ],
      "x_proofOfConcept": [
        {
          "lang": "en",
          "supportingMedia": [
            {
              "base64": false,
              "type": "text/html",
              "value": "\u003col\u003e\n\u003cli\u003eBuild a schema with \u003ccode\u003epatternProperties\u003c/code\u003e mapping the regex \u003ccode\u003e^(?:(a+)+b|a+!)$\u003c/code\u003e to \u003ccode\u003e{\"type\": \"integer\"}\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eSubmit an object whose only key is twenty \u003ccode\u003ea\u003c/code\u003e characters followed by \u003ccode\u003e!\u003c/code\u003e and whose value is the string \u003ccode\u003enot an int\u003c/code\u003e. The key matches the regex through its second alternative, but PCRE exhausts the 11,050-step budget in the first alternative.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eJSV.validate/2\u003c/code\u003e returns \u003ccode\u003e:ok\u003c/code\u003e. The value is never checked against the subschema.\u003c/li\u003e\n\u003cli\u003eBuild a second schema \u003ccode\u003e{\"not\": {\"pattern\": \"^(?:(a+)+b|a+!)$\"}}\u003c/code\u003e and submit the same string. \u003ccode\u003eJSV.validate/2\u003c/code\u003e returns \u003ccode\u003e:ok\u003c/code\u003e although the string matches the denied pattern.\u003c/li\u003e\n\u003cli\u003eRepeat with the short key \u003ccode\u003eaaa!\u003c/code\u003e. Both schemas now reject the data as expected.\u003c/li\u003e\n\u003c/ol\u003e"
            },
            {
              "base64": false,
              "type": "text/markdown",
              "value": "1. Build a schema with `patternProperties` mapping the regex `^(?:(a+)+b|a+!)$` to `{\"type\": \"integer\"}`.\n2. Submit an object whose only key is twenty `a` characters followed by `!` and whose value is the string `not an int`. The key matches the regex through its second alternative, but PCRE exhausts the 11,050-step budget in the first alternative.\n3. `JSV.validate/2` returns `:ok`. The value is never checked against the subschema.\n4. Build a second schema `{\"not\": {\"pattern\": \"^(?:(a+)+b|a+!)$\"}}` and submit the same string. `JSV.validate/2` returns `:ok` although the string matches the denied pattern.\n5. Repeat with the short key `aaa!`. Both schemas now reject the data as expected."
            }
          ],
          "value": "* Build a schema with patternProperties mapping the regex ^(?:(a+)+b|a+!)$ to {\"type\": \"integer\"}.\n* Submit an object whose only key is twenty a characters followed by ! and whose value is the string not an int. The key matches the regex through its second alternative, but PCRE exhausts the 11,050-step budget in the first alternative.\n* JSV.validate/2 returns :ok. The value is never checked against the subschema.\n* Build a second schema {\"not\": {\"pattern\": \"^(?:(a+)+b|a+!)$\"}} and submit the same string. JSV.validate/2 returns :ok although the string matches the denied pattern.\n* Repeat with the short key aaa!. Both schemas now reject the data as expected."
        }
      ],
      "x_technicalAnalysis": [
        {
          "lang": "en",
          "supportingMedia": [
            {
              "base64": false,
              "type": "text/html",
              "value": "\u003cp\u003e\u003cstrong\u003e1. Bounded matching.\u003c/strong\u003e \u003ccode\u003eJSV.Helpers.RegexExt.bounded_match?/2\u003c/code\u003e in \u003ccode\u003elib/jsv/helpers/regex_ext.ex\u003c/code\u003e runs each schema regex through \u003ccode\u003e:re.run/3\u003c/code\u003e with \u003ccode\u003ematch_limit\u003c/code\u003e and \u003ccode\u003ematch_limit_recursion\u003c/code\u003e set to \u003ccode\u003e10_000 + 50 * byte_size(subject)\u003c/code\u003e, capped at 10,000,000. The call omits \u003ccode\u003e:report_errors\u003c/code\u003e, so PCRE\u0027s \u003ccode\u003ematch_limit\u003c/code\u003e error is returned as \u003ccode\u003e:nomatch\u003c/code\u003e. The function compares the result to \u003ccode\u003e:match\u003c/code\u003e and returns \u003ccode\u003efalse\u003c/code\u003e for a genuine non-match and for an exhausted budget alike.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e2. Keyword evaluation.\u003c/strong\u003e \u003ccode\u003eJSV.Vocabulary.V202012.Validation.validate_keyword/3\u003c/code\u003e uses the result for \u003ccode\u003epattern\u003c/code\u003e, and \u003ccode\u003eJSV.Vocabulary.V202012.Applicator\u003c/code\u003e uses it to decide which \u003ccode\u003epatternProperties\u003c/code\u003e subschemas apply to each key. The draft 7 vocabulary delegates to the same modules. A \u003ccode\u003efalse\u003c/code\u003e from an exhausted budget therefore means a \u003ccode\u003epattern\u003c/code\u003e keyword fails and a \u003ccode\u003epatternProperties\u003c/code\u003e subschema is skipped.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e3. Inversion by combinators.\u003c/strong\u003e Under \u003ccode\u003enot\u003c/code\u003e, \u003ccode\u003eanyOf\u003c/code\u003e, \u003ccode\u003eoneOf\u003c/code\u003e, \u003ccode\u003eif\u003c/code\u003e and \u003ccode\u003econtains\u003c/code\u003e, a failing subschema can make the parent succeed, so a false non-match under \u003ccode\u003enot\u003c/code\u003e accepts a string the deny-list should reject. Under \u003ccode\u003epatternProperties\u003c/code\u003e the skipped subschema means the value is checked against \u003ccode\u003eadditionalProperties\u003c/code\u003e or nothing.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e4. History.\u003c/strong\u003e Before the budget was introduced, the same keywords called \u003ccode\u003eRegex.match?/2\u003c/code\u003e, which also returns \u003ccode\u003efalse\u003c/code\u003e on Erlang\u0027s default limit of 10,000,000 steps. The budget lowered the input size needed from about 25 bytes to about 20 bytes for the advisory\u0027s pattern.\u003c/p\u003e"
            },
            {
              "base64": false,
              "type": "text/markdown",
              "value": "**1. Bounded matching.** `JSV.Helpers.RegexExt.bounded_match?/2` in `lib/jsv/helpers/regex_ext.ex` runs each schema regex through `:re.run/3` with `match_limit` and `match_limit_recursion` set to `10_000 + 50 * byte_size(subject)`, capped at 10,000,000. The call omits `:report_errors`, so PCRE\u0027s `match_limit` error is returned as `:nomatch`. The function compares the result to `:match` and returns `false` for a genuine non-match and for an exhausted budget alike.\n\n**2. Keyword evaluation.** `JSV.Vocabulary.V202012.Validation.validate_keyword/3` uses the result for `pattern`, and `JSV.Vocabulary.V202012.Applicator` uses it to decide which `patternProperties` subschemas apply to each key. The draft 7 vocabulary delegates to the same modules. A `false` from an exhausted budget therefore means a `pattern` keyword fails and a `patternProperties` subschema is skipped.\n\n**3. Inversion by combinators.** Under `not`, `anyOf`, `oneOf`, `if` and `contains`, a failing subschema can make the parent succeed, so a false non-match under `not` accepts a string the deny-list should reject. Under `patternProperties` the skipped subschema means the value is checked against `additionalProperties` or nothing.\n\n**4. History.** Before the budget was introduced, the same keywords called `Regex.match?/2`, which also returns `false` on Erlang\u0027s default limit of 10,000,000 steps. The budget lowered the input size needed from about 25 bytes to about 20 bytes for the advisory\u0027s pattern."
            }
          ],
          "value": "1. Bounded matching. JSV.Helpers.RegexExt.bounded_match?/2 in lib/jsv/helpers/regex_ext.ex runs each schema regex through :re.run/3 with match_limit and match_limit_recursion set to 10_000 + 50 * byte_size(subject), capped at 10,000,000. The call omits :report_errors, so PCRE\u0027s match_limit error is returned as :nomatch. The function compares the result to :match and returns false for a genuine non-match and for an exhausted budget alike.\n\n2. Keyword evaluation. JSV.Vocabulary.V202012.Validation.validate_keyword/3 uses the result for pattern, and JSV.Vocabulary.V202012.Applicator uses it to decide which patternProperties subschemas apply to each key. The draft 7 vocabulary delegates to the same modules. A false from an exhausted budget therefore means a pattern keyword fails and a patternProperties subschema is skipped.\n\n3. Inversion by combinators. Under not, anyOf, oneOf, if and contains, a failing subschema can make the parent succeed, so a false non-match under not accepts a string the deny-list should reject. Under patternProperties the skipped subschema means the value is checked against additionalProperties or nothing.\n\n4. History. Before the budget was introduced, the same keywords called Regex.match?/2, which also returns false on Erlang\u0027s default limit of 10,000,000 steps. The budget lowered the input size needed from about 25 bytes to about 20 bytes for the advisory\u0027s pattern."
        }
      ]
    }
  },
  "cveMetadata": {
    "assignerOrgId": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
    "assignerShortName": "EEF",
    "cveId": "CVE-2026-117680",
    "datePublished": "2026-11-01T13:29:36.681Z",
    "dateReserved": "2026-10-30T12:45:01.930Z",
    "dateUpdated": "2026-11-02T19:44:02.251Z",
    "state": "PUBLISHED"
  },
  "dataType": "CVE_RECORD",
  "dataVersion": "5.2",
  "vulnerability-lookup:meta": {
    "epss": {
      "cve": "CVE-2026-117680",
      "date": "2026-11-08",
      "epss": "0.00191",
      "percentile": "0.08824"
    },
    "nvd": {
      "cve": {
        "affected": [
          {
            "affectedData": [
              {
                "collectionURL": "https://repo.hex.pm",
                "cpes": [
                  "cpe:2.3:a:lud:jsv:*:*:*:*:*:*:*:*"
                ],
                "defaultStatus": "unaffected",
                "modules": [
                  "\u0027Elixir.JSV.Helpers.RegexExt\u0027",
                  "\u0027Elixir.JSV.Vocabulary.V202012.Validation\u0027",
                  "\u0027Elixir.JSV.Vocabulary.V202012.Applicator\u0027",
                  "\u0027Elixir.JSV\u0027"
                ],
                "packageName": "jsv",
                "packageURL": "pkg:hex/jsv",
                "product": "jsv",
                "programFiles": [
                  "lib/jsv/helpers/regex_ext.ex",
                  "lib/jsv/vocabulary/v202012/validation.ex",
                  "lib/jsv/vocabulary/v202012/applicator.ex",
                  "lib/jsv.ex"
                ],
                "programRoutines": [
                  {
                    "name": "\u0027Elixir.JSV.Helpers.RegexExt\u0027:\u0027bounded_match?\u0027/2"
                  },
                  {
                    "name": "\u0027Elixir.JSV.Vocabulary.V202012.Validation\u0027:validate_keyword/3"
                  },
                  {
                    "name": "\u0027Elixir.JSV.Vocabulary.V202012.Applicator\u0027:validate_keyword/3"
                  },
                  {
                    "name": "\u0027Elixir.JSV\u0027:validate/2"
                  },
                  {
                    "name": "\u0027Elixir.JSV\u0027:validate/3"
                  }
                ],
                "repo": "https://github.com/lud/jsv",
                "vendor": "lud",
                "versions": [
                  {
                    "lessThan": "0.26.2",
                    "status": "affected",
                    "version": "0.1.0",
                    "versionType": "semver"
                  }
                ]
              },
              {
                "collectionURL": "https://github.com",
                "cpes": [
                  "cpe:2.3:a:lud:jsv:*:*:*:*:*:*:*:*"
                ],
                "defaultStatus": "unaffected",
                "modules": [
                  "\u0027Elixir.JSV.Helpers.RegexExt\u0027",
                  "\u0027Elixir.JSV.Vocabulary.V202012.Validation\u0027",
                  "\u0027Elixir.JSV.Vocabulary.V202012.Applicator\u0027",
                  "\u0027Elixir.JSV\u0027"
                ],
                "packageName": "lud/jsv",
                "packageURL": "pkg:github/lud/jsv",
                "product": "jsv",
                "programFiles": [
                  "lib/jsv/helpers/regex_ext.ex",
                  "lib/jsv/vocabulary/v202012/validation.ex",
                  "lib/jsv/vocabulary/v202012/applicator.ex",
                  "lib/jsv.ex"
                ],
                "programRoutines": [
                  {
                    "name": "\u0027Elixir.JSV.Helpers.RegexExt\u0027:\u0027bounded_match?\u0027/2"
                  },
                  {
                    "name": "\u0027Elixir.JSV.Vocabulary.V202012.Validation\u0027:validate_keyword/3"
                  },
                  {
                    "name": "\u0027Elixir.JSV.Vocabulary.V202012.Applicator\u0027:validate_keyword/3"
                  },
                  {
                    "name": "\u0027Elixir.JSV\u0027:validate/2"
                  },
                  {
                    "name": "\u0027Elixir.JSV\u0027:validate/3"
                  }
                ],
                "repo": "https://github.com/lud/jsv",
                "vendor": "lud",
                "versions": [
                  {
                    "lessThan": "defdb8a68ac7f218aa5dfe85190d484017cb8817",
                    "status": "affected",
                    "version": "302a5d0803468f81a1cf08e3b67d8b14cee759ca",
                    "versionType": "git"
                  }
                ]
              }
            ],
            "source": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db"
          }
        ],
        "cveTags": [],
        "descriptions": [
          {
            "lang": "en",
            "value": "Improper Check for Unusual or Exceptional Conditions vulnerability in the pattern and patternProperties keywords in lud jsv allows an unauthenticated remote attacker to bypass schema validation via a string that matches a schema regex only after heavy backtracking. JSV.Helpers.RegexExt.bounded_match?/2 runs schema regexes with a backtracking budget but calls :re.run/3 without :report_errors, so a match that exhausts the budget returns the same :nomatch as a real non-match. A key that matches a patternProperties regex is then checked against additionalProperties or not at all, and a string that matches a not subschema with a pattern is accepted. Before the budget existed, Regex.match?/2 failed the same way at Erlang\u0027s default match limit.\n\nOnly schemas whose regex explores a catastrophic branch before the branch that matches are affected. The attacker controls the data, not the schema, and linear patterns never exhaust the budget.\n\nThis issue affects jsv: from 0.1.0 before 0.26.2."
          }
        ],
        "id": "CVE-2026-117680",
        "lastModified": "2026-11-02T20:17:36.543",
        "metrics": {
          "cvssMetricV40": [
            {
              "cvssData": {
                "Automatable": "NOT_DEFINED",
                "Recovery": "NOT_DEFINED",
                "Safety": "NOT_DEFINED",
                "attackComplexity": "LOW",
                "attackRequirements": "PRESENT",
                "attackVector": "LOCAL",
                "availabilityRequirement": "NOT_DEFINED",
                "baseScore": 2.1,
                "baseSeverity": "LOW",
                "confidentialityRequirement": "NOT_DEFINED",
                "exploitMaturity": "NOT_DEFINED",
                "integrityRequirement": "NOT_DEFINED",
                "modifiedAttackComplexity": "NOT_DEFINED",
                "modifiedAttackRequirements": "NOT_DEFINED",
                "modifiedAttackVector": "NOT_DEFINED",
                "modifiedPrivilegesRequired": "NOT_DEFINED",
                "modifiedSubAvailabilityImpact": "NOT_DEFINED",
                "modifiedSubConfidentialityImpact": "NOT_DEFINED",
                "modifiedSubIntegrityImpact": "NOT_DEFINED",
                "modifiedUserInteraction": "NOT_DEFINED",
                "modifiedVulnAvailabilityImpact": "NOT_DEFINED",
                "modifiedVulnConfidentialityImpact": "NOT_DEFINED",
                "modifiedVulnIntegrityImpact": "NOT_DEFINED",
                "privilegesRequired": "NONE",
                "providerUrgency": "NOT_DEFINED",
                "subAvailabilityImpact": "NONE",
                "subConfidentialityImpact": "NONE",
                "subIntegrityImpact": "NONE",
                "userInteraction": "NONE",
                "valueDensity": "NOT_DEFINED",
                "vectorString": "CVSS:4.0/AV:L/AC:L/AT:P/PR:N/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
                "version": "4.0",
                "vulnAvailabilityImpact": "NONE",
                "vulnConfidentialityImpact": "NONE",
                "vulnIntegrityImpact": "LOW",
                "vulnerabilityResponseEffort": "NOT_DEFINED"
              },
              "source": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
              "type": "Secondary"
            }
          ],
          "ssvcV203": [
            {
              "source": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
              "ssvcData": {
                "id": "CVE-2026-117680",
                "options": [
                  {
                    "exploitation": "poc"
                  },
                  {
                    "automatable": "no"
                  },
                  {
                    "technicalImpact": "partial"
                  }
                ],
                "role": "CISA Coordinator",
                "timestamp": "2026-11-02T19:43:40.753996Z",
                "version": "2.0.3"
              }
            }
          ]
        },
        "published": "2026-11-01T14:18:51.500",
        "references": [
          {
            "source": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
            "url": "https://cna.erlef.org/cves/CVE-2026-117680.html"
          },
          {
            "source": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
            "url": "https://github.com/lud/jsv/commit/302a5d0803468f81a1cf08e3b67d8b14cee759ca"
          },
          {
            "source": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
            "url": "https://github.com/lud/jsv/commit/defdb8a68ac7f218aa5dfe85190d484017cb8817"
          },
          {
            "source": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
            "url": "https://github.com/lud/jsv/security/advisories/GHSA-cvmg-hgv6-jqcp"
          },
          {
            "source": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
            "url": "https://osv.dev/vulnerability/EEF-CVE-2026-117680"
          },
          {
            "source": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
            "url": "https://github.com/lud/jsv/security/advisories/GHSA-cvmg-hgv6-jqcp"
          }
        ],
        "sourceIdentifier": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
        "vulnStatus": "Deferred",
        "weaknesses": [
          {
            "description": [
              {
                "lang": "en",
                "value": "CWE-754"
              }
            ],
            "source": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
            "type": "Secondary"
          }
        ]
      }
    },
    "vulnrichment": {
      "containers": {
        "adp": [
          {
            "metrics": [
              {
                "other": {
                  "content": {
                    "id": "CVE-2026-117680",
                    "options": [
                      {
                        "Exploitation": "poc"
                      },
                      {
                        "Automatable": "no"
                      },
                      {
                        "Technical Impact": "partial"
                      }
                    ],
                    "role": "CISA Coordinator",
                    "timestamp": "2026-11-02T19:43:40.753996Z",
                    "version": "2.0.3"
                  },
                  "type": "ssvc"
                }
              }
            ],
            "providerMetadata": {
              "dateUpdated": "2026-11-02T19:43:57.102Z",
              "orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
              "shortName": "CISA-ADP"
            },
            "references": [
              {
                "tags": [
                  "exploit"
                ],
                "url": "https://github.com/lud/jsv/security/advisories/GHSA-cvmg-hgv6-jqcp"
              }
            ],
            "title": "CISA ADP Vulnrichment"
          }
        ],
        "cna": {
          "affected": [
            {
              "collectionURL": "https://repo.hex.pm",
              "cpes": [
                "cpe:2.3:a:lud:jsv:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "\u0027Elixir.JSV.Helpers.RegexExt\u0027",
                "\u0027Elixir.JSV.Vocabulary.V202012.Validation\u0027",
                "\u0027Elixir.JSV.Vocabulary.V202012.Applicator\u0027",
                "\u0027Elixir.JSV\u0027"
              ],
              "packageName": "jsv",
              "packageURL": "pkg:hex/jsv",
              "product": "jsv",
              "programFiles": [
                "lib/jsv/helpers/regex_ext.ex",
                "lib/jsv/vocabulary/v202012/validation.ex",
                "lib/jsv/vocabulary/v202012/applicator.ex",
                "lib/jsv.ex"
              ],
              "programRoutines": [
                {
                  "name": "\u0027Elixir.JSV.Helpers.RegexExt\u0027:\u0027bounded_match?\u0027/2"
                },
                {
                  "name": "\u0027Elixir.JSV.Vocabulary.V202012.Validation\u0027:validate_keyword/3"
                },
                {
                  "name": "\u0027Elixir.JSV.Vocabulary.V202012.Applicator\u0027:validate_keyword/3"
                },
                {
                  "name": "\u0027Elixir.JSV\u0027:validate/2"
                },
                {
                  "name": "\u0027Elixir.JSV\u0027:validate/3"
                }
              ],
              "repo": "https://github.com/lud/jsv",
              "vendor": "lud",
              "versions": [
                {
                  "lessThan": "0.26.2",
                  "status": "affected",
                  "version": "0.1.0",
                  "versionType": "semver"
                }
              ]
            },
            {
              "collectionURL": "https://github.com",
              "cpes": [
                "cpe:2.3:a:lud:jsv:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "\u0027Elixir.JSV.Helpers.RegexExt\u0027",
                "\u0027Elixir.JSV.Vocabulary.V202012.Validation\u0027",
                "\u0027Elixir.JSV.Vocabulary.V202012.Applicator\u0027",
                "\u0027Elixir.JSV\u0027"
              ],
              "packageName": "lud/jsv",
              "packageURL": "pkg:github/lud/jsv",
              "product": "jsv",
              "programFiles": [
                "lib/jsv/helpers/regex_ext.ex",
                "lib/jsv/vocabulary/v202012/validation.ex",
                "lib/jsv/vocabulary/v202012/applicator.ex",
                "lib/jsv.ex"
              ],
              "programRoutines": [
                {
                  "name": "\u0027Elixir.JSV.Helpers.RegexExt\u0027:\u0027bounded_match?\u0027/2"
                },
                {
                  "name": "\u0027Elixir.JSV.Vocabulary.V202012.Validation\u0027:validate_keyword/3"
                },
                {
                  "name": "\u0027Elixir.JSV.Vocabulary.V202012.Applicator\u0027:validate_keyword/3"
                },
                {
                  "name": "\u0027Elixir.JSV\u0027:validate/2"
                },
                {
                  "name": "\u0027Elixir.JSV\u0027:validate/3"
                }
              ],
              "repo": "https://github.com/lud/jsv",
              "vendor": "lud",
              "versions": [
                {
                  "lessThan": "defdb8a68ac7f218aa5dfe85190d484017cb8817",
                  "status": "affected",
                  "version": "302a5d0803468f81a1cf08e3b67d8b14cee759ca",
                  "versionType": "git"
                }
              ]
            }
          ],
          "configurations": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eThe schema must contain a \u003ccode\u003epattern\u003c/code\u003e or \u003ccode\u003epatternProperties\u003c/code\u003e regex that PCRE can match only after exploring a catastrophic branch first, such as a nested quantifier in an earlier alternative. Linear patterns never exhaust the budget. The attacker controls the validated data but not the schema.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "The schema must contain a `pattern` or `patternProperties` regex that PCRE can match only after exploring a catastrophic branch first, such as a nested quantifier in an earlier alternative. Linear patterns never exhaust the budget. The attacker controls the validated data but not the schema."
                }
              ],
              "value": "The schema must contain a pattern or patternProperties regex that PCRE can match only after exploring a catastrophic branch first, such as a nested quantifier in an earlier alternative. Linear patterns never exhaust the budget. The attacker controls the validated data but not the schema."
            }
          ],
          "cpeApplicability": [
            {
              "nodes": [
                {
                  "cpeMatch": [
                    {
                      "criteria": "cpe:2.3:a:lud:jsv:*:*:*:*:*:*:*:*",
                      "versionEndExcluding": "0.26.2",
                      "versionStartIncluding": "0.1.0",
                      "vulnerable": true
                    }
                  ],
                  "negate": false,
                  "operator": "OR"
                }
              ],
              "operator": "AND"
            }
          ],
          "credits": [
            {
              "lang": "en",
              "type": "finder",
              "value": "Lars Hesel Christensen"
            },
            {
              "lang": "en",
              "type": "reporter",
              "value": "Lars Hesel Christensen"
            },
            {
              "lang": "en",
              "type": "remediation developer",
              "value": "Ludovic Dem"
            },
            {
              "lang": "en",
              "type": "coordinator",
              "value": "Jonatan M\u00e4nnchen / EEF"
            }
          ],
          "dateAssigned": "2026-10-30T23:20:38.000Z",
          "descriptions": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eImproper Check for Unusual or Exceptional Conditions vulnerability in the \u003ccode\u003epattern\u003c/code\u003e and \u003ccode\u003epatternProperties\u003c/code\u003e keywords in lud jsv allows an unauthenticated remote attacker to bypass schema validation via a string that matches a schema regex only after heavy backtracking. \u003ccode\u003eJSV.Helpers.RegexExt.bounded_match?/2\u003c/code\u003e runs schema regexes with a backtracking budget but calls \u003ccode\u003e:re.run/3\u003c/code\u003e without \u003ccode\u003e:report_errors\u003c/code\u003e, so a match that exhausts the budget returns the same \u003ccode\u003e:nomatch\u003c/code\u003e as a real non-match. A key that matches a \u003ccode\u003epatternProperties\u003c/code\u003e regex is then checked against \u003ccode\u003eadditionalProperties\u003c/code\u003e or not at all, and a string that matches a \u003ccode\u003enot\u003c/code\u003e subschema with a \u003ccode\u003epattern\u003c/code\u003e is accepted. Before the budget existed, \u003ccode\u003eRegex.match?/2\u003c/code\u003e failed the same way at Erlang\u0027s default match limit.\u003c/p\u003e\n\u003cp\u003eOnly schemas whose regex explores a catastrophic branch before the branch that matches are affected. The attacker controls the data, not the schema, and linear patterns never exhaust the budget.\u003c/p\u003e\n\u003cp\u003eThis issue affects jsv: from 0.1.0 before 0.26.2.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Improper Check for Unusual or Exceptional Conditions vulnerability in the `pattern` and `patternProperties` keywords in lud jsv allows an unauthenticated remote attacker to bypass schema validation via a string that matches a schema regex only after heavy backtracking. `JSV.Helpers.RegexExt.bounded_match?/2` runs schema regexes with a backtracking budget but calls `:re.run/3` without `:report_errors`, so a match that exhausts the budget returns the same `:nomatch` as a real non-match. A key that matches a `patternProperties` regex is then checked against `additionalProperties` or not at all, and a string that matches a `not` subschema with a `pattern` is accepted. Before the budget existed, `Regex.match?/2` failed the same way at Erlang\u0027s default match limit.\n\nOnly schemas whose regex explores a catastrophic branch before the branch that matches are affected. The attacker controls the data, not the schema, and linear patterns never exhaust the budget.\n\nThis issue affects jsv: from 0.1.0 before 0.26.2."
                }
              ],
              "value": "Improper Check for Unusual or Exceptional Conditions vulnerability in the pattern and patternProperties keywords in lud jsv allows an unauthenticated remote attacker to bypass schema validation via a string that matches a schema regex only after heavy backtracking. JSV.Helpers.RegexExt.bounded_match?/2 runs schema regexes with a backtracking budget but calls :re.run/3 without :report_errors, so a match that exhausts the budget returns the same :nomatch as a real non-match. A key that matches a patternProperties regex is then checked against additionalProperties or not at all, and a string that matches a not subschema with a pattern is accepted. Before the budget existed, Regex.match?/2 failed the same way at Erlang\u0027s default match limit.\n\nOnly schemas whose regex explores a catastrophic branch before the branch that matches are affected. The attacker controls the data, not the schema, and linear patterns never exhaust the budget.\n\nThis issue affects jsv: from 0.1.0 before 0.26.2."
            }
          ],
          "impacts": [
            {
              "capecId": "CAPEC-153",
              "descriptions": [
                {
                  "lang": "en",
                  "supportingMedia": [
                    {
                      "base64": false,
                      "type": "text/html",
                      "value": "\u003cp\u003eAn attacker pads a string until its match exhausts the budget, so a value under a \u003ccode\u003epatternProperties\u003c/code\u003e key skips its subschema or a string passes a \u003ccode\u003enot\u003c/code\u003e deny-list. The application then accepts input its schema should reject.\u003c/p\u003e"
                    },
                    {
                      "base64": false,
                      "type": "text/markdown",
                      "value": "An attacker pads a string until its match exhausts the budget, so a value under a `patternProperties` key skips its subschema or a string passes a `not` deny-list. The application then accepts input its schema should reject."
                    }
                  ],
                  "value": "An attacker pads a string until its match exhausts the budget, so a value under a patternProperties key skips its subschema or a string passes a not deny-list. The application then accepts input its schema should reject."
                }
              ]
            }
          ],
          "metrics": [
            {
              "cvssV4_0": {
                "Automatable": "NOT_DEFINED",
                "Recovery": "NOT_DEFINED",
                "Safety": "NOT_DEFINED",
                "attackComplexity": "LOW",
                "attackRequirements": "PRESENT",
                "attackVector": "LOCAL",
                "baseScore": 2.1,
                "baseSeverity": "LOW",
                "privilegesRequired": "NONE",
                "providerUrgency": "NOT_DEFINED",
                "subAvailabilityImpact": "NONE",
                "subConfidentialityImpact": "NONE",
                "subIntegrityImpact": "NONE",
                "userInteraction": "NONE",
                "valueDensity": "NOT_DEFINED",
                "vectorString": "CVSS:4.0/AV:L/AC:L/AT:P/PR:N/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N",
                "version": "4.0",
                "vulnAvailabilityImpact": "NONE",
                "vulnConfidentialityImpact": "NONE",
                "vulnIntegrityImpact": "LOW",
                "vulnerabilityResponseEffort": "NOT_DEFINED"
              },
              "format": "CVSS",
              "scenarios": [
                {
                  "lang": "en",
                  "value": "GENERAL"
                }
              ]
            }
          ],
          "problemTypes": [
            {
              "descriptions": [
                {
                  "cweId": "CWE-754",
                  "description": "CWE-754 Improper Check for Unusual or Exceptional Conditions",
                  "lang": "en",
                  "type": "CWE"
                }
              ]
            }
          ],
          "providerMetadata": {
            "dateUpdated": "2026-11-01T13:29:36.681Z",
            "orgId": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
            "shortName": "EEF"
          },
          "references": [
            {
              "name": "Regex match budget exhaustion is treated as a non-match, bypassing `patternProperties` and `not`",
              "tags": [
                "vendor-advisory",
                "related"
              ],
              "url": "https://github.com/lud/jsv/security/advisories/GHSA-cvmg-hgv6-jqcp"
            },
            {
              "name": "EEF CNA record for CVE-2026-117680",
              "tags": [
                "related"
              ],
              "url": "https://cna.erlef.org/cves/CVE-2026-117680.html"
            },
            {
              "name": "OSV record EEF-CVE-2026-117680",
              "tags": [
                "related"
              ],
              "url": "https://osv.dev/vulnerability/EEF-CVE-2026-117680"
            },
            {
              "name": "Introducing commit 302a5d0 in lud/jsv",
              "tags": [
                "related"
              ],
              "url": "https://github.com/lud/jsv/commit/302a5d0803468f81a1cf08e3b67d8b14cee759ca"
            },
            {
              "name": "Fix commit defdb8a in lud/jsv",
              "tags": [
                "patch"
              ],
              "url": "https://github.com/lud/jsv/commit/defdb8a68ac7f218aa5dfe85190d484017cb8817"
            }
          ],
          "source": {
            "discovery": "EXTERNAL"
          },
          "title": "jsv treats regex match budget exhaustion as a non-match, bypassing patternProperties and not",
          "workarounds": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003ePair \u003ccode\u003epatternProperties\u003c/code\u003e with \u003ccode\u003eadditionalProperties: false\u003c/code\u003e. A key whose match exhausts the budget is then rejected instead of accepted unchecked. Valid keys that need heavy backtracking are rejected as well.\u003c/p\u003e\n\u003cp\u003eWrite schema regexes without nested quantifiers or overlapping alternatives, and do not express deny-lists as a \u003ccode\u003enot\u003c/code\u003e subschema with a \u003ccode\u003epattern\u003c/code\u003e on untrusted input.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Pair `patternProperties` with `additionalProperties: false`. A key whose match exhausts the budget is then rejected instead of accepted unchecked. Valid keys that need heavy backtracking are rejected as well.\n\nWrite schema regexes without nested quantifiers or overlapping alternatives, and do not express deny-lists as a `not` subschema with a `pattern` on untrusted input."
                }
              ],
              "value": "Pair patternProperties with additionalProperties: false. A key whose match exhausts the budget is then rejected instead of accepted unchecked. Valid keys that need heavy backtracking are rejected as well.\n\nWrite schema regexes without nested quantifiers or overlapping alternatives, and do not express deny-lists as a not subschema with a pattern on untrusted input."
            }
          ],
          "x_proofOfConcept": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003col\u003e\n\u003cli\u003eBuild a schema with \u003ccode\u003epatternProperties\u003c/code\u003e mapping the regex \u003ccode\u003e^(?:(a+)+b|a+!)$\u003c/code\u003e to \u003ccode\u003e{\"type\": \"integer\"}\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eSubmit an object whose only key is twenty \u003ccode\u003ea\u003c/code\u003e characters followed by \u003ccode\u003e!\u003c/code\u003e and whose value is the string \u003ccode\u003enot an int\u003c/code\u003e. The key matches the regex through its second alternative, but PCRE exhausts the 11,050-step budget in the first alternative.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eJSV.validate/2\u003c/code\u003e returns \u003ccode\u003e:ok\u003c/code\u003e. The value is never checked against the subschema.\u003c/li\u003e\n\u003cli\u003eBuild a second schema \u003ccode\u003e{\"not\": {\"pattern\": \"^(?:(a+)+b|a+!)$\"}}\u003c/code\u003e and submit the same string. \u003ccode\u003eJSV.validate/2\u003c/code\u003e returns \u003ccode\u003e:ok\u003c/code\u003e although the string matches the denied pattern.\u003c/li\u003e\n\u003cli\u003eRepeat with the short key \u003ccode\u003eaaa!\u003c/code\u003e. Both schemas now reject the data as expected.\u003c/li\u003e\n\u003c/ol\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "1. Build a schema with `patternProperties` mapping the regex `^(?:(a+)+b|a+!)$` to `{\"type\": \"integer\"}`.\n2. Submit an object whose only key is twenty `a` characters followed by `!` and whose value is the string `not an int`. The key matches the regex through its second alternative, but PCRE exhausts the 11,050-step budget in the first alternative.\n3. `JSV.validate/2` returns `:ok`. The value is never checked against the subschema.\n4. Build a second schema `{\"not\": {\"pattern\": \"^(?:(a+)+b|a+!)$\"}}` and submit the same string. `JSV.validate/2` returns `:ok` although the string matches the denied pattern.\n5. Repeat with the short key `aaa!`. Both schemas now reject the data as expected."
                }
              ],
              "value": "* Build a schema with patternProperties mapping the regex ^(?:(a+)+b|a+!)$ to {\"type\": \"integer\"}.\n* Submit an object whose only key is twenty a characters followed by ! and whose value is the string not an int. The key matches the regex through its second alternative, but PCRE exhausts the 11,050-step budget in the first alternative.\n* JSV.validate/2 returns :ok. The value is never checked against the subschema.\n* Build a second schema {\"not\": {\"pattern\": \"^(?:(a+)+b|a+!)$\"}} and submit the same string. JSV.validate/2 returns :ok although the string matches the denied pattern.\n* Repeat with the short key aaa!. Both schemas now reject the data as expected."
            }
          ],
          "x_technicalAnalysis": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003e\u003cstrong\u003e1. Bounded matching.\u003c/strong\u003e \u003ccode\u003eJSV.Helpers.RegexExt.bounded_match?/2\u003c/code\u003e in \u003ccode\u003elib/jsv/helpers/regex_ext.ex\u003c/code\u003e runs each schema regex through \u003ccode\u003e:re.run/3\u003c/code\u003e with \u003ccode\u003ematch_limit\u003c/code\u003e and \u003ccode\u003ematch_limit_recursion\u003c/code\u003e set to \u003ccode\u003e10_000 + 50 * byte_size(subject)\u003c/code\u003e, capped at 10,000,000. The call omits \u003ccode\u003e:report_errors\u003c/code\u003e, so PCRE\u0027s \u003ccode\u003ematch_limit\u003c/code\u003e error is returned as \u003ccode\u003e:nomatch\u003c/code\u003e. The function compares the result to \u003ccode\u003e:match\u003c/code\u003e and returns \u003ccode\u003efalse\u003c/code\u003e for a genuine non-match and for an exhausted budget alike.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e2. Keyword evaluation.\u003c/strong\u003e \u003ccode\u003eJSV.Vocabulary.V202012.Validation.validate_keyword/3\u003c/code\u003e uses the result for \u003ccode\u003epattern\u003c/code\u003e, and \u003ccode\u003eJSV.Vocabulary.V202012.Applicator\u003c/code\u003e uses it to decide which \u003ccode\u003epatternProperties\u003c/code\u003e subschemas apply to each key. The draft 7 vocabulary delegates to the same modules. A \u003ccode\u003efalse\u003c/code\u003e from an exhausted budget therefore means a \u003ccode\u003epattern\u003c/code\u003e keyword fails and a \u003ccode\u003epatternProperties\u003c/code\u003e subschema is skipped.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e3. Inversion by combinators.\u003c/strong\u003e Under \u003ccode\u003enot\u003c/code\u003e, \u003ccode\u003eanyOf\u003c/code\u003e, \u003ccode\u003eoneOf\u003c/code\u003e, \u003ccode\u003eif\u003c/code\u003e and \u003ccode\u003econtains\u003c/code\u003e, a failing subschema can make the parent succeed, so a false non-match under \u003ccode\u003enot\u003c/code\u003e accepts a string the deny-list should reject. Under \u003ccode\u003epatternProperties\u003c/code\u003e the skipped subschema means the value is checked against \u003ccode\u003eadditionalProperties\u003c/code\u003e or nothing.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e4. History.\u003c/strong\u003e Before the budget was introduced, the same keywords called \u003ccode\u003eRegex.match?/2\u003c/code\u003e, which also returns \u003ccode\u003efalse\u003c/code\u003e on Erlang\u0027s default limit of 10,000,000 steps. The budget lowered the input size needed from about 25 bytes to about 20 bytes for the advisory\u0027s pattern.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "**1. Bounded matching.** `JSV.Helpers.RegexExt.bounded_match?/2` in `lib/jsv/helpers/regex_ext.ex` runs each schema regex through `:re.run/3` with `match_limit` and `match_limit_recursion` set to `10_000 + 50 * byte_size(subject)`, capped at 10,000,000. The call omits `:report_errors`, so PCRE\u0027s `match_limit` error is returned as `:nomatch`. The function compares the result to `:match` and returns `false` for a genuine non-match and for an exhausted budget alike.\n\n**2. Keyword evaluation.** `JSV.Vocabulary.V202012.Validation.validate_keyword/3` uses the result for `pattern`, and `JSV.Vocabulary.V202012.Applicator` uses it to decide which `patternProperties` subschemas apply to each key. The draft 7 vocabulary delegates to the same modules. A `false` from an exhausted budget therefore means a `pattern` keyword fails and a `patternProperties` subschema is skipped.\n\n**3. Inversion by combinators.** Under `not`, `anyOf`, `oneOf`, `if` and `contains`, a failing subschema can make the parent succeed, so a false non-match under `not` accepts a string the deny-list should reject. Under `patternProperties` the skipped subschema means the value is checked against `additionalProperties` or nothing.\n\n**4. History.** Before the budget was introduced, the same keywords called `Regex.match?/2`, which also returns `false` on Erlang\u0027s default limit of 10,000,000 steps. The budget lowered the input size needed from about 25 bytes to about 20 bytes for the advisory\u0027s pattern."
                }
              ],
              "value": "1. Bounded matching. JSV.Helpers.RegexExt.bounded_match?/2 in lib/jsv/helpers/regex_ext.ex runs each schema regex through :re.run/3 with match_limit and match_limit_recursion set to 10_000 + 50 * byte_size(subject), capped at 10,000,000. The call omits :report_errors, so PCRE\u0027s match_limit error is returned as :nomatch. The function compares the result to :match and returns false for a genuine non-match and for an exhausted budget alike.\n\n2. Keyword evaluation. JSV.Vocabulary.V202012.Validation.validate_keyword/3 uses the result for pattern, and JSV.Vocabulary.V202012.Applicator uses it to decide which patternProperties subschemas apply to each key. The draft 7 vocabulary delegates to the same modules. A false from an exhausted budget therefore means a pattern keyword fails and a patternProperties subschema is skipped.\n\n3. Inversion by combinators. Under not, anyOf, oneOf, if and contains, a failing subschema can make the parent succeed, so a false non-match under not accepts a string the deny-list should reject. Under patternProperties the skipped subschema means the value is checked against additionalProperties or nothing.\n\n4. History. Before the budget was introduced, the same keywords called Regex.match?/2, which also returns false on Erlang\u0027s default limit of 10,000,000 steps. The budget lowered the input size needed from about 25 bytes to about 20 bytes for the advisory\u0027s pattern."
            }
          ]
        }
      },
      "cveMetadata": {
        "assignerOrgId": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
        "assignerShortName": "EEF",
        "cveId": "CVE-2026-117680",
        "datePublished": "2026-11-01T13:29:36.681Z",
        "dateReserved": "2026-10-30T12:45:01.930Z",
        "dateUpdated": "2026-11-02T19:44:02.251Z",
        "state": "PUBLISHED"
      },
      "dataType": "CVE_RECORD",
      "dataVersion": "5.2"
    }
  }
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Drag nodes to arrange them. Double-click a related vulnerability to open it, or a source to visit its link. The Physics button on the left tunes the layout and the simulation; the legend at the bottom left hides or shows nodes by kind and by sighting type.

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.
Vulnerability timeline

Sightings and recorded dates, grouped by day · UTC

JSON
How durations are calculated

Following the VTEM framework (Black Hat USA 2015), time to patch starts when the vendor or a coordinator was informed, total time to patch at discovery, and disclosure to patch at public disclosure; vendor response time runs from the report to its acknowledgement. Time to exploit and time unpatched start at the earliest discovery or report, falling back to public disclosure. Unpatched time ends at the first recorded patch, or the calculation time when no patch is recorded. Exploitation to patch shows the interval between those two events; a published proof of concept is a public exploit, not exploitation.

Each result shows its source dates. A negative interval means the end event came first; when date-only inputs leave the order open, the result says so. Date-only inputs are approximate. The earliest evidence wins: KEV report dates and sightings are labelled as such. Records describing another vulnerability are listed but never calculated from, and a PoC alone does not establish exploitation. Missing patch evidence does not prove that no patch exists. Filters below change the event list only.

Events included in the timeline

Loading timeline…


    Loading…

    Loading…

    Loading…

    Related by attack behaviour

    Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.