Date: 2026-02-23
Affected components: Generated Go, Rust and WASM implementations (depending on bug)
Fixed in: Noise Explorer 1.0.6
Affected Component
Noise Explorer versions ≤ 1.0.6
Summary
Multiple bugs were discovered in Noise Explorer's code generation templates affecting Go, Rust, and WebAssembly implementations:
-
Truncated Forbidden Curve Value (Go): The last byte of the 12th forbidden Curve25519 point was truncated from 255 to 25, causing the Go template to fail to reject a known small-order point.
-
Public Key Validation Panic (Go): validatePublicKey() called panic() on encountering a forbidden key instead of returning an error, allowing remote denial of service.
-
Fixed-Size Buffer Overflow in decrypt_and_hash (Rust/WASM): A hardcoded 2048-byte buffer caused a panic when processing handshake messages with payloads exceeding 2048 bytes, allowing remote denial of service.
-
Public Key Validation Bypass in Key::generate_public_key (Rust/WASM): The method constructed PublicKey values directly, bypassing from_bytes() forbidden curve value validation.
Vulnerability Details
Bug #1: Truncated Forbidden Curve Value
The Go template 3utils.go listed the 12th forbidden Curve25519 small-order point with its final byte as 25 instead of 255. The correct value is 0xdbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff. This caused all generated Go implementations to accept this specific low-order point as a valid public key, potentially enabling small-subgroup key recovery attacks against the local party's static or ephemeral private key.
Bug #2: Public Key Validation Panic
The Go template 3utils.go function validatePublicKey() called panic("Invalid public key") when a forbidden value was detected. Since an attacker controls the public key bytes sent during a handshake, any remote party could crash the process by sending a forbidden Curve25519 point. The function now returns false, which existing callers already handle correctly.
Bug #3: Fixed-Size Buffer in decrypt_and_hash
The Rust and WASM templates 5state.rs used a fixed [u8; 2048] buffer to preserve ciphertext before decryption for hash chaining. The maximum message size allowed by the protocol is 65535 bytes. If a handshake message payload exceeded 2048 bytes, the copy into this buffer caused an index-out-of-bounds panic, enabling remote denial of service. The buffer has been replaced with a dynamically-sized Vec<u8>.
Bug #4: Public Key Validation Bypass
The Rust template Key::generate_public_key() and the WASM template Key::generate_public_key() constructed PublicKey structs by directly setting the k field, bypassing the PublicKey::from_bytes() method that checks against forbidden Curve25519 values. These methods now route through from_bytes().
Impact
- Loss of static or ephemeral private key confidentiality via small-subgroup attack (Bug #1)
- Remote denial of service via process crash (Bugs #2, #3)
- Weakened defense-in-depth against invalid public key acceptance (Bug #4)
Remediation
Regenerate all Go, Rust, and WebAssembly implementations using the patched version of Noise Explorer or update generated source files from the repository.
Credit
These bugs were discovered internally by Nadim Kobeissi during a code review of many-years-old code.
Date: 2026-02-23
Affected components: Generated Go, Rust and WASM implementations (depending on bug)
Fixed in: Noise Explorer 1.0.6
Affected Component
Noise Explorer versions ≤ 1.0.6
Summary
Multiple bugs were discovered in Noise Explorer's code generation templates affecting Go, Rust, and WebAssembly implementations:
Truncated Forbidden Curve Value (Go): The last byte of the 12th forbidden Curve25519 point was truncated from
255to25, causing the Go template to fail to reject a known small-order point.Public Key Validation Panic (Go):
validatePublicKey()calledpanic()on encountering a forbidden key instead of returning an error, allowing remote denial of service.Fixed-Size Buffer Overflow in
decrypt_and_hash(Rust/WASM): A hardcoded 2048-byte buffer caused a panic when processing handshake messages with payloads exceeding 2048 bytes, allowing remote denial of service.Public Key Validation Bypass in
Key::generate_public_key(Rust/WASM): The method constructedPublicKeyvalues directly, bypassingfrom_bytes()forbidden curve value validation.Vulnerability Details
Bug #1: Truncated Forbidden Curve Value
The Go template
3utils.golisted the 12th forbidden Curve25519 small-order point with its final byte as25instead of255. The correct value is0xdbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff. This caused all generated Go implementations to accept this specific low-order point as a valid public key, potentially enabling small-subgroup key recovery attacks against the local party's static or ephemeral private key.Bug #2: Public Key Validation Panic
The Go template
3utils.gofunctionvalidatePublicKey()calledpanic("Invalid public key")when a forbidden value was detected. Since an attacker controls the public key bytes sent during a handshake, any remote party could crash the process by sending a forbidden Curve25519 point. The function now returnsfalse, which existing callers already handle correctly.Bug #3: Fixed-Size Buffer in
decrypt_and_hashThe Rust and WASM templates
5state.rsused a fixed[u8; 2048]buffer to preserve ciphertext before decryption for hash chaining. The maximum message size allowed by the protocol is 65535 bytes. If a handshake message payload exceeded 2048 bytes, the copy into this buffer caused an index-out-of-bounds panic, enabling remote denial of service. The buffer has been replaced with a dynamically-sizedVec<u8>.Bug #4: Public Key Validation Bypass
The Rust template
Key::generate_public_key()and the WASM templateKey::generate_public_key()constructedPublicKeystructs by directly setting thekfield, bypassing thePublicKey::from_bytes()method that checks against forbidden Curve25519 values. These methods now route throughfrom_bytes().Impact
Remediation
Regenerate all Go, Rust, and WebAssembly implementations using the patched version of Noise Explorer or update generated source files from the repository.
Credit
These bugs were discovered internally by Nadim Kobeissi during a code review of many-years-old code.