{"id":"CVE-2026-111758","revision":null,"records":[{"revision":"601869fa64dc40c1863d63c193b36135","observedAt":"2026-10-28T17:46:48.824+00:00","statement":{"source":"cve-program","id":"CVE-2026-111758","aliases":[],"title":"markdown-it: Quadratic-time rendering of a single multi-line link reference definition with default options (regression since 14.0)","description":"markdown-it is a Markdown parser. From versions 14.1.0 to before 14.3.3, and 15.0.0 to before 15.0.3, a link reference definition whose label or title is never closed is O(n²) with default options. Continuation lines are pulled lazily with str += lineContent in src/rules_block/reference.ts, and the subsequent charCodeAt and slice calls flatten the V8 cons-string, copying everything collected so far; this runs before the rule decides the definition is invalid. No options are required to trigger it. This issue has been patched in versions 14.3.3 and 15.0.3.","state":0,"publishedAt":"2026-10-20T20:28:40.677+00:00","modifiedAt":"2026-10-28T16:40:33.483+00:00","affected":[{"ecosystem":"Vendor product","name":"markdown-it","ranges":[],"versions":[],"rawVersionEvidence":"{\n                    \"vendor\": \"markdown-it\",\n                    \"product\": \"markdown-it\",\n                    \"versions\": [\n                        {\n                            \"version\": \">= 14.1.0, < 14.3.3\",\n                            \"status\": \"affected\"\n                        },\n                        {\n                            \"version\": \">= 15.0.0, < 15.0.3\",\n                            \"status\": \"affected\"\n                        }\n                    ]\n                }"}],"metrics":[{"system":"CVSS 3.1","vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","score":7.5,"severity":"HIGH"}],"references":["https://github.com/markdown-it/markdown-it/security/advisories/GHSA-gfr2-rv44-r23c","https://github.com/markdown-it/markdown-it/commit/48fbc465812c440020c663f040ab22deaf8f1eca","https://github.com/markdown-it/markdown-it/commit/d99f48839d37af6fd8a2617516c43dab90755503","https://github.com/markdown-it/markdown-it/releases/tag/14.3.3","https://github.com/markdown-it/markdown-it/releases/tag/15.0.3"],"sourceUrl":"https://www.cve.org/CVERecord?id=CVE-2026-111758","license":"CVE Program Terms of Use","key":"cve-program:CVE-2026-111758","identifiers":["CVE-2026-111758"]},"retained":false,"historicalAffected":[]},{"revision":"82f730817b47483699495465a89ea10e","observedAt":"2026-10-30T01:56:25.622+00:00","statement":{"source":"euvd","id":"EUVD-2026-105358","aliases":["CVE-2026-111758","GHSA-gfr2-rv44-r23c"],"title":"markdown-it is a Markdown parser. From versions 14.1.0 to before 14.3.3, and 15.0.0 to before 15.0.3, a link reference definition whose label or title is never closed is O(n²) with default options. Continuation lines are pulled lazily with …","description":"markdown-it is a Markdown parser. From versions 14.1.0 to before 14.3.3, and 15.0.0 to before 15.0.3, a link reference definition whose label or title is never closed is O(n²) with default options. Continuation lines are pulled lazily with str += lineContent in src/rules_block/reference.ts, and the subsequent charCodeAt and slice calls flatten the V8 cons-string, copying everything collected so far; this runs before the rule decides the definition is invalid. No options are required to trigger it. This issue has been patched in versions 14.3.3 and 15.0.3.","state":0,"publishedAt":null,"modifiedAt":null,"affected":[],"metrics":[{"system":"EUVD CVSS 3.1","vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","score":7.5,"severity":null}],"references":["https://github.com/markdown-it/markdown-it/security/advisories/GHSA-gfr2-rv44-r23c","https://github.com/markdown-it/markdown-it/commit/48fbc465812c440020c663f040ab22deaf8f1eca","https://github.com/markdown-it/markdown-it/commit/d99f48839d37af6fd8a2617516c43dab90755503","https://github.com/markdown-it/markdown-it/releases/tag/14.3.3","https://github.com/markdown-it/markdown-it/releases/tag/15.0.3"],"sourceUrl":"https://euvd.enisa.europa.eu/vulnerability/EUVD-2026-105358","license":"ENISA EUVD · source terms and attribution apply","enrichment":{"sourceStatus":null,"weaknesses":[],"productCriteria":[],"sourceDates":{"datePublished":"Oct 20, 2026, 8:28:40 PM","dateUpdated":"Oct 28, 2026, 4:40:33 PM"},"relatedAdvisories":[],"note":"EUVD source date text has no stated timezone and is retained without inventing a UTC instant. Related bulletin membership is not an alias, common cause or applicability claim. A missing vector with a zero score is treated as unrated. Complete vendor/product and underlying source evidence remains in the original JSON."},"key":"euvd:EUVD-2026-105358","identifiers":["EUVD-2026-105358","CVE-2026-111758","GHSA-gfr2-rv44-r23c"]},"retained":false,"historicalAffected":[]},{"revision":"083e5d0d899147199c5abee90eb3fd4f","observedAt":"2026-10-29T05:48:28.56+00:00","statement":{"source":"nvd","id":"CVE-2026-111758","aliases":[],"title":"markdown-it is a Markdown parser. From versions 14.1.0 to before 14.3.3, and 15.0.0 to before 15.0.3, a link reference definition whose label or title is never closed is O(n²) with default options. Continuation lines are pulled lazily with …","description":"markdown-it is a Markdown parser. From versions 14.1.0 to before 14.3.3, and 15.0.0 to before 15.0.3, a link reference definition whose label or title is never closed is O(n²) with default options. Continuation lines are pulled lazily with str += lineContent in src/rules_block/reference.ts, and the subsequent charCodeAt and slice calls flatten the V8 cons-string, copying everything collected so far; this runs before the rule decides the definition is invalid. No options are required to trigger it. This issue has been patched in versions 14.3.3 and 15.0.3.","state":0,"publishedAt":"2026-10-20T21:17:17.11+00:00","modifiedAt":"2026-10-28T17:17:39.977+00:00","affected":[],"metrics":[{"system":"CVSS 3.1 · security-advisories@github.com · Secondary","vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","score":7.5,"severity":"HIGH"}],"references":["https://github.com/markdown-it/markdown-it/commit/48fbc465812c440020c663f040ab22deaf8f1eca","https://github.com/markdown-it/markdown-it/commit/d99f48839d37af6fd8a2617516c43dab90755503","https://github.com/markdown-it/markdown-it/releases/tag/14.3.3","https://github.com/markdown-it/markdown-it/releases/tag/15.0.3","https://github.com/markdown-it/markdown-it/security/advisories/GHSA-gfr2-rv44-r23c"],"sourceUrl":"https://nvd.nist.gov/vuln/detail/CVE-2026-111758","license":"NIST NVD usage terms; underlying source attribution retained","enrichment":{"sourceStatus":"Awaiting Analysis","weaknesses":["CWE-400","CWE-407"],"productCriteria":[],"sourceDates":{"published":"2026-10-20T21:17:17.110","lastModified":"2026-10-28T17:17:39.977"},"relatedAdvisories":[],"note":"NVD analysis and CPE criteria are source context, not proof that a package or your environment is affected. Complete affected data, logical configurations and SSVC are retained in the original JSON."},"key":"nvd:CVE-2026-111758","identifiers":["CVE-2026-111758"]},"retained":false,"historicalAffected":[]},{"revision":"c13743f84cf4491f91715ed70a5b45a1","observedAt":"2026-10-24T13:17:17.793+00:00","statement":{"source":"osv","id":"GHSA-gfr2-rv44-r23c","aliases":["CVE-2026-111758"],"title":"markdown-it: Quadratic-time rendering of a single multi-line link reference definition with default options (regression since 14.0)","description":"### Summary\n\nA link reference definition whose label or title is never closed is O(n²) in markdown-it 15.0.2 with default options. Continuation lines are pulled lazily with str += lineContent in src/rules_block/reference.ts, and the subsequent charCodeAt and slice calls flatten the V8 cons-string, copying everything collected so far; this runs before the rule decides the definition is invalid. It is a regression introduced by PR #1004 in 14.0.0: 13.0.2 processed a 313 KB input in 125 ms, while every version since takes about 11 seconds on the same input. At the sizes below, 200 KB takes 3.6 seconds, 400 KB takes 18.1 seconds, and 800 KB takes 74.0 seconds, which is roughly 4–5× per doubling. No options are required to trigger it.\n\n### Details\n\nsrc/rules_block/reference.ts appends continuation lines with str += lineContent at lines 74, 83, 100, 133, and 150, then keeps indexing the accumulated string via str.charCodeAt(pos) in the label and whitespace loops and str.slice(...) in parseLinkTitle. V8 represents += as a cons-string, and the next charCodeAt or slice flattens it, copying everything collected so far, so one definition spanning n lines costs O(n²). Isolation confirms the rule is responsible: block-only parsing with inline disabled is still quadratic, md.disable('reference') makes the same input linear, and the same text without the leading [ is linear. The fix is to track positions in state.src instead of building str, or to collect line slices in an array and parse across them. At minimum, stop scanning the label after 999 characters (CommonMark §6.3) before pulling more lines, and cap title continuation. Add a pathological test with a 100k-line unclosed title and label. Open PR #1215 edits the same file but its label check runs after the label loop, so it does not bound either variant and the fix can land together with that PR.\n\nThe observed output from PoC was:\nunclosed title n=100000   200009 B    3585.5 ms\nunclosed title n=200000   400009 B   18107.1 ms   (5.05x)\nunclosed title n=400000   800009 B   73954.4 ms   (4.08x)\n\nRegression comparison at 313 KB: 13.0.2 → 125 ms, 14.1.0 → 11.4 s, 15.0.0 → 10.6 s, 15.0.2 → 10.7 s.\n\n### Proof of concept\n\nHow to execute the PoC:\n1. mkdir -p markdown-it-poc && cd markdown-it-poc\n2. npm init -y\n3. npm i markdown-it@15.0.2\n4. node poc_markdown_it.js\n\nPoC below is:\n```javascript\n// poc_markdown_it.js\n// Requires: npm install markdown-it@15.0.2\nconst MarkdownIt = require('markdown-it');\nconst md = new MarkdownIt();\n\nfunction bench(label, src) {\n  const t0 = process.hrtime.bigint();\n  md.render(src);\n  const t1 = process.hrtime.bigint();\n  console.log(\n    `${label.padEnd(30)} ${String(src.length).padStart(9)} B ${(Number(t1 - t0) / 1e6).toFixed(1).padStart(9)} ms`\n  );\n}\n\n// Unclosed title: one reference definition spread over many lines\nfor (const n of [100000, 200000, 400000]) {\n  bench(`unclosed title n=${n}`, '[a]: /u \"' + 'x\\n'.repeat(n));\n}\n\n// Unclosed label\nfor (const n of [5000, 10000, 20000]) {\n  bench(`unclosed label n=${n}`, '[' + 'a\\n'.repeat(n));\n}\n```\n\n### Impact\n\nThis is an algorithmic-complexity denial of service (CWE-407). Any server that renders user Markdown with markdown-it is affected with default options, including comments, issues, chat, wikis, docs previews, and LLM chat UIs. A ~400 KB request body blocks the Node.js event loop for about 18 seconds and an ~800 KB body for about 74 seconds. This is the same class and attacker model as GHSA-253c, but it is reachable without any opt-in option, since the affected path is a core block rule.","state":0,"publishedAt":"2026-10-20T20:28:44+00:00","modifiedAt":"2026-10-20T20:45:05.953469+00:00","affected":[{"ecosystem":"npm","name":"markdown-it","ranges":[{"type":"SEMVER","events":[{"kind":"introduced","version":"14.1.0"},{"kind":"fixed","version":"14.3.3"}]}],"versions":[],"rawVersionEvidence":null},{"ecosystem":"npm","name":"markdown-it","ranges":[{"type":"SEMVER","events":[{"kind":"introduced","version":"15.0.0"},{"kind":"fixed","version":"15.0.3"}]}],"versions":[],"rawVersionEvidence":null}],"metrics":[{"system":"CVSS_V3","vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","score":null,"severity":null},{"system":"Publisher rating","vector":null,"score":null,"severity":"HIGH"}],"references":["https://github.com/markdown-it/markdown-it/security/advisories/GHSA-gfr2-rv44-r23c","https://github.com/markdown-it/markdown-it/commit/48fbc465812c440020c663f040ab22deaf8f1eca","https://github.com/markdown-it/markdown-it/commit/d99f48839d37af6fd8a2617516c43dab90755503","https://github.com/markdown-it/markdown-it","https://github.com/markdown-it/markdown-it/releases/tag/14.3.3","https://github.com/markdown-it/markdown-it/releases/tag/15.0.3"],"sourceUrl":"https://github.com/advisories/GHSA-gfr2-rv44-r23c","license":"GitHub Advisory Database · CC-BY-4.0","key":"osv:GHSA-gfr2-rv44-r23c","identifiers":["GHSA-gfr2-rv44-r23c","CVE-2026-111758"]},"retained":false,"historicalAffected":[]}],"coverage":[{"source":"cisa-kev:global","scope":"Complete CISA KEV catalog; all vendors. Missing entries do not establish absence of exploitation.","generation":"2026-10-31T00:45:27.0287685+00:00","complete":true,"records":1766,"lastAttemptAt":"2026-10-31T00:45:27.0287685+00:00","lastSuccessAt":"2026-10-31T00:45:27.1820559+00:00","error":null,"lastVerifiedAt":"2026-10-31T00:45:27.1820567+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"cve-program","scope":"Official CVE Program baseline and cumulative hourly delta; all vendors, published and rejected records","generation":"cve-7e2c4e7288f2c464ad8c61f3bb6017374714faedcc781283ac06a706ee1a820b-2ab14bbac7aed146eb4566d0c0f2f6122020a00e6e03e98c548f6ca78b564d0c","complete":true,"records":417480,"lastAttemptAt":"2026-10-31T00:45:26.3480081+00:00","lastSuccessAt":"2026-10-30T23:45:37.8421483+00:00","error":"InvalidOperationException","lastVerifiedAt":"2026-10-30T23:45:38.1384309+00:00","snapshotPublishedAt":"2026-10-30T23:26:20+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"euvd","scope":"Rolling EUVD lookups of CVE aliases in current public OSV archives; 500 identifiers per refresh, rechecked after 48 hours. Not a global EUVD catalog. Successful not-found lookups count as checked; they do not imply withdrawal or safety. No reader inventory is sent.","generation":"enrichment-39149994e3854f27b5e713b62480af55","complete":true,"records":13563,"lastAttemptAt":"2026-10-31T00:45:56.6248575+00:00","lastSuccessAt":"2026-10-31T00:45:56.62+00:00","error":null,"lastVerifiedAt":"2026-10-31T00:45:56.62+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":13635,"expectedIdentifiers":13635,"failedIdentifiers":0},{"source":"first-epss:nuget","scope":"FIRST EPSS for explicit CVE aliases in the collected public NuGet archive. Not a global EPSS backfill.","generation":"2026-10-31T00:45:27.0287685+00:00","complete":true,"records":1094,"lastAttemptAt":"2026-10-31T00:45:27.0287685+00:00","lastSuccessAt":"2026-10-31T00:45:27.1829931+00:00","error":null,"lastVerifiedAt":"2026-10-31T00:45:27.1829933+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"nvd","scope":"Rolling NVD lookups of CVE aliases in current public OSV archives; 500 identifiers per refresh, rechecked after 48 hours. Not a global NVD catalog. Successful not-found lookups count as checked; they do not imply withdrawal or safety. No reader inventory is sent.","generation":"enrichment-01dfb738868f495991dd71b57183de53","complete":false,"records":13575,"lastAttemptAt":"2026-10-31T00:45:54.6049966+00:00","lastSuccessAt":"2026-10-31T00:45:54.602+00:00","error":null,"lastVerifiedAt":"2026-10-31T00:45:54.602+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":13599,"expectedIdentifiers":13635,"failedIdentifiers":0},{"source":"osv:Go","scope":"Complete OSV Go ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"go-21dcd6662970dfea02e4ea60ee637115e8d92664947484d2b9276b3f6568a84f","complete":true,"records":9815,"lastAttemptAt":"2026-10-31T00:45:26.9752288+00:00","lastSuccessAt":"2026-10-30T23:47:34.1817587+00:00","error":null,"lastVerifiedAt":"2026-10-31T00:45:26.9752288+00:00","snapshotPublishedAt":"2026-10-30T23:33:17+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"osv:NuGet","scope":"Complete OSV NuGet ecosystem archive, including GitHub Advisory Database records; NuGet version matching only","generation":"nuget-2de9ccc5290f060c7aa63f89c25dd76f655a64ba1aba7c05c97fa3bee4f09899","complete":true,"records":1967,"lastAttemptAt":"2026-10-31T00:45:26.4902262+00:00","lastSuccessAt":"2026-10-28T20:55:34.2982937+00:00","error":null,"lastVerifiedAt":"2026-10-31T00:45:26.4902262+00:00","snapshotPublishedAt":"2026-10-28T20:03:08+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"osv:crates.io","scope":"Complete OSV crates.io ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"crates.io-f95f76cd406ae5bae3de632ad37fd2d5160b44f5e6b51748ac6f8f0c0c88e72b","complete":true,"records":3028,"lastAttemptAt":"2026-10-31T00:45:26.9885441+00:00","lastSuccessAt":"2026-10-30T23:47:38.4914494+00:00","error":null,"lastVerifiedAt":"2026-10-31T00:45:26.9885441+00:00","snapshotPublishedAt":"2026-10-30T23:18:12+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"osv:npm","scope":"Complete OSV npm ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"npm-3bba47d78eb61bae29443e8f4fe215a6614d54f3560d07419145a76e9ac024ad","complete":true,"records":230992,"lastAttemptAt":"2026-10-31T00:45:26.8701271+00:00","lastSuccessAt":"2026-10-30T23:47:24.2343384+00:00","error":null,"lastVerifiedAt":"2026-10-31T00:45:26.8701271+00:00","snapshotPublishedAt":"2026-10-30T23:18:17+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null}]}