Feb 25, 2026·6 min read·35 visits
The ENS DNSSEC oracle failed to verify RSA PKCS#1 v1.5 padding, checking only the hash suffix. This allowed attackers to use basic math (cube roots) to forge signatures for TLDs using $e=3$, enabling the theft of domains like `target.cc` on the Ethereum network.
A critical cryptographic oversight in the Ethereum Name Service (ENS) DNSSEC oracle allowed attackers to bypass RSA signature verification. By exploiting a lazy validation implementation in `RSASHA256Algorithm` and `RSASHA1Algorithm` contracts, adversaries could forge valid-looking signatures for specific Top-Level Domains (TLDs) like `.cc` and `.name` that utilize a low public exponent ($e=3$). This flaw essentially permitted the hijacking of ENS domains rooted in these TLDs without possessing the actual DNS private keys.
The Ethereum Name Service (ENS) is the phonebook of the decentralized web, turning arcane hexadecimal addresses into human-readable names like vitalik.eth. But ENS isn't just an island; it builds bridges to the legacy DNS world. If you own example.com, you can claim example.com on ENS. To do this securely, ENS relies on a DNSSEC Oracle—a set of smart contracts that verify the chain of trust from the root DNS keys down to your domain.
This mechanism sounds robust on paper. It uses RSA cryptography, the bedrock of internet security. However, cryptography is brittle. It's not enough to use the right algorithms; you have to implement them with paranoid precision. In CVE-2026-22866, the developers made a classic mistake: they assumed that if the math works out at the end of the equation, the input must be valid.
This vulnerability is a resurrection of a ghost from 2006—Daniel Bleichenbacher's RSA signature forgery. It’s a stark reminder that in the unforgiving world of smart contracts, skipping a few bytes of validation to save gas can result in a total collapse of trust for affected domains.
To understand the exploit, we have to look at how RSA PKCS#1 v1.5 signatures work. When a signer creates a signature, they don't just encrypt the hash of the message. They format a specific block of data:
0x00 0x01 [Padding of 0xFFs] 0x00 [ASN.1 OID] [Hash]
This structure prevents mathematical malleability. A verifier computes $M = S^e \pmod N$ (where $S$ is the signature, $e$ is the public exponent, and $N$ is the modulus). The verifier MUST check that the resulting $M$ matches the strict format above, byte for byte.
Here is where the ENS contracts failed. The implementation of RSASHA256Algorithm and RSASHA1Algorithm performed the modular exponentiation, but then it got lazy. It looked at the result and effectively asked, "Does the last 20 bytes match the hash of the DNS record?" If yes, it returned true.
This is the cryptographic equivalent of authenticating a painting by only looking at the signature in the bottom corner. An attacker doesn't need to paint a masterpiece; they can draw a stick figure (garbage data), as long as they glue a convincing signature (the correct hash) at the very end. When the public exponent is small—like $e=3$, which is used by .cc and .name TLDs—finding a number that cubes to a value ending in a specific suffix is trivial.
Let's look at the vulnerable logic. In the unpatched versions of RSASHA1Algorithm.sol, the verification logic was dangerously concise. It delegated the heavy lifting of RSA recovery but fumbled the check.
function verify(bytes calldata key, bytes calldata data, bytes calldata sig) external view returns (bool) {
// ... key parsing ...
(bool ok, bytes memory result) = RSAVerify.rsarecover(modulus, exponent, sig);
// CRITICAL FLAW: Ignores everything before the last 20 bytes
return ok && SHA1.sha1(data) == result.readBytes20(result.length - 20);
}As you can see, readBytes20(result.length - 20) extracts only the tail of the decrypted message. The padding, the structure, the ASN.1 Object Identifier—all ignored.
The patch, introduced in commit c76c5ad0dc9de1c966443bd946fafc6351f87587, rips out this naive check and replaces it with a rigorous validation library, RSAPKCS1Verify. The new logic explicitly walks through the decrypted byte array:
0x00 0x01.0xFF.0x00 byte after the padding.This forces the attacker to generate a signature that, when cubed, matches the entire block, which requires breaking RSA itself.
So, how does a hacker exploit this? We need to forge a signature $S$ for a malicious DNS record (claiming we own google.cc, for example). The target TLD .cc uses a public key with exponent $e=3$.
Since the contract only checks the suffix, we need to find an integer $S$ such that: $S^3 \equiv \text{Garbage} \ || \ \text{TargetHash} \pmod N$
If we can make $S^3$ end with the TargetHash, the contract accepts it. Because we don't care about the "Garbage" part (the higher-order bytes), we aren't constrained by the modulus $N$ in the same way a legitimate signer is. We can treat this as finding a cube root in modular arithmetic over a power of 2, specifically $2^{hash_bits}$.
Using Hensel lifting, we can iteratively construct the root bit by bit (or byte by byte). Here is the conceptual attack flow:
H = SHA256(MaliciousDNSData).The oracle computes $x^3$, sees the result ends in $H$, ignores the fact that the rest of the result is mathematical noise, and hands over the domain.
While the CVSS score sits at a seemingly low 2.7 (likely due to the high complexity of setting up the DNSSEC environment and the limitation to specific TLDs), the functional impact is severe for the affected zones.
An attacker successfully exploiting this could claim ownership of any domain under TLDs that use $e=3$ for their Key Signing Keys (KSK) or Zone Signing Keys (ZSK). Known vulnerable TLDs include .cc and .name.
Imagine an attacker claiming exchange.cc on ENS and setting the resolution address to a wallet they control. Users trusting ENS to resolve that domain would be sending funds directly to the attacker. It undermines the core promise of ENS: that it is a secure, trustless naming system. The vulnerability allows for a complete bypass of the DNS ownership proof for these specific zones.
For developers and integrators running their own ENS infrastructure or forks, the path is clear: Upgrade immediately.
The fix is available in ens-contracts versions following 1.6.2. If you are utilizing the RSASHA256Algorithm or RSASHA1Algorithm contracts directly:
RSAPKCS1Verify.sol.DNSSECImpl configuration to point to these new algorithm verifiers via setAlgorithm.This vulnerability highlights a broader lesson for Solidity developers: Never roll your own crypto verification logic without strictly adhering to the RFCs. The "happy path" is not enough. You must validate the entire structure of cryptographic primitives, or the math will find a way to bite you.
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N/E:U| Product | Affected Versions | Fixed Version |
|---|---|---|
ens-contracts ENS Domains | <= 1.6.2 | 1.6.3 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-347 |
| CVSS Score | 2.7 (Low) |
| Attack Vector | Network |
| Key Factor | RSA Public Exponent e=3 |
| Exploit Status | PoC Available |
| Impact | Domain Hijacking / Signature Forgery |
The product verifies a cryptographic signature but does not verify or incorrectly verifies that the signature is valid.
A DNS-rebinding Time-of-Check to Time-of-Use (TOCTOU) vulnerability exists in the mcp-atlassian server before version 0.17.0. The server processes unauthenticated client-supplied URLs via custom headers, validating the destination IP but failing to pin the resolved address before connecting. This allows remote adjacent-network attackers to achieve Server-Side Request Forgery (SSRF) and access restricted resources or cloud metadata services.
A high-severity denial-of-service vulnerability in @libp2p/gossipsub prior to version 16.0.0 allows unauthenticated remote attackers to trigger event loop starvation and complete node freeze by exploiting unbounded protobuf decoding limits and nested synchronous array iteration loops.
CVE-2026-49858 is a vulnerability in API Platform Core's JSON:API and HAL item normalizers where conditionally secured attributes are cached globally in memory. When deployed in long-running PHP execution environments such as FrankenPHP worker mode, Swoole, or RoadRunner, this persistent caching bypasses property-level security constraints, allowing unprivileged users to access sensitive, unauthorized fields cached during privileged requests.
CVE-2026-5078 is a log injection vulnerability in Morgan, the widely deployed Node.js HTTP request logging middleware. The vulnerability arises because the ':remote-user' logging token decodes and outputs basic authentication usernames containing control characters, such as Carriage Return (CR) and Line Feed (LF), without sanitization. An unauthenticated attacker can bypass native HTTP header parsers by Base64-encoding CRLF sequences in the Authorization header. When Morgan logs the request, these control characters force newlines in the log stream, enabling log forging, SIEM evasion, and system activity spoofing.
CVE-2026-48861 is a client-side HTTP request-line CRLF (Carriage Return Line Feed) injection vulnerability in the popular Elixir HTTP client library, Mint. The vulnerability permits HTTP Request Splitting and HTTP Request Smuggling when an application forwards untrusted, attacker-controlled inputs to Mint's HTTP client requests as either the HTTP request method or target. By embedding CRLF characters within these parameters, an attacker can terminate the request line prematurely, inject malicious headers, or pipeline entirely independent requests. These smuggled requests are then processed by upstream or downstream proxy servers as separate HTTP queries on the same TCP connection. While Mint version 1.7.0 introduced target validation to secure the request target, the HTTP request method parameter remained completely unvalidated. This flaw allows attackers to bypass routing filters, access restricted internal APIs, or poison HTTP caches under default configurations.
An Inconsistent Interpretation of HTTP Requests (HTTP Request/Response Smuggling) vulnerability in the Elixir Mint HTTP client allows attacker-controlled HTTP/1 servers to desynchronize response framing on shared connections due to over-lenient parsing of sign-prefixed Content-Length headers.