CVE-2026-5479: Verified Reproduction
CVE-2026-5479: wolfSSL: EVP ChaCha20-Poly1305 decryption returns plaintext without verifying authentication tag
CVE-2026-5479 is verified against wolfssl · source. Affected versions: < 5.9.1. Fixed in 5.9.1. This high reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00172.
What Is CVE-2026-5479?
CVE-2026-5479 (CWE-354) is a high-severity vulnerability in wolfSSL's EVP compatibility API where ChaCha20-Poly1305 decryption returns plaintext to the caller without verifying that the Poly1305 authentication tag matches, silently defeating the AEAD's authenticity guarantee. Pruva reproduced it (reproduction REPRO-2026-00172).
CVE-2026-5479 Severity & CVSS Score
CVE-2026-5479 is rated high severity, with a CVSS base score of 8.1 out of 10.
High — serious impact or readily exploitable. Prioritize remediation.
Affected wolfssl Versions
wolfssl · source versions < 5.9.1 are affected.
How to Reproduce CVE-2026-5479
pruva-verify REPRO-2026-00172 curl -O https://www.pruva.dev/api/v1/reproductions/REPRO-2026-00172/artifacts/bundle/repro/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh Proof of Reproduction for CVE-2026-5479
- Vulnerable
wolfSSL v5.9.0-stable - Fixed
wolfSSL v5.9.1-stable
How the agent worked
Root Cause and Exploit Chain for CVE-2026-5479
CVE-2026-5479 is an integrity-check bypass (CWE-354) in wolfSSL's EVP compatibility layer for ChaCha20-Poly1305 AEAD decryption. In wolfSSL_EVP_CipherFinal (wolfcrypt/src/evp.c), the decrypt path for WC_CHACHA20_POLY1305_TYPE calls wc_ChaCha20Poly1305_Final() to compute the Poly1305 authentication tag, which overwrites the expected tag previously stored in ctx->authTag by EVP_CIPHER_CTX_ctrl(EVP_CTRL_AEAD_SET_TAG). No comparison between the computed tag and the expected tag is ever performed, so any forged or mismatched tag is silently accepted. This completely nullifies the authenticity guarantee of the AEAD cipher, allowing an active network adversary to supply modified ciphertext that the application will treat as integrity-validated.
- Package/component affected: wolfSSL
libwolfssl, specifically the EVP compatibility API (wolfSSL_EVP_CipherFinal) for ChaCha20-Poly1305 decryption. - Affected versions: wolfSSL
< 5.9.1(last vulnerable release tag:v5.9.0-stable). - Fixed versions:
5.9.1(commit1faddd640). - Risk level: High (CVSS 3.1: 8.1, CVSS 4.0: 7.6).
- Consequences: Any consumer using the standard EVP decrypt pattern (
EVP_DecryptInit_ex→EVP_DecryptUpdate→EVP_CIPHER_CTX_ctrl(SET_TAG)→EVP_DecryptFinal_ex) will accept attacker-modified ciphertext as authentic. This enables message forgery in protocols that rely on ChaCha20-Poly1305 via the wolfSSL EVP API (e.g., TLS record-layer AEAD when used through the EVP abstraction).
Root Cause
The bug is located in wolfcrypt/src/evp.c inside the wolfSSL_EVP_CipherFinal function, specifically in the WC_CHACHA20_POLY1305_TYPE branch (lines ~1502–1515 in v5.9.0-stable).
On the decrypt path (!ctx->enc), the code does:
case WC_CHACHA20_POLY1305_TYPE:
if (wc_ChaCha20Poly1305_Final(&ctx->cipher.chachaPoly,
ctx->authTag) != 0) {
WOLFSSL_MSG("wc_ChaCha20Poly1305_Final failed");
return WOLFSSL_FAILURE;
}
else {
*outl = 0;
return WOLFSSL_SUCCESS;
}
break;
wc_ChaCha20Poly1305_Final() computes the Poly1305 tag and writes it into ctx->authTag, overwriting the expected tag that was set earlier via EVP_CTRL_AEAD_SET_TAG. The code then unconditionally returns WOLFSSL_SUCCESS without ever comparing the computed tag to the expected tag.
The fix (commit 1faddd640edc8195c1fb7cb3904876e434ecab87, PR #10102) mirrors the existing AES-GCM branch: it saves the expected tag before calling _Final(), then uses wc_ChaCha20Poly1305_CheckTag() to verify the computed tag against the saved expected tag on the decrypt path. If the tags do not match, WOLFSSL_FAILURE is returned.
Diff excerpt from the fix:
+ {
+ byte computedTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE];
+ if (!ctx->enc) {
+ XMEMCPY(computedTag, ctx->authTag, sizeof(computedTag));
+ }
if (wc_ChaCha20Poly1305_Final(&ctx->cipher.chachaPoly,
ctx->authTag) != 0) {
WOLFSSL_MSG("wc_ChaCha20Poly1305_Final failed");
return WOLFSSL_FAILURE;
}
- else {
- *outl = 0;
- return WOLFSSL_SUCCESS;
+ if (!ctx->enc) {
+ int tagErr = wc_ChaCha20Poly1305_CheckTag(computedTag,
+ ctx->authTag);
+ ForceZero(computedTag, sizeof(computedTag));
+ if (tagErr != 0) {
+ WOLFSSL_MSG("ChaCha20-Poly1305 tag mismatch");
+ return WOLFSSL_FAILURE;
+ }
}
- break;
+ *outl = 0;
+ return WOLFSSL_SUCCESS;
+ }
+ break;
Reproduction Steps
Run
repro/reproduction_steps.sh. This self-contained script:- Builds vulnerable wolfSSL (
v5.9.0-stable) into/tmp/wolfssl-vulnand fixed wolfSSL (v5.9.1-stable) into/tmp/wolfssl-fixed(or uses pre-built installations if present). - Compiles
repro/aead_tag_check.cagainst both libraries. - Executes the test harness against each build.
- Generates
logs/runtime_manifest.jsonwith concrete API return values. - Prints a verdict based on observable cryptographic behavior.
- Builds vulnerable wolfSSL (
What the script does:
- Encrypts a known plaintext under ChaCha20-Poly1305 with a fixed key/nonce.
- Performs three tamper attacks on the ciphertext/tag pair:
- Replaces the 16-byte authentication tag with all zeros.
- Replaces the tag with a random bad tag (
0xABrepeated). - Flips the first byte of the ciphertext while keeping the original tag.
- Decrypts each tampered pair using the standard EVP API (
EVP_DecryptInit_ex→EVP_DecryptUpdate→EVP_CIPHER_CTX_ctrl(SET_TAG)→EVP_DecryptFinal_ex). - Captures the return value of
EVP_DecryptFinal_exand the decrypted bytes.
Expected evidence:
- Vulnerable build:
EVP_DecryptFinal_exreturns1(success) for all three tampered inputs, and the decrypted plaintext is delivered to the caller (either matching the original plaintext for forged tags, or producing modified bytes for flipped ciphertext). - Fixed build:
EVP_DecryptFinal_exreturns0(failure) for all three tampered inputs, correctly rejecting the forgeries.
- Vulnerable build:
Evidence
Vulnerable run log:
logs/vulnerable_output.txt- Excerpt (Test 1 — zeroed tag):
EVP_DecryptUpdate ret=1, EVP_DecryptFinal_ex ret=1 Decrypted: 54686520717569636b2062726f776e20666f78206a756d7073206f7665720000 Plaintext match: YES VULNERABLE: YES (Final succeeded with forged tag) - Excerpt (Test 3 — flipped ciphertext byte):
EVP_DecryptUpdate ret=1, EVP_DecryptFinal_ex ret=1 Decrypted: ab686520717569636b2062726f776e20666f78206a756d7073206f7665720000 Plaintext match: NO VULNERABLE: YES (Final succeeded with modified ciphertext)
- Excerpt (Test 1 — zeroed tag):
Fixed run log:
logs/fixed_output.txt- Excerpt (Test 1 — zeroed tag):
EVP_DecryptUpdate ret=1, EVP_DecryptFinal_ex ret=0 Decrypted: 54686520717569636b2062726f776e20666f78206a756d7073206f7665720000 Plaintext match: YES VULNERABLE: NO (Final rejected forged tag)
- Excerpt (Test 1 — zeroed tag):
Runtime manifest:
logs/runtime_manifest.json- Contains structured JSON with the exact
EVP_DecryptFinal_exreturn codes for each tamper strategy on both the vulnerable and fixed builds.
- Contains structured JSON with the exact
Environment:
- Host:
x86_64-pc-linux-gnu - Compiler:
gcc - wolfSSL configure flags:
--enable-chacha --enable-poly1305 --enable-aesgcm --enable-opensslextra --disable-shared --enable-static --enable-debug CFLAGS='-g -O0'
- Host:
Recommendations / Next Steps
- Upgrade immediately to wolfSSL
5.9.1or later, which contains commit1faddd640. - Verify tag-check coverage in any custom fork or wrapper around
wolfSSL_EVP_CipherFinalfor ChaCha20-Poly1305; the missingwc_ChaCha20Poly1305_CheckTag()call is the root cause. - Regression testing: Add the exact tamper strategies from this reproduction (zeroed tag, random tag, flipped ciphertext byte) to the project's EVP cipher unit tests. The upstream fix already includes a negative test for an all-zero forged tag.
- Audit other AEAD paths: Review
wolfSSL_EVP_CipherFinalfor any other AEAD ciphers that might lack tag verification. The AES-GCM branch already had the correct pattern; ChaCha20-Poly1305 was the outlier.
Additional Notes
- Idempotency:
repro/reproduction_steps.shwas executed twice consecutively on the same host and produced identical results (exit code 0,VERDICT: CONFIRMED). - Edge cases: The reproduction uses the standard
EVP_DecryptInit_ex+EVP_DecryptUpdate+EVP_DecryptFinal_expattern. The streamingEVP_CipherUpdate/EVP_CipherFinalequivalents are also affected because they route through the samewolfSSL_EVP_CipherFinalcode path. - Limitations: The reproduction requires building wolfSSL from source with
--enable-chacha --enable-poly1305 --enable-opensslextra. On systems without a C compiler or git, the script will exit with a descriptive error rather than a false positive.
CVE-2026-5479 Reproduction Transcript
The agent's step-by-step process — every tool call, every handoff, the moment the exploit fired.
Full session Replay every step — scrub the timeline or play it back.
Unknown error
Unknown error
Artifacts and Evidence for CVE-2026-5479
Scripts, logs, diffs, and output captured during the reproduction.
How to Fix CVE-2026-5479
Upgrade wolfssl · source to 5.9.1 or later.
FAQ: CVE-2026-5479
How does the CVE-2026-5479 tag-bypass attack work?
Which wolfSSL versions are affected by CVE-2026-5479, and where is it fixed?
How severe is CVE-2026-5479?
How can I reproduce CVE-2026-5479?
References for CVE-2026-5479
Authoritative sources for CVE-2026-5479 — official vulnerability databases and the upstream advisory. Pruva's reproduction verifies the issue firsthand; these are the primary records to corroborate it.