{
  "variant_id": "CVE-2026-39999-variant-jwt-auth-alg-confusion-asymmetric-families",
  "created_at": "2026-07-13T16:42:00Z",
  "variant_summary": "Bypass/variant probe for CVE-2026-39999 (Apache APISIX jwt-auth JWT algorithm confusion). Tested whether the 3.17.0 alg-match fix can be bypassed, and whether the same confusion reaches consumers configured with asymmetric algorithms other than RS256 (ES256/ECDSA, EdDSA/Ed25519). Result: NO BYPASS. The fix rejects forged HS256 tokens for RS256, ES256, and EdDSA consumers on 3.17.0 with explicit 'algorithm mismatch, expected <alg>' log lines. The ES256/EdDSA cases are alternate triggers (same root cause/sink/entry point/trust boundary) that reproduce the authz_bypass on 3.16.0 only and are covered by the generic fix; they are not distinct variants and do not bypass the fix.",
  "relation": "newer_version_sibling",
  "origin_kind": "pruva_variant",
  "repository": "https://github.com/apache/apisix",
  "submitted_target": {
    "target_kind": "container_image",
    "version": "3.16.0",
    "ref": "apache/apisix:3.16.0-debian",
    "display": "apache/apisix:3.16.0-debian (APISIX 3.16.0, release tag f9c4ee37)"
  },
  "variant_target": {
    "target_kind": "container_image",
    "commit_sha": "9ef2ecab67f652d38365049613610ef649bb4ad0",
    "version": "3.17.0",
    "ref": "apache/apisix:3.17.0-debian",
    "display": "apache/apisix:3.17.0-debian (APISIX 3.17.0, release tag 9ef2ecab; contains fix e4de423f)"
  },
  "same_root_cause_confidence": "high",
  "same_surface_confidence": "high",
  "claimed_surface": "api_remote",
  "validated_surface": "api_remote",
  "required_entrypoint_kind": "endpoint",
  "required_entrypoint_detail": "HTTP request to an APISIX route protected by the jwt-auth plugin, carrying a forged JWT in the Authorization header (or query/cookie). Consumer selected by the token's key claim.",
  "attacker_controlled_input": "JWT header alg value (set to HS256) and HMAC-SHA256 signature computed using the consumer's asymmetric public key PEM (RSA / EC / Ed25519) as the HMAC secret; token payload key claim selects the targeted consumer",
  "trigger_path": "apisix/plugins/jwt-auth.lua find_consumer -> get_auth_secret (returns consumer.public_key for asymmetric alg) -> [fix guard: jwt.header.alg ~= consumer.auth_conf.algorithm] -> apisix/plugins/jwt-auth/parser.lua verify_signature -> alg_verify[self.header.alg] (HS256 -> HMAC-SHA256 with public key as secret)",
  "observed_impact_class": "authz_bypass",
  "exploitability_confidence": "high",
  "evidence_scope": "production_path",
  "runtime_manifest_present": true,
  "end_to_end_target_reached": true,
  "inferred": false,
  "bypass_confirmed": false,
  "distinct_variant_confirmed": false,
  "claim_block_reason": null,
  "blocking_mitigation": "Fix commit e4de423fc583fdf82f47a1dda6c666aa2f2b3dca (PR #13182, APISIX 3.17.0): in apisix/plugins/jwt-auth.lua find_consumer, enforce jwt.header.alg == consumer.auth_conf.algorithm before jwt:verify_signature. Rejects with HTTP 401 and log 'failed to verify jwt: algorithm mismatch, expected <alg>'. The check and alg_verify dispatch both read self.header.alg (set once by resty.jwt load_jwt, no normalization), so no header.alg value can both pass the equality and dispatch HMAC against an asymmetric key. Guard is on the sole path to verify_signature and is generic over all supported consumer algorithms (HS*/RS*/ES*/PS*/EdDSA).",
  "file_path": "apisix/plugins/jwt-auth.lua",
  "line_start": 329,
  "line_end": 340,
  "secondary_anchors": [
    {
      "file_path": "apisix/plugins/jwt-auth/parser.lua",
      "line_start": 225,
      "line_end": 228
    },
    {
      "file_path": "apisix/plugins/jwt-auth.lua",
      "line_start": 271,
      "line_end": 278
    }
  ],
  "review_scope_paths": [
    "apisix/plugins/jwt-auth.lua",
    "apisix/plugins/jwt-auth/parser.lua",
    "apisix/utils/auth.lua",
    "apisix/plugins/multi-auth.lua",
    "t/plugin/jwt-auth.t",
    "t/plugin/jwt-auth-more-algo.t"
  ],
  "tested_candidates": [
    {"id": "V1", "alg": "RS256", "vuln_3_16_0": 200, "fixed_3_17_0": 401, "class": "control"},
    {"id": "V2", "alg": "ES256", "vuln_3_16_0": 200, "fixed_3_17_0": 401, "class": "alternate_trigger_not_distinct"},
    {"id": "V3", "alg": "EdDSA", "vuln_3_16_0": 200, "fixed_3_17_0": 401, "class": "alternate_trigger_not_distinct"}
  ],
  "artifact_refs": {
    "variant_manifest": "bundle/vuln_variant/variant_manifest.json",
    "validation_verdict": "bundle/vuln_variant/validation_verdict.json",
    "runtime_manifest": "bundle/vuln_variant/runtime_manifest.json",
    "repro_log": "bundle/logs/variant_run1.stdout.log",
    "root_cause_equivalence": "bundle/vuln_variant/root_cause_equivalence.json",
    "reproducer": [
      "bundle/vuln_variant/reproduction_steps.sh",
      "bundle/vuln_variant/artifacts/variant_harness.py"
    ]
  }
}
