{
  "claim_outcome": "variant_confirmed_no_bypass",
  "variant_confirmed": true,
  "bypass_confirmed": false,
  "claim_block_reason": null,
  "summary": "Distinct alternate triggers confirmed on the vulnerable build (7.146.25): POST /access/api/v1/registry/join/router (HTTP 200, admin service token via wrapper JWT), the same endpoint with ?override=true, and POST /access/api/v1/registry/join with explicit kid=sha256('') (HTTP 201). Each yielded a never-expiring scp=admin service token and full admin takeover with zero credentials. Identical attacks against fixed 7.146.38 were all rejected with HTTP 400, so the shipped fix covers every variant found - no bypass.",
  "validated_surface": "api_remote",
  "evidence_scope": "production_path",
  "claimed_impact_class": "authz_bypass",
  "observed_impact_class": "authz_bypass",
  "exploitability_confidence": "high",
  "attacker_controlled_input": "Unauthenticated HS256 join JWT signed with the publicly derivable blank-join-key HMAC secret (32 x 0x20), attacker-chosen service_id/node_id/node_ip/skip_node_registration/iat/kid claims",
  "trigger_path": "RegistryNoAuthResource.joinRouter -> JoinServiceImpl.joinRouter -> getValidatedJwtToken -> getJoinKey -> JoinKeyAccess.getTokenSignatureVerifiers (blank additional join key kid=sha256('')) -> registerWith -> ServiceTokenProviderImpl scope=admin token (wrapped in join-key-signed JWT 'token' claim); variant C: kid-selected branch of getRelevantJoinKeys via POST /v1/registry/join",
  "end_to_end_target_reached": true,
  "exploit_chain_demonstrated": true,
  "blocking_mitigation": "Fix in Access 7.176.28 / Artifactory 7.146.38: JoinKeyHashPair rejects null/blank join keys and JoinKeyAccess.tryResolveJoinKeys filters blank entries; both no-auth endpoints and both key-selection branches funnel through this patched choke point (JoinServiceImpl/RegistryNoAuthResource are byte-identical across versions; JoinServiceImpl is the sole consumer of the join-key verification sink).",
  "variants_tested": [
    {"id": "router", "entrypoint": "POST /access/api/v1/registry/join/router", "vuln_result": "exploited (200, scp=admin, admin takeover)", "fixed_result": "blocked (400)"},
    {"id": "router-override", "entrypoint": "POST /access/api/v1/registry/join/router?override=true", "vuln_result": "exploited (200, scp=admin, admin takeover)", "fixed_result": "blocked (400)"},
    {"id": "join-kid", "entrypoint": "POST /access/api/v1/registry/join with kid=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "vuln_result": "exploited (201, scp=admin, admin takeover)", "fixed_result": "blocked (400)"}
  ],
  "ruled_out": [
    "Other sink consumers: constant-pool scan shows JoinServiceImpl is the only consumer of JoinKeyAccess.getTokenSignatureVerifiers/JoinKeyUtils.getSigningKey; JoinService referenced only by RegistryNoAuthResource and TopologyServiceImpl (internal) - no gRPC or other REST path exists",
    "Whitespace-only additionalJoinKeys entries: collapse to the same blank key after trim and require admin config access (no trust-boundary crossing)",
    "Short/guessable non-blank hex join keys: deterministic pkcs7 padding remains, but only via admin-controlled configuration - out of scope for this CVE's zero-credential boundary"
  ],
  "inferred": false,
  "evidence": {
    "vuln_transcripts": ["artifacts/variant_http/vuln_router.json", "artifacts/variant_http/vuln_router-override.json", "artifacts/variant_http/vuln_join-kid.json"],
    "fixed_transcripts": ["artifacts/variant_http/fixed_router.json", "artifacts/variant_http/fixed_router-override.json", "artifacts/variant_http/fixed_join-kid.json"],
    "log": "logs/vuln_variant/reproduction_steps.log",
    "static_analysis": "vuln_variant/decomp/"
  }
}
