## Ticket: CVE-2026-5479 — wolfSSL EVP ChaCha20-Poly1305 authentication-tag verification failure

**CVE**: CVE-2026-5479 | **CWE-354** (Improper Validation of Integrity Check Value) | **CVSS 3.1**: 8.1 (High) | **CVSS 4.0**: 7.6 (High)
**Vendor / Product**: wolfSSL — `libwolfssl` EVP compatibility layer
**Repository**: https://github.com/wolfSSL/wolfssl
**Affected**: `< 5.9.1` | **Fixed**: `5.9.1`
**Upstream PR**: https://github.com/wolfSSL/wolfssl/pull/10102
**NVD**: https://nvd.nist.gov/vuln/detail/CVE-2026-5479
**Cited on**: https://red.anthropic.com/2026/cvd/

### Impact

wolfSSL's EVP compatibility API for ChaCha20-Poly1305 decryption (`wolfSSL_EVP_CipherFinal` on the AEAD path) returns the decrypted plaintext to the caller **without** verifying that the Poly1305 authentication tag matches. The AEAD's authenticity guarantee — the entire point of using an *authenticated* cipher — silently disappears.

Concretely: a consumer that uses the EVP API in the standard pattern (`EVP_DecryptInit_ex` → `EVP_DecryptUpdate` → `EVP_DecryptFinal_ex`, or the streaming `EVP_CipherUpdate`/`EVP_CipherFinal` equivalents) and ends with a tag check sees `EVP_DecryptFinal_ex` return success on every input — including ciphertexts with a tag that doesn't match, including ciphertexts where individual bytes have been flipped. Any active network attacker on the wire (or anyone supplying ciphertext to such a consumer) can forge messages that the application will treat as integrity-validated. Network adjacency (CVSS `AV:A`) reflects the typical deployment where wolfSSL EVP is used as a TLS-record / packet-AEAD primitive, not the strict TLS handshake path.

### Affected / Fixed

| | Version |
|--|--|
| **Vulnerable** | wolfSSL `< 5.9.1` (last vulnerable tag: `v5.9.0-stable`) |
| **Fixed** | `5.9.1` (PR https://github.com/wolfSSL/wolfssl/pull/10102) |

### Where the patch lives

```
git clone https://github.com/wolfSSL/wolfssl external/wolfssl
cd external/wolfssl
git log --oneline v5.9.0-stable..v5.9.1-stable -- wolfcrypt/src/evp.c | head
git show <fix commit> -- wolfcrypt/src/evp.c
```

The fix lives in `wolfcrypt/src/evp.c` inside the ChaCha20-Poly1305 branch of `wolfSSL_EVP_CipherFinal`, where the tag-comparison step was either missing or short-circuited.

### Reproduction plan

1. Build vulnerable wolfSSL (`v5.9.0-stable`) into `/tmp/wolfssl-vuln`:
   ```
   git clone https://github.com/wolfSSL/wolfssl external/wolfssl-vuln && cd external/wolfssl-vuln
   git checkout v5.9.0-stable
   ./autogen.sh
   ./configure --enable-chacha --enable-poly1305 --enable-opensslextra \
       --disable-shared --enable-static --enable-debug \
       CFLAGS='-fsanitize=address -g -O0' \
       --prefix=/tmp/wolfssl-vuln
   make -j && make install
   ```
   Repeat at `v5.9.1-stable` into `/tmp/wolfssl-fixed`.

2. Write a small C test program (`repro/aead_tag_check.c`) that uses the EVP compatibility API to:
   1. Encrypt a known plaintext under ChaCha20-Poly1305 with a fixed key + nonce, capture ciphertext + tag.
   2. Tamper: zero out the 16-byte tag, OR flip a byte in the ciphertext.
   3. Decrypt the tampered (ciphertext, tag) pair using `EVP_DecryptInit_ex(EVP_chacha20_poly1305())` → `EVP_DecryptUpdate` → `EVP_CIPHER_CTX_ctrl(SET_TAG)` → `EVP_DecryptFinal_ex`.
   4. Print the return value of `EVP_DecryptFinal_ex` and the recovered plaintext.

3. Compile the test against each lib and run:
   ```
   cc repro/aead_tag_check.c \
       -I/tmp/wolfssl-vuln/include -L/tmp/wolfssl-vuln/lib -lwolfssl \
       -fsanitize=address -o /tmp/aead-vuln
   cc repro/aead_tag_check.c \
       -I/tmp/wolfssl-fixed/include -L/tmp/wolfssl-fixed/lib -lwolfssl \
       -fsanitize=address -o /tmp/aead-fixed

   LD_LIBRARY_PATH=/tmp/wolfssl-vuln/lib  /tmp/aead-vuln
   LD_LIBRARY_PATH=/tmp/wolfssl-fixed/lib /tmp/aead-fixed
   ```
   - Vulnerable build: `EVP_DecryptFinal_ex` returns 1 (success) on the tampered input; plaintext is delivered.
   - Fixed build: `EVP_DecryptFinal_ex` returns ≤0 (failure); no plaintext delivered.

4. To strengthen evidence, run both with multiple tamper strategies (tag zeroed, tag random, last ciphertext byte flipped, first ciphertext byte flipped) and confirm the vulnerable build accepts ALL of them while the fixed build rejects each.

### Expected reproduction artifacts

- `repro/reproduction_steps.sh` — builds vuln + fixed wolfSSL, compiles the EVP test against each, runs the tampering harness, captures stdout/stderr from both.
- `repro/aead_tag_check.c` — the small EVP test harness.
- `repro/validation_verdict.json` — `confirmed` only if (a) the vulnerable build returns success and plaintext for a tampered ciphertext/tag, AND (b) the fixed build returns failure on the same input.
- `logs/vulnerable_output.txt` — vulnerable run output (success + plaintext on tamper).
- `logs/fixed_output.txt` — fixed run output (failure on tamper).
- `repro/rca_report.md` — RCA explaining the missing/short-circuited tag check in `wolfSSL_EVP_CipherFinal` for ChaCha20-Poly1305.
