Skip to content

Security Advisory: Go Template and Rust/WASM Implementation Bugs

High
nadimkobeissi published GHSA-q6mw-qh5x-m2p8 Feb 23, 2026

Package

No package listed

Affected versions

<1.0.6

Patched versions

1.0.6

Description

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:

  1. 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.

  2. Public Key Validation Panic (Go): validatePublicKey() called panic() on encountering a forbidden key instead of returning an error, allowing remote denial of service.

  3. 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.

  4. 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.

Severity

High

CVE ID

No known CVE

Weaknesses

No CWEs