Back to Blog
critical SEVERITY9 min read

How buffer overflow in Intel SGX enclave ECALLs happens in C and how to fix it

A critical buffer overflow vulnerability was discovered in Intel SGX enclave functions `ecall_encrypt_data` and `ecall_decrypt_data` in `backend/sgx/enclave/enclave.c`. The functions performed memory operations without validating that the provided buffer lengths matched the actual allocated buffer sizes, allowing an attacker controlling the untrusted application to trigger heap corruption within the secure enclave by passing oversized length parameters.

O
By Orbis AppSec
Published July 27, 2026Reviewed July 27, 2026

Answer Summary

This is a CWE-120 buffer overflow vulnerability in Intel SGX enclave C code. The `ecall_encrypt_data` and `ecall_decrypt_data` functions in `backend/sgx/enclave/enclave.c` wrote to output buffers using attacker-controlled length parameters without bounds checking. An attacker could call these ECALLs with a large `plaintext_len` value (e.g., 10000 bytes) while providing a small ciphertext buffer (e.g., 256 bytes), causing memory corruption inside the secure enclave. The fix adds validation to reject zero or oversized length parameters before any memory operations occur.

Vulnerability at a Glance

cweCWE-120 (Buffer Copy without Checking Size of Input)
fixAdded input validation to reject zero or oversized length values before memory operations
riskMemory corruption within secure enclave, potential enclave compromise
languageC (Intel SGX)
root causeMissing bounds validation on length parameters from untrusted caller
vulnerabilityBuffer overflow in Intel SGX enclave ECALL functions

Introduction

In a Node.js library utilizing Intel SGX trusted execution environments, we discovered a critical buffer overflow vulnerability in backend/sgx/enclave/enclave.c at line 42. The ecall_encrypt_data and ecall_decrypt_data functions—the secure entry points into the enclave—performed memory operations without validating buffer sizes against the length parameters provided by the untrusted application. This created a dangerous situation where an attacker controlling the host application could trigger memory corruption inside the supposedly secure enclave by simply passing a large plaintext_len value that exceeded the actual allocated buffer size.

What makes this vulnerability particularly severe is its location: Intel SGX enclaves are designed to be the last line of defense, protecting sensitive data even from a compromised operating system. A buffer overflow within the enclave itself undermines this entire security model, potentially allowing an attacker to corrupt enclave memory, leak secrets, or manipulate cryptographic operations.

The Vulnerability Explained

Let's examine the vulnerable code in ecall_encrypt_data:

void ecall_encrypt_data(
    const uint8_t* plaintext,
    uint32_t plaintext_len,
    uint8_t* ciphertext,
    uint32_t* ciphertext_len
) {
    // In production: use AES-GCM inside enclave
    // For demo: XOR encryption
    uint8_t key[32] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF};

    for (uint32_t i = 0; i < plaintext_len; i++) {
        ciphertext[i] = plaintext[i] ^ key[i % 32];
    }
    *ciphertext_len = plaintext_len;
}

The critical flaw is on the line ciphertext[i] = plaintext[i] ^ key[i % 32];. This loop iterates plaintext_len times, writing to the ciphertext buffer without ever checking whether ciphertext is actually large enough to hold plaintext_len bytes.

The same vulnerability exists in ecall_decrypt_data:

void ecall_decrypt_data(
    const uint8_t* ciphertext,
    uint32_t ciphertext_len,
    uint8_t* plaintext,
    uint32_t* plaintext_len
) {
    uint8_t key[32] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF};

    for (uint32_t i = 0; i < ciphertext_len; i++) {
        plaintext[i] = ciphertext[i] ^ key[i % 32];
    }
    *plaintext_len = ciphertext_len;
}

How Could This Be Exploited?

Here's a concrete attack scenario against ecall_encrypt_data:

  1. The attacker controls the untrusted application that calls the enclave
  2. They allocate a small ciphertext buffer—say, 256 bytes
  3. They call ecall_encrypt_data with plaintext_len=10000
  4. The enclave's loop writes 10,000 bytes into a 256-byte buffer
  5. The overflow corrupts adjacent enclave memory, potentially:
    - Overwriting function pointers or return addresses
    - Corrupting cryptographic keys stored in enclave memory
    - Leaking sensitive data through controlled memory corruption

The severity is amplified because:
- The enclave trusts the length parameter: SGX enclaves must treat all inputs from the untrusted application as potentially malicious, but this code assumes plaintext_len is valid
- No bounds checking exists: There's no validation that plaintext_len is reasonable or fits within the buffer
- Memory corruption is within the enclave: This isn't just crashing the application—it's corrupting the trusted execution environment itself

Real-World Impact

For applications using this library, the impact is severe:

  • Confidentiality breach: Attackers could potentially leak secrets stored in enclave memory by carefully controlling the overflow
  • Integrity violation: The cryptographic operations could be manipulated by corrupting key material
  • Availability impact: At minimum, the enclave could crash, but worse, it could continue operating with corrupted state

In a Node.js library context, any downstream consumer who integrates this SGX enclave code inherits this vulnerability. If they're using SGX to protect API keys, encryption keys, or other sensitive data, an attacker who can influence the length parameters could compromise the entire security model.

The Fix

The fix adds explicit bounds checking before any memory operations occur. Here's what changed in ecall_encrypt_data:

Before:

void ecall_encrypt_data(
    const uint8_t* plaintext,
    uint32_t plaintext_len,
    uint8_t* ciphertext,
    uint32_t* ciphertext_len
) {
    // In production: use AES-GCM inside enclave
    // For demo: XOR encryption
    uint8_t key[32] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF};

    for (uint32_t i = 0; i < plaintext_len; i++) {
        ciphertext[i] = plaintext[i] ^ key[i % 32];
    }
    *ciphertext_len = plaintext_len;
}

After:

void ecall_encrypt_data(
    const uint8_t* plaintext,
    uint32_t plaintext_len,
    uint8_t* ciphertext,
    uint32_t* ciphertext_len
) {
    if (plaintext_len == 0 || plaintext_len > sizeof(((secure_data_t*)0)->data)) {
        return;
    }
    // In production: use AES-GCM inside enclave
    // For demo: XOR encryption
    uint8_t key[32] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF};

    for (uint32_t i = 0; i < plaintext_len; i++) {
        ciphertext[i] = plaintext[i] ^ key[i % 32];
    }
    *ciphertext_len = plaintext_len;
}

The identical validation was added to ecall_decrypt_data:

void ecall_decrypt_data(
    const uint8_t* ciphertext,
    uint32_t ciphertext_len,
    uint8_t* plaintext,
    uint32_t* plaintext_len
) {
    if (ciphertext_len == 0 || ciphertext_len > sizeof(((secure_data_t*)0)->data)) {
        return;
    }
    uint8_t key[32] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF};

    for (uint32_t i = 0; i < ciphertext_len; i++) {
        plaintext[i] = ciphertext[i] ^ key[i % 32];
    }
    *plaintext_len = ciphertext_len;
}

How This Fix Works

The validation check if (plaintext_len == 0 || plaintext_len > sizeof(((secure_data_t*)0)->data)) performs two critical validations:

  1. Zero-length check: Rejects empty inputs, preventing edge cases and potential integer underflows in subsequent calculations
  2. Maximum size check: Uses a clever C idiom sizeof(((secure_data_t*)0)->data) to determine the maximum allowable size based on the secure_data_t structure definition, ensuring the length doesn't exceed what the buffer can actually hold

If either check fails, the function returns immediately without performing any memory operations. This "fail-safe" approach ensures that invalid inputs are rejected before they can cause harm.

Security Improvement

This fix provides defense-in-depth:

  • Prevents the overflow: The length is validated against the actual buffer capacity before the loop executes
  • Early exit on invalid input: No partial processing occurs when validation fails
  • Uses compile-time size calculation: The sizeof() expression is evaluated at compile time, so there's no runtime overhead or potential for the check itself to be bypassed
  • Protects both functions: Both encryption and decryption paths are secured with identical validation logic

The fix maintains the existing behavior for valid inputs while completely blocking the attack vector for oversized length parameters.

Prevention & Best Practices

To prevent buffer overflow vulnerabilities in Intel SGX enclave code:

1. Validate All Untrusted Inputs

Every ECALL parameter must be validated. The untrusted application controls all inputs, so treat them as potentially malicious:

// Always check lengths
if (len == 0 || len > MAX_ALLOWED_SIZE) {
    return SGX_ERROR_INVALID_PARAMETER;
}

// Validate pointers aren't NULL
if (buffer == NULL) {
    return SGX_ERROR_INVALID_PARAMETER;
}

// Check pointer alignment if required
if ((uintptr_t)buffer % REQUIRED_ALIGNMENT != 0) {
    return SGX_ERROR_INVALID_PARAMETER;
}

2. Use Safe Memory Functions

Replace unsafe functions with bounds-checked alternatives:

// Instead of memcpy
if (len > dest_size) {
    return SGX_ERROR_INVALID_PARAMETER;
}
memcpy_s(dest, dest_size, src, len);

// Instead of strcpy
strncpy_s(dest, dest_size, src, _TRUNCATE);

3. Define Maximum Buffer Sizes

Use compile-time constants or structure sizes to define limits:

#define MAX_PLAINTEXT_SIZE 4096

typedef struct {
    uint8_t data[MAX_PLAINTEXT_SIZE];
    uint32_t len;
} secure_data_t;

// Then validate against these limits
if (plaintext_len > MAX_PLAINTEXT_SIZE) {
    return SGX_ERROR_INVALID_PARAMETER;
}

4. Implement Defense in Depth

Layer multiple security controls:

  • Input validation: Check all parameters at ECALL entry
  • Buffer size tracking: Store allocated sizes alongside buffers
  • Assertions: Use assert() for internal consistency checks (disabled in release builds)
  • Return error codes: Always return status codes so callers can detect failures

5. Use Static Analysis Tools

Static analysis can catch these issues before code review:

  • Intel SGX SDK tools: Use the SDK's built-in analysis capabilities
  • Clang Static Analyzer: Run with -analyze flag
  • Coverity or similar: Enterprise-grade static analysis
  • Semgrep rules: Create custom rules for ECALL validation patterns

6. Follow OWASP Guidelines

The OWASP Secure Coding Practices provide excellent guidance:

  • Validate input length, range, format, and type
  • Use parameterized queries and prepared statements (for database operations)
  • Implement proper error handling that doesn't leak information
  • Apply the principle of least privilege

7. Security Standards Reference

This vulnerability maps to:
- CWE-120: Buffer Copy without Checking Size of Input
- CWE-119: Improper Restriction of Operations within the Bounds of a Memory Buffer
- OWASP Top 10 2021 - A03:2021: Injection (memory corruption as a form of injection)

Key Takeaways

  • Never trust ECALL length parameters: The ecall_encrypt_data and ecall_decrypt_data functions trusted plaintext_len and ciphertext_len from the untrusted application without validation, enabling the buffer overflow
  • Validate before the loop, not during: The fix adds validation before for (uint32_t i = 0; i < plaintext_len; i++) executes, preventing any malicious writes from occurring
  • Use sizeof() for compile-time bounds: The expression sizeof(((secure_data_t*)0)->data) provides a safe, compile-time constant for maximum buffer size validation
  • Both encryption and decryption paths need protection: The vulnerability existed in both ecall_encrypt_data and ecall_decrypt_data, requiring identical fixes to both functions
  • SGX enclave vulnerabilities are especially critical: Because enclaves are the trusted computing base, buffer overflows within them can compromise the entire security model that SGX provides

How Orbis AppSec Detected This

Source: Untrusted length parameters plaintext_len and ciphertext_len passed through ECALL interface from the host application

Sink: Memory write operations ciphertext[i] = plaintext[i] ^ key[i % 32] and plaintext[i] = ciphertext[i] ^ key[i % 32] in backend/sgx/enclave/enclave.c:42 and line 57

Missing control: No bounds validation on length parameters before memory operations; no check that plaintext_len or ciphertext_len fit within the allocated buffer sizes

CWE: CWE-120 (Buffer Copy without Checking Size of Input)

Fix: Added input validation if (plaintext_len == 0 || plaintext_len > sizeof(((secure_data_t*)0)->data)) and if (ciphertext_len == 0 || ciphertext_len > sizeof(((secure_data_t*)0)->data)) to reject zero or oversized length values before any memory operations

Orbis AppSec automatically detected this vulnerability and opened a pull request with the fix. Try Orbis AppSec on your repositories to find and fix issues like this automatically.

Conclusion

Buffer overflow vulnerabilities in Intel SGX enclaves represent a critical threat to trusted execution environments. The vulnerability in ecall_encrypt_data and ecall_decrypt_data demonstrates how easily missing input validation can undermine even the most secure architectural features. By adding simple bounds checks before memory operations, we prevented an attacker from corrupting enclave memory through oversized length parameters.

For developers working with SGX or any trusted execution environment, the lesson is clear: never trust inputs from untrusted code, even when you control both sides of the interface. Every ECALL parameter must be validated as if it came from an attacker, because in a compromised system, it might. The few lines of validation code added in this fix prevent a critical vulnerability that could have compromised the entire security model of applications using this library.

Always validate input lengths, use safe memory functions, and leverage static analysis tools to catch these issues before they reach production. The security of your trusted computing base depends on it.

References

Frequently Asked Questions

What is a buffer overflow in Intel SGX enclaves?

A buffer overflow in SGX enclaves occurs when enclave code writes beyond the bounds of an allocated buffer, potentially corrupting enclave memory. Unlike normal buffer overflows, SGX enclave vulnerabilities are particularly severe because they can compromise the trusted execution environment that's designed to protect sensitive data from the host operating system.

How do you prevent buffer overflow in Intel SGX C code?

Always validate length parameters from untrusted callers before performing memory operations. Check that lengths are non-zero and don't exceed the actual buffer size using sizeof() or predefined constants. Never trust size parameters passed through ECALL interfaces without validation, as the untrusted application controls these values.

What CWE is buffer overflow in SGX enclaves?

This vulnerability is classified as CWE-120 (Buffer Copy without Checking Size of Input), which describes cases where a program copies data to a buffer without verifying that the size of the input fits within the destination buffer.

Is using AES-GCM encryption enough to prevent buffer overflow in SGX?

No. While the code comment mentions using AES-GCM for production encryption, cryptographic algorithms don't prevent buffer overflows. Buffer overflow prevention requires explicit bounds checking on all memory operations, regardless of what encryption algorithm is used. The vulnerability exists in the memory copy operations, not the encryption itself.

Can static analysis detect buffer overflow in SGX enclaves?

Yes. Static analysis tools can detect missing bounds checks in ECALL functions by analyzing data flow from untrusted inputs (ECALL parameters) to memory operations. The Orbis AppSec scanner successfully identified this vulnerability using the multi_agent_ai rule V-001, demonstrating that automated tools can find these issues before they reach production.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #5115

Related Articles

critical

How Server-Side Request Forgery (SSRF) happens in JavaScript fetch() and how to fix it

A critical Server-Side Request Forgery vulnerability in `popup.js` allowed attackers to inject malicious URLs from scraped webpages directly into fetch() calls, potentially accessing internal network resources and AWS metadata endpoints. The fix adds URL validation to ensure only HTTP/HTTPS protocols are used and blocks requests to private IP ranges and localhost addresses.

high

How NO_PROXY bypass via crafted URL happens in Node.js axios and how to fix it

A high-severity vulnerability (CVE-2026-42043) in axios versions prior to 1.15.1 allowed attackers to bypass NO_PROXY environment variable restrictions using specially crafted URLs. This meant HTTP requests intended to stay internal could be routed through an attacker-controlled proxy, potentially exposing sensitive data. The fix upgrades axios to version 1.15.1, which correctly validates URLs against NO_PROXY rules.

critical

How JSON request validation bypass happens in Node.js API handlers and how to fix it

A critical validation bypass in the `/api/agents/jobs` endpoint allowed attackers to send malformed JSON with arbitrary properties that could trigger prototype pollution or unexpected behavior. The fix added comprehensive validation checks including array detection and property existence verification to prevent malicious payloads from reaching downstream processing logic.

critical

How Server-Side Request Forgery happens in Node.js httpProxy.js and how to fix it

A critical Server-Side Request Forgery (SSRF) vulnerability was discovered in `hubcmdui/routes/httpProxy.js` where the `/proxy/test` endpoint passed a user-controlled `testUrl` parameter directly to `axios.get()` without any validation. An attacker could exploit this to probe internal infrastructure — including AWS metadata endpoints, Redis instances, and private network ranges. The fix introduces a strict URL validation function that blocks private IP ranges, loopback addresses, and non-HTTP(S)

critical

How Remote Configuration Injection happens in JavaScript fetch() and how to fix it

A critical vulnerability in `js/config.js` allowed attackers to inject malicious configuration data through DNS spoofing or man-in-the-middle attacks. The application fetched remote JSON configuration from GitHub without validating the response structure, enabling arbitrary code execution through crafted payloads. A single validation check now ensures only properly-formed configuration objects are accepted.

high

How missing Dependabot cooldown configuration happens in GitHub Actions and how to fix it

A high-severity vulnerability was discovered in the `.github/dependabot.yml` configuration file where no cooldown period was set for dependency updates. This exposed the Node.js library and its downstream consumers to potentially malicious or unstable packages immediately after publication. The fix adds a 7-day cooldown period to all package ecosystem entries, providing a critical safety buffer before accepting newly published package versions.