{"record":{"id":"abc46f86c5edc815","repo":"Pumpkin-MC/Pumpkin","slug":"vine-challenge-nonce-mismatch","errorCode":null,"errorMessage":"Vine challenge nonce mismatch","messagePattern":"Vine challenge nonce mismatch","errorType":"error_code","errorClass":"VineError","httpStatus":null,"severity":"critical","filePath":"crates/pumpkin/src/net/proxy/vine.rs","lineNumber":42,"sourceCode":"#[derive(Error, Debug)]\npub enum VineError {\n    #[error(\"No response data received\")]\n    NoData,\n    #[error(\"Vine response data too short (minimum 89 bytes)\")]\n    DataTooShort,\n    #[error(\"No public key or secret configured for Vine proxy\")]\n    MissingKeyConfig,\n    #[error(\"Invalid Ed25519 public key\")]\n    InvalidPublicKey,\n    #[error(\"Failed to verify Ed25519 signature\")]\n    InvalidSignature,\n    #[error(\"Failed to read forward version\")]\n    FailedReadForwardVersion,\n    #[error(\"Unsupported forwarding version {0}. Expected {1}\")]\n    UnsupportedForwardVersion(i32, i32),\n    #[error(\"Vine timestamp expired or desynchronized: skew of {0}s exceeds limit of {1}s\")]\n    TimestampExpired(i64, i64),\n    #[error(\"Vine challenge nonce mismatch\")]\n    ChallengeMismatch,\n    #[error(\"Missing expected challenge from pending connection\")]\n    MissingChallenge,\n    #[error(\"Failed to read address\")]\n    FailedReadAddress,\n    #[error(\"Failed to parse address\")]\n    FailedParseAddress,\n    #[error(\"Failed to read game profile name\")]\n    FailedReadProfileName,\n    #[error(\"Failed to read game profile UUID\")]\n    FailedReadProfileUUID,\n    #[error(\"Failed to read game profile properties\")]\n    FailedReadProfileProperties,\n}\n\n/// Initiates Vine modern forwarding handshake by sending a `CLoginPluginRequest`\n/// with a unique 16-byte challenge nonce to protect against replay attacks.\npub async fn vine_login(connection: &mut PendingConnection) {","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/Pumpkin-MC/Pumpkin/blob/8d4639e25a57c15e47448ec327c780d41bbf2356/crates/pumpkin/src/net/proxy/vine.rs#L24-L60","documentation":"VineError::ChallengeMismatch is raised when the 16-byte nonce echoed back in the signed Vine payload does not equal the challenge the server generated for this specific login (vine.rs:196-203). The server stored the nonce in PendingConnection.vine_challenge when issuing the login plugin request; a mismatch means the response is stale, replayed, or forged, so the login is rejected.","triggerScenarios":"challenge != expected_challenge in receive_vine_plugin_response: the proxy responded to a different (earlier) login plugin request, an attacker replayed an old signed payload, or the response was routed to the wrong pending connection (message_id collision/mixup).","commonSituations":"Concurrent logins through a buggy proxy mixing up responses between connections; replay attempts against the backend; the proxy caching or reusing responses instead of answering each challenge freshly.","solutions":["Ensure the proxy answers each vine:player_info request with a fresh response signing the exact challenge received","Update the proxy if it caches/reuses forwarding responses across logins","Verify the backend matches responses to connections by message_id correctly and no packets are being cross-delivered","Treat repeated mismatches from one source as an attack and block that source"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// before dispatching the response, confirm a challenge exists for this connection\nfn challenge_present(conn: &PendingConnection) -> bool {\n    conn.vine_challenge.is_some()\n}","typeGuard":null,"tryCatchPattern":"match receive_vine_plugin_response(port, &config, response, Some(expected)) {\n    Err(VineError::ChallengeMismatch) => {\n        tracing::warn!(\"Vine challenge nonce mismatch — possible replay or proxy bug; dropping login\");\n        disconnect(DisconnectReason::ForwardingChallenge);\n    }\n    result => result?,\n}","preventionTips":["Only allow the proxy host to reach the backend so attackers cannot replay payloads","Ensure the proxy signs the exact challenge received per request and never reuses responses","Keep the per-connection nonce stored until the response arrives, then clear it exactly once","Treat repeated mismatches from one IP as an attack signal and rate-limit/block it"],"tags":["security","replay-protection","challenge-response","minecraft"],"backgroundTag":"challenge-mismatch","analyzedSha":"8d4639e25a57c15e47448ec327c780d41bbf2356","analyzedAt":"2026-09-09T15:32:22.916Z","contentChangedAt":"2026-09-09T15:32:22.916Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}