RECONINTEL
◄ ALL RESEARCH
SEPTEMBER 18, 2026CVSS 8.8 · STACK OVERFLOW · GNUTLS BUILDS ONLY10 MIN READ

Same Source, Two Builds, One Crash: The PJSIP GnuTLS Certificate Overflow (CVE-2026-57163)

PJSIP — the SIP stack inside Asterisk, FreePBX and a long tail of VoIP software — has a stack buffer overflow in how it reads a TLS peer certificate. A malicious server presents a certificate with one oversized Subject Alternative Name, and a connecting client overflows a 256-byte buffer on its own stack while extracting the cert's details, before the connection ever reaches the SIP layer. The twist that makes CVE-2026-57163 worth a close look: whether a given build is vulnerable is decided by a single ./configure flag chosen at compile time. We built pjproject 2.17 two ways from the same source — once against GnuTLS, once against OpenSSL — pointed both at the same malicious certificate, and only the GnuTLS build crashed — and the builds most people run, including Asterisk and FreePBX as shipped, use the other one.

Reproduction of CVE-2026-57163 against pjproject 2.17. A malicious TLS certificate with one 400-byte SubjectAltName entry: the GnuTLS build crashes with an AddressSanitizer stack-buffer-overflow (WRITE of size 400) in tls_cert_get_info at ssl_sock_gtls.c line 1022, reached via ssl_update_certs_info and on_handshake_complete; the OpenSSL build handshakes cleanly with no crash; a benign short-SAN cert does not crash the GnuTLS build; and the GnuTLS build with fix commit c4a151a applied no longer crashes.

Real reproduction against pjproject 2.17 (the latest release). The same client, the same malicious certificate: the --with-gnutls build takes a stack-buffer-overflow in tls_cert_get_info; the OpenSSL build handshakes cleanly; a benign short-SAN cert is harmless even on GnuTLS; and the GnuTLS build with fix c4a151a applied no longer crashes.

The Vulnerability

CVE-2026-57163 is CWE-121 (Stack-based Buffer Overflow) in tls_cert_get_info() in pjlib/src/pj/ssl_sock_gtls.c — the GnuTLS TLS backend. The function extracts a peer certificate's fields into a pj_ssl_cert_info structure. To enumerate the certificate's Subject Alternative Names, it loops over them with a 256-byte output buffer:

// pjlib/src/pj/ssl_sock_gtls.c  (pjproject <= 2.17)
char buf[512] = { 0 };
size_t len = sizeof(buf);            // len = 512
...
char out[256] = { 0 };               // the SAN output buffer: 256 bytes
while (gnutls_x509_crt_get_subject_alt_name(cert, seq, out, &len, NULL)
       != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
{
    seq++;                           // len is never reset -> still 512
}

The bug is a stale size argument. len is initialised to sizeof(buf) (512) near the top of the function and used by earlier getters. By the time the SAN-counting loop runs, len still holds 512 — but the buffer it now points at, out, is only 256 bytes. gnutls_x509_crt_get_subject_alt_name() trusts the caller's stated capacity, so a SAN entry between 257 and 512 bytes is written straight past the end of the 256-byte stack buffer. The populate loop lower in the same function does it correctly (len = sizeof(out) - 1 each iteration); only the counting loop was missed.

This runs when pjproject extracts the peer certificate's details at handshake completion — before the connection is handed to the SIP layer, and regardless of whether the certificate ultimately passes trust verification. A self-signed, untrusted certificate triggers it just the same, because the overflow happens while the bytes are being read, before anything decides to accept or reject them. That is what makes it pre-authentication: no SIP credentials, no trusted certificate, nothing but a TCP connection and a crafted cert.

Only the GnuTLS Build — and That Is the Whole Story

pjproject can be compiled against several TLS backends, each in its own source file. The overflow lives in ssl_sock_gtls.c, the GnuTLS backend; the fix touches only that file. Only the GnuTLS backend is affected. The OpenSSL backend (ssl_sock_ossl.c) has its own certificate-parsing code and is not affected — and OpenSSL is pjproject's default backend. GnuTLS is the opt-in alternative, chosen with --with-gnutls, most often by projects whose licensing precludes linking OpenSSL. Asterisk and FreePBX build their bundled pjproject against OpenSSL by default, so a typical Asterisk or FreePBX deployment is not affected by this bug. The affected population is the minority of pjproject consumers that deliberately built the GnuTLS backend.

Here is the uncomfortable part for anyone triaging a fleet. Two hosts can run byte-identical pjproject 2.17, present identical version banners, and answer a SIP OPTIONS probe identically — and one is vulnerable while the other is not, because they differ only in a compile-time flag. No SIP-level probe and no CVE scanner keyed to a version number can see that flag; version-matching is blind to it. (TLS-library fingerprinting — the JA3/JA3S family, which reads cipher-suite ordering and extension layout from the handshake — can often distinguish GnuTLS from OpenSSL, so the backend is not perfectly opaque on the wire; but that is a different and far less common check than the version matching that vulnerability scanners actually perform.) The finding a scanner hands you — "pjproject 2.17, CVE-2026-57163" — is only half an answer.

Reproducing It

We built pjproject 2.17 (the latest release) twice from identical source under AddressSanitizer — once --with-gnutls, once with the default OpenSSL backend — and drove a small pjlib TLS client at a malicious server (openssl s_server) presenting a self-signed certificate whose Subject Alternative Name is a single 400-byte dNSName — comfortably past the 256-byte buffer, within the erroneous 512. Four runs:

[1] GnuTLS build  x  malicious cert  ->  CRASH
      AddressSanitizer: stack-buffer-overflow, WRITE of size 400
      #3 in tls_cert_get_info      ssl_sock_gtls.c:1022
      #4 in ssl_update_certs_info  ssl_sock_gtls.c:1146
      #5 in on_handshake_complete  ssl_sock_imp_common.c:299

[2] OpenSSL build x  same cert      ->  handshake completes, no crash
[3] GnuTLS build  x  benign cert    ->  handshake completes, no crash
[4] GnuTLS build + fix c4a151a      ->  handshake completes, no crash

Cell [1] is the bug; cell [2] is the spine — the identical certificate against the OpenSSL build simply completes the handshake. Cell [3] confirms the trigger is the SAN's length, not merely presenting a certificate. Cell [4] verifies the fix. The crash stack lands exactly where the source predicts: line 1022, the SAN-counting loop, reached from on_handshake_complete — proof it fires at handshake completion, before the SIP layer, on an untrusted cert. We demonstrated the malicious-server-to-client direction; the advisory notes a malicious client can hit a server that requests client certificates the same way.

Impact, stated exactly. This is a reliable pre-authentication remote crash — a denial of service — via up to ~256 bytes of attacker-influenced overrun of a 256-byte stack buffer. The bytes come from the certificate's SAN, so the write is attacker-influenced, and on a build compiled without stack-smashing mitigations a stack overflow of this shape could in principle lead to code execution. We did not demonstrate that, and neither does the advisory, which describes "application crashes or memory corruption." With the stack canaries and ASLR that any modern build carries, the dependable outcome is a crash. Treat it as pre-auth DoS; treat RCE as a theoretical ceiling, not a claim.

AM I EXPOSED?

  • AFFECTEDSoftware built on pjproject / PJSIP with the --with-gnutls backend, on any release up to and including 2.17 (we verified the flaw is present in the 2.14–2.17 source; OSV gives the range as 2.10–2.17), where it terminates or initiates TLS with untrusted peers. The overflow fires on the party that reads the peer certificate.
  • NOT YOUBuilds using the default OpenSSL backend — which includes Asterisk and FreePBX as they ship by default. The advisory also lists Apple SecureTransport / Network.framework builds as unaffected. Only the GnuTLS backend carries the bug.
  • CHECKYou cannot tell from the network — the backend is a compile-time choice. As a first glance on the box, ldd $(command -v asterisk) | grep -iE 'gnutls|libssl' (or ldd against your pjproject binary or res_pjsip.so) shows which TLS libraries it links — but treat it as a hint, not proof: libgnutls can be pulled in by an unrelated dependency rather than pjproject's TLS backend. The authoritative answer: distro packages of Asterisk (Debian, Ubuntu, RHEL) are built against OpenSSL and are not affected regardless of what ldd shows; for a self-built stack, the definitive check is the pjproject --with-gnutls flag in your build log / config.
  • FIXThere is no fixed release — 2.17 is the latest tag and is still vulnerable. Cherry-pick fix commit c4a151a onto your build (it changes one file). Switching to the OpenSSL backend also removes the bug, but only consider it if the licensing reason you chose GnuTLS no longer binds you. Until patched, restrict which peers can open TLS to the service.

The Fix

Commit c4a151a (2026-06-17) sets len to the buffer's true capacity before the counting loop and again on every iteration, matching what the populate loop already did:

  char out[256] = { 0 };
+ len = sizeof(out) - 1;              /* added: true capacity, 255 */
  while (gnutls_x509_crt_get_subject_alt_name(cert, seq, out, &len, NULL)
         != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
  {
      seq++;
+     len = sizeof(out) - 1;          /* added */
  }

As of this writing the fix lives only on the main branch — it is not in any tagged release, including the latest, 2.17. So the accurate remediation is not "upgrade to the fixed version" (there isn't one) but "cherry-pick the commit, or move to the OpenSSL backend if your licensing allows."

One of Eight — and Deliberately Not the Widest

CVE-2026-57163 was disclosed alongside seven sibling pjproject memory-safety bugs (CVE-2026-57159 through 57166, which Debian tracks together because Asterisk embeds the pjproject source). They span different subsystems: SDP negotiation, SIP header handling, SRTP, the HTTP client, and the telnet CLI. 57163 is the only one in the TLS certificate path — and it is not the widest-reaching of the set. CVE-2026-57159, an out-of-bounds read and write in the SDP negotiator, is backend-independent and sits in a signalling path every deployment exercises. We chose 57163 for this write-up because it is a clean, isolated, single-commit, pre-authentication bug whose backend-specific nature makes a genuinely instructive reproduction — not because it is the scariest of the eight. If you run pjproject, treat the whole cluster as your remediation scope, not this one CVE.

Investigation Workflow

Two questions for a fleet of SIP infrastructure: which hosts speak SIP over TLS, and which of those are pjproject/Asterisk below the fix. The first is a network question; the second and the backend question are on-box.

1. Find SIP-over-TLS Endpoints

SIP over TLS is conventionally 5061/tcp (plain SIP is 5060), though either can be moved. A TLS service answering SIP is the surface here; a SIP OPTIONS exchange over TLS confirms a live SIP stack and often reveals a Server or User-Agent banner (e.g. a PJSIP or Asterisk version).

2. Establish the Version — and Accept Its Limit

The banner or the on-box version tells you whether the build predates the fix (everything through 2.17 does). But version alone cannot answer the question that decides exposure here: which TLS backend was compiled in. That is the on-box ldd check above. A version scanner will flag every pjproject 2.17 as "CVE-2026-57163"; only the backend check separates the genuinely-affected GnuTLS builds from the OpenSSL majority that are not.

3. Cross-Reference Exposure

A pre-auth cert-parsing bug is reachable by anyone who can open a TLS connection to the SIP port, or — for the client-side direction — anyone a client can be induced to connect to. Confirm who can reach 5061: internet-exposed SIP-TLS on a GnuTLS build below the fix is the urgent case; a peer-restricted, firewalled service is a lower-priority patch.

Remediation

  1. Cherry-pick commit c4a151a. It is a one-file change to ssl_sock_gtls.c. Because there is no fixed release, this is the primary remediation for anyone who must keep the GnuTLS backend.
  2. Consider the OpenSSL backend — conditionally. Rebuilding against OpenSSL removes the bug, but GnuTLS was likely chosen for a licensing reason; only switch if that reason no longer applies to you.
  3. Restrict TLS reachability. A pre-auth bug reached over TLS is far less dangerous when only known peers can open that connection. Firewall 5061 (and any client-side TLS egress) to trusted endpoints while you patch.
  4. Patch the whole cluster. 57163 is one of eight sibling CVEs, most of them backend-independent. Track your remediation against the full CVE-2026-57159..57166 set, not this CVE alone.

Triage Notes

  • Remote recon proves: that a host answers SIP over TLS and, from a banner, its pjproject/Asterisk version — so "is this below the fix" is answerable from the network.
  • It cannot prove: which TLS backend was compiled in, which is what actually decides exposure. Version-matching scanners are blind to the --with-gnutls flag; only an on-box ldd/build check answers it.
  • Evidence to request: the pjproject version; whether the build links GnuTLS or OpenSSL (ldd); who can reach the SIP-TLS port; and whether the sibling CVEs (57159–57166) are in scope.
  • Escalation threshold: a GnuTLS-linked pjproject build below the fix, terminating or initiating TLS with untrusted peers. An OpenSSL build, or a peer-restricted service, drops it sharply.
  • Finding statement: "The host runs pjproject/PJSIP ≤ 2.17 and its TLS is served by the GnuTLS backend, exposing it to CVE-2026-57163: a peer certificate with an oversized SubjectAltName overflows a 256-byte stack buffer in tls_cert_get_info during cert-info extraction at handshake completion, before SIP authentication (CWE-121; pre-auth crash / DoS; code execution theoretical, not demonstrated). No fixed release exists — cherry-pick c4a151a or move to the OpenSSL backend, and restrict who can reach the SIP-TLS port. Remediate the full 57159–57166 cluster."

The network half of this — finding hosts that answer SIP over TLS on your network, from your phone — runs in RECON. Which TLS backend a build was compiled with is an on-box check RECON does not replace; that distinction is the whole point of this bug. Get RECON on the App Store.

Follow @hellorecon for new CVE investigations.

Sources

By Vladimir Slavin · Founder, RECON · [email protected]
// THREAT BRIEFING

This, pointed at the software you run

Every month, every CVE published against the software you run: triaged by hand, in plain words, with the one that deserves attention written up the way these are.

REQUEST PERSONAL BRIEFING →