{"id":"CVE-2026-13734","aliases":["EUVD-2026-67946","GHSA-x7q7-fjx9-4vj2"],"status":"published","title":"Zephyr WireGuard mutates peer state before anti-replay check, enabling capture-replay endpoint hijack","description":"Zephyr's WireGuard VPN data-plane receive handler wg_process_data_message() in subsys/net/lib/wireguard/wg_crypto.c validated the anti-replay counter too late. After AEAD decryption of a MESSAGE_TRANSPORT_DATA packet succeeded, the code committed several peer-state changes — update_peer_addr() (endpoint roaming update), the keypair-\u003elast_rx/peer-\u003elast_rx liveness timers, and keypair_update() (promote next→current and destroy the previous keypair) — and only afterward called wg_check_replay(). On a replayed packet the replay check returned -EINVAL, but none of the preceding mutations were rolled back.\n\nThe AEAD tag authenticates content but not freshness, so a replayed-but-authentic transport packet decrypts correctly. An attacker who captures one valid ciphertext off the wire (an on-path or shared-medium observer) can re-inject it from an arbitrary spoofed source address. Reaching the handler requires no credentials: it is driven directly from inbound UDP datagrams via the dispatch in subsys/net/lib/wireguard/wg.c.\n\nBecause the state mutations committed before the replay check, the replay repoints the peer endpoint to the attacker-chosen source address (roaming hijack), redirecting the victim's subsequent outbound tunnel traffic until the legitimate peer's next packet re-corrects it; it also prematurely destroys the previous keypair and refreshes the RX liveness timer. The tunnel payload stays encrypted under the session keypair, so this is an integrity/availability impact (traffic redirection and session disruption), not payload disclosure. The fix moves wg_check_replay() to immediately after a successful decrypt, before any peer-state mutation, matching the WireGuard specification and the Linux reference implementation.","severity":{"version":"3.1","score":6.5,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:H","level":"medium","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-10","score":0.00332,"percentile":0.26688,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":false},"cwes":["CWE-294"],"published":"2026-08-28T20:38:49Z","modified":"2026-10-28T11:07:34Z","products":[{"vendor":"zephyrproject","product":"zephyr"},{"vendor":"zephyrproject-rtos","product":"zephyr"}],"references":[{"url":"https://github.com/zephyrproject-rtos/zephyr/commit/260c32ef9a89824bd25e17170e77aa4b98c84069","tags":["patch","fix"]},{"url":"https://github.com/zephyrproject-rtos/zephyr/security/advisories/GHSA-x7q7-fjx9-4vj2","tags":["advisory"]},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/13xxx/CVE-2026-13734.json","tags":["advisory"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-13734","tags":["advisory"]},{"url":"https://github.com/zephyrproject-rtos/zephyr","tags":["package"]}],"sources":{"cve":[{"id":"CVE-2026-13734","title":"Zephyr WireGuard mutates peer state before anti-replay check, enabling capture-replay endpoint hijack","description":"Zephyr's WireGuard VPN data-plane receive handler wg_process_data_message() in subsys/net/lib/wireguard/wg_crypto.c validated the anti-replay counter too late. After AEAD decryption of a MESSAGE_TRANSPORT_DATA packet succeeded, the code committed several peer-state changes — update_peer_addr() (endpoint roaming update), the keypair-\u003elast_rx/peer-\u003elast_rx liveness timers, and keypair_update() (promote next→current and destroy the previous keypair) — and only afterward called wg_check_replay(). On a replayed packet the replay check returned -EINVAL, but none of the preceding mutations were rolled back.\n\nThe AEAD tag authenticates content but not freshness, so a replayed-but-authentic transport packet decrypts correctly. An attacker who captures one valid ciphertext off the wire (an on-path or shared-medium observer) can re-inject it from an arbitrary spoofed source address. Reaching the handler requires no credentials: it is driven directly from inbound UDP datagrams via the dispatch in subsys/net/lib/wireguard/wg.c.\n\nBecause the state mutations committed before the replay check, the replay repoints the peer endpoint to the attacker-chosen source address (roaming hijack), redirecting the victim's subsequent outbound tunnel traffic until the legitimate peer's next packet re-corrects it; it also prematurely destroys the previous keypair and refreshes the RX liveness timer. The tunnel payload stays encrypted under the session keypair, so this is an integrity/availability impact (traffic redirection and session disruption), not payload disclosure. The fix moves wg_check_replay() to immediately after a successful decrypt, before any peer-state mutation, matching the WireGuard specification and the Linux reference implementation.","status":"published","published":"2026-08-28T20:38:49.617Z","modified":"2026-09-01T12:26:16.293Z","cvss":[{"version":"3.1","score":6.5,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:H","level":"medium","assessor":"cna"}],"cwes":["CWE-294"],"updated_at":"2026-11-02T14:19:49.885652Z"}],"euvd":[{"id":"EUVD-2026-67946","description":"Zephyr's WireGuard VPN data-plane receive handler wg_process_data_message() in subsys/net/lib/wireguard/wg_crypto.c validated the anti-replay counter too late. After AEAD decryption of a MESSAGE_TRANSPORT_DATA packet succeeded, the code committed several peer-state changes — update_peer_addr() (endpoint roaming update), the keypair-\u003elast_rx/peer-\u003elast_rx liveness timers, and keypair_update() (promote next→current and destroy the previous keypair) — and only afterward called wg_check_replay(). On a replayed packet the replay check returned -EINVAL, but none of the preceding mutations were rolled back.\n\nThe AEAD tag authenticates content but not freshness, so a replayed-but-authentic transport packet decrypts correctly. An attacker who captures one valid ciphertext off the wire (an on-path or shared-medium observer) can re-inject it from an arbitrary spoofed source address. Reaching the handler requires no credentials: it is driven directly from inbound UDP datagrams via the dispatch in subsys/net/lib/wireguard/wg.c.\n\nBecause the state mutations committed before the replay check, the replay repoints the peer endpoint to the attacker-chosen source address (roaming hijack), redirecting the victim's subsequent outbound tunnel traffic until the legitimate peer's next packet re-corrects it; it also prematurely destroys the previous keypair and refreshes the RX liveness timer. The tunnel payload stays encrypted under the session keypair, so this is an integrity/availability impact (traffic redirection and session disruption), not payload disclosure. The fix moves wg_check_replay() to immediately after a successful decrypt, before any peer-state mutation, matching the WireGuard specification and the Linux reference implementation.","status":"published","published":"2026-08-28T20:38:49Z","modified":"2026-09-01T12:26:16Z","cvss":[{"version":"3.1","score":6.5,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:H","level":"medium"}],"updated_at":"2026-11-02T18:01:18.76029Z"}],"nvd":[{"id":"CVE-2026-13734","description":"Zephyr's WireGuard VPN data-plane receive handler wg_process_data_message() in subsys/net/lib/wireguard/wg_crypto.c validated the anti-replay counter too late. After AEAD decryption of a MESSAGE_TRANSPORT_DATA packet succeeded, the code committed several peer-state changes — update_peer_addr() (endpoint roaming update), the keypair-\u003elast_rx/peer-\u003elast_rx liveness timers, and keypair_update() (promote next→current and destroy the previous keypair) — and only afterward called wg_check_replay(). On a replayed packet the replay check returned -EINVAL, but none of the preceding mutations were rolled back.\n\nThe AEAD tag authenticates content but not freshness, so a replayed-but-authentic transport packet decrypts correctly. An attacker who captures one valid ciphertext off the wire (an on-path or shared-medium observer) can re-inject it from an arbitrary spoofed source address. Reaching the handler requires no credentials: it is driven directly from inbound UDP datagrams via the dispatch in subsys/net/lib/wireguard/wg.c.\n\nBecause the state mutations committed before the replay check, the replay repoints the peer endpoint to the attacker-chosen source address (roaming hijack), redirecting the victim's subsequent outbound tunnel traffic until the legitimate peer's next packet re-corrects it; it also prematurely destroys the previous keypair and refreshes the RX liveness timer. The tunnel payload stays encrypted under the session keypair, so this is an integrity/availability impact (traffic redirection and session disruption), not payload disclosure. The fix moves wg_check_replay() to immediately after a successful decrypt, before any peer-state mutation, matching the WireGuard specification and the Linux reference implementation.","status":"published","published":"2026-08-28T22:16:46.057Z","modified":"2026-09-01T13:18:10.01Z","cvss":[{"version":"3.1","score":6.5,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:H","level":"medium","assessor":"secondary"}],"cwes":["CWE-294"],"updated_at":"2026-11-02T14:12:42.366888Z"}],"osv":[{"id":"CVE-2026-13734","title":"Zephyr WireGuard mutates peer state before anti-replay check, enabling capture-replay endpoint hijack","description":"Zephyr's WireGuard VPN data-plane receive handler wg_process_data_message() in subsys/net/lib/wireguard/wg_crypto.c validated the anti-replay counter too late. After AEAD decryption of a MESSAGE_TRANSPORT_DATA packet succeeded, the code committed several peer-state changes — update_peer_addr() (endpoint roaming update), the keypair-\u003elast_rx/peer-\u003elast_rx liveness timers, and keypair_update() (promote next→current and destroy the previous keypair) — and only afterward called wg_check_replay(). On a replayed packet the replay check returned -EINVAL, but none of the preceding mutations were rolled back.\n\nThe AEAD tag authenticates content but not freshness, so a replayed-but-authentic transport packet decrypts correctly. An attacker who captures one valid ciphertext off the wire (an on-path or shared-medium observer) can re-inject it from an arbitrary spoofed source address. Reaching the handler requires no credentials: it is driven directly from inbound UDP datagrams via the dispatch in subsys/net/lib/wireguard/wg.c.\n\nBecause the state mutations committed before the replay check, the replay repoints the peer endpoint to the attacker-chosen source address (roaming hijack), redirecting the victim's subsequent outbound tunnel traffic until the legitimate peer's next packet re-corrects it; it also prematurely destroys the previous keypair and refreshes the RX liveness timer. The tunnel payload stays encrypted under the session keypair, so this is an integrity/availability impact (traffic redirection and session disruption), not payload disclosure. The fix moves wg_check_replay() to immediately after a successful decrypt, before any peer-state mutation, matching the WireGuard specification and the Linux reference implementation.","status":"published","published":"2026-08-28T20:38:49.617Z","modified":"2026-10-28T11:07:34.207001063Z","cvss":[{"version":"3.1","score":6.5,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:H","level":"medium"}],"cwes":["CWE-294"],"updated_at":"2026-11-02T15:44:57.354194Z"}]}}
