VYPR
High severityNVD Advisory· Published Jun 10, 2026

CVE-2026-49759

CVE-2026-49759

Description

Erlang OTP's inet_drv contains a stack buffer overflow in SCTP error chunk parsing, allowing remote attackers to crash the VM.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Erlang OTP's inet_drv contains a stack buffer overflow in SCTP error chunk parsing, allowing remote attackers to crash the VM.

Vulnerability

Erlang OTP's inet_drv contains a stack-based buffer overflow vulnerability in the sctp_parse_error_chunk function located in erts/emulator/drivers/common/inet_drv.c. This function parses SCTP ERROR chunks and writes cause codes into a fixed-size stack-allocated array without proper bounds checking. This vulnerability affects OTP versions from OTP 17.0 before 27.3.4.13, 28.5.0.2, and 29.0.2 [3].

Exploitation

An unauthenticated remote attacker can exploit this vulnerability by establishing an SCTP association to a listening port and then sending a single crafted SCTP ERROR chunk containing sufficient cause codes to overflow the stack buffer. This action is required to trigger the crash [3, 4].

Impact

Successful exploitation of this vulnerability leads to a Denial of Service by crashing the Erlang BEAM VM. While the overflow does not provide a controlled return address for Remote Code Execution, a crafted chunk may also leak small amounts of Erlang VM memory into the received error packet, though this data is typically already readable by the system user running the VM [3, 4].

Mitigation

This vulnerability is fixed in OTP versions 27.3.4.13, 28.5.0.2, and 29.0.2. There are no workarounds other than avoiding the opening of an SCTP listening socket on a network reachable by attackers. Running a VM built with standard stack protection is also recommended [4].

AI Insight generated on Jun 10, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected products

3
  • SSH/SSHreferences
  • Erlang/ertsllm-create
    Range: erts 6.0 - 15.2.7.9, 16.4.0.2, 17.0.2
  • Erlang/OTPllm-fuzzy
    Range: OTP 17.0 - 27.3.4.13, 28.5.0.2, 29.0.2

Patches

1
3983d4952843

Protect the output term buffer from overflow

https://github.com/erlang/otpRaimo NiskanenJun 2, 2026via body-scan
1 file changed · +34 18
  • erts/emulator/drivers/common/inet_drv.c+34 18 modified
    @@ -3392,7 +3392,7 @@ static int sctp_parse_ancillary_data
     ** concerns the protocol implementation), so we omit it:
     */
     static int sctp_parse_error_chunk
    -       (ErlDrvTermData * spec, int i, char * chunk, int chlen)
    +      (ErlDrvTermData * spec, int i, int spec_size, char * chunk, int chlen)
     {
         /* The "chunk" itself contains its length, which must not be greater than
            the "chlen" derived from the over-all msg size:
    @@ -3415,16 +3415,26 @@ static int sctp_parse_error_chunk
         {
     	ccode = sock_ntohs (*((uint16_t*)(cause)));
     	clen  = sock_ntohs (*((uint16_t*)(cause + 2)));
    -	if (clen <= 0)
    -	    /* Strange, but must guard against that!  */
    -	    break;
    -
    -	/* Install the corresp atom for this "ccode": */
    +        /* Install the corresp atom for this "ccode": */
     	i = LOAD_INT (spec, i, ccode);
    +	s ++;
    +        if (clen <= 0 || /* Overflow - truncate here */
    +            i + 2*LOAD_INT_CNT+LOAD_NIL_CNT+LOAD_LIST_CNT > spec_size)
    +            /* We do not have room for two INT:s which is
    +             * the worst case for the next iteration, so truncate now.
    +             *
    +             * We should have room for the truncation marker since
    +             * we have added at most one INT after the previous check.
    +             */ {
    +            i = LOAD_INT (spec, i, 0);
    +            /* Truncation marker - there is no error 0 */
    +            s ++;
    +            break;
    +        }
     	cause += clen;
     	coff  += clen;
    -	s ++;
         }
    +    /* Finalize the list */
         i = LOAD_NIL (spec, i);
         i = LOAD_LIST(spec, i, s+1);
         return i;
    @@ -3435,7 +3445,7 @@ static int sctp_parse_error_chunk
     ** are sent IN PLACE OF, not in conjunction with, the normal data:
     */
     static int sctp_parse_async_event
    -      (ErlDrvTermData * spec, int i,    int ok_pos,
    +      (ErlDrvTermData * spec, int i,    int spec_size,         int ok_pos,
            ErlDrvTermData   error_atom,     inet_descriptor* desc,
            ErlDrvBinary   * bin,  int offs, int sz)
     {
    @@ -3569,7 +3579,7 @@ static int sctp_parse_async_event
     		+ sizeof(sptr->sre_assoc_id);
     #	    endif
     	    chlen = sptr->sre_length  - (chunk - (char *)sptr);
    -	    i = sctp_parse_error_chunk(spec, i, chunk, chlen);
    +	    i = sctp_parse_error_chunk(spec, i, spec_size, chunk, chlen);
     
     	    i = LOAD_TUPLE (spec, i, 4);
     	    /* The {error, {...}} will be closed by the caller */
    @@ -3809,6 +3819,7 @@ inet_async_binary_data
     	 ErlDrvBinary   * bin,  int offs, int len, void *mp)
     {
         unsigned int hsz = desc->hsz + phsz;
    +    const int spec_size = PACKET_ERL_DRV_TERM_DATA_LEN;
         ErlDrvTermData spec [PACKET_ERL_DRV_TERM_DATA_LEN];
         ErlDrvTermData caller;
         int aid;
    @@ -3859,7 +3870,8 @@ inet_async_binary_data
     	       condition; in the latter case,   the 'ok' above is overridden by
     	       an 'error', and the Event we receive contains the error term: */
     	    i = sctp_parse_async_event
    -		(spec, i, ok_pos, am_error, desc, bin, offs+hsz, sz);
    +		(spec, i, spec_size - 3*LOAD_TUPLE_CNT,
    +                 ok_pos, am_error, desc, bin, offs+hsz, sz);
             else
         	    /* This is SCTP data, not a notification event.   The data can be
     	       returned as a List or as a Binary, similar to the generic case:
    @@ -4045,6 +4057,7 @@ static int packet_binary_message(inet_descriptor* desc,
                                      void *mp)
     {
         unsigned int hsz = desc->hsz;
    +    const int spec_size = PACKET_ERL_DRV_TERM_DATA_LEN;
         ErlDrvTermData spec [PACKET_ERL_DRV_TERM_DATA_LEN];
         int i = 0;
         int alen;
    @@ -4107,14 +4120,16 @@ static int packet_binary_message(inet_descriptor* desc,
     	i = sctp_parse_ancillary_data (spec, i, mptr);
     
     	/* Then: Data or Event (Notification)? */
    -	if (mptr->msg_flags & MSG_NOTIFICATION)
    +	if (mptr->msg_flags & MSG_NOTIFICATION) {
     	    /* This is an Event, parse it. It may indicate a normal or an error
     	       condition; in the latter case,  the initial 'sctp' atom is over-
     	       ridden by 'sctp_error',   and the Event we receive contains the
     	       error term: */
     	    i = sctp_parse_async_event
    -		(spec, i, 0, am_sctp_error, desc, bin, offs, len);
    -        else
    +		(spec, i, spec_size - 2*LOAD_TUPLE_CNT,
    +                 0, am_sctp_error, desc, bin, offs, len);
    +        }
    +        else {
         	    /* This is SCTP data, not a notification event.   The data can be
     	       returned as a List or as a Binary, similar to the generic case:
     	    */
    @@ -4126,6 +4141,7 @@ static int packet_binary_message(inet_descriptor* desc,
     	    else
     	    	/* INET_MODE_BINARY => Binary */
     		i = LOAD_BINARY(spec, i, bin, offs, len);
    +        }
     
     	/* Close up the {[AncilData], Event_OR_Data} tuple: */
     	i = LOAD_TUPLE (spec, i, 2);
    @@ -9497,8 +9513,8 @@ static ErlDrvSSizeT sctp_fill_opts(inet_descriptor* desc,
         int i      = 0;
         int length = 0; /* Number of result list entries */
         
    -    int spec_allocated = PACKET_ERL_DRV_TERM_DATA_LEN;
    -    spec = ALLOC(sizeof(* spec) * spec_allocated);
    +    int spec_size = PACKET_ERL_DRV_TERM_DATA_LEN;
    +    spec = ALLOC(sizeof(* spec) * spec_size);
         
     #   define RETURN_ERROR(Spec, Errno) \
         do {                    \
    @@ -9510,18 +9526,18 @@ static ErlDrvSSizeT sctp_fill_opts(inet_descriptor* desc,
     #   define PLACE_FOR(Spec, Index, N)                            \
         do {                                                        \
     	int need;                                               \
    -	if ((Index) > spec_allocated) {                         \
    +	if ((Index) > spec_size) {                              \
     	    erts_exit(ERTS_ERROR_EXIT,"Internal error in inet_drv, "           \
     		     "miscalculated buffer size");              \
     	}                                                       \
     	need = (Index) + (N);                                   \
     	if (need > INET_MAX_OPT_BUFFER/sizeof(ErlDrvTermData)) {\
     	    RETURN_ERROR((Spec), -ENOMEM);                      \
     	}                                                       \
    -	if (need > spec_allocated) {                            \
    +	if (need > spec_size) {                                 \
     	    (Spec) = REALLOC((Spec),                            \
     			     sizeof(* (Spec))                   \
    -			     * (spec_allocated = need + 20));   \
    +			     * (spec_size = need + 20));        \
     	}                                                       \
         } while (0)
         
    

Vulnerability mechanics

Root cause

"The sctp_parse_error_chunk function does not validate the size of SCTP ERROR chunk cause codes before writing them to a fixed-size stack buffer."

Attack vector

An unauthenticated remote attacker must establish an SCTP association to a listening port on the target system. The attacker then sends a single, crafted SCTP ERROR chunk containing sufficient cause codes to overflow the stack buffer in the `sctp_parse_error_chunk` function. This overflow causes the Erlang VM to crash, leading to a denial-of-service condition [ref_id=2].

Affected code

The vulnerability resides in the `sctp_parse_error_chunk` function located in `erts/emulator/drivers/common/inet_drv.c`. This function is responsible for parsing SCTP ERROR chunks and writing cause codes into a stack-allocated buffer without proper bounds checking.

What the fix does

The patch introduces an overflow check within the loop that parses SCTP ERROR chunks in the `sctp_parse_error_chunk` function [patch_id=5502027]. This check ensures that the total size of the parsed cause codes does not exceed the allocated buffer size (`spec_size`). By truncating the data when an overflow is detected, the vulnerability is mitigated, preventing the stack buffer overflow and subsequent VM crash [ref_id=1].

Preconditions

  • configSCTP support must be compiled into Erlang OTP.
  • networkA listening SCTP socket must be open and reachable from the attacker's network.

Generated on Jun 10, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

5

News mentions

1