GCVE Workshop - 22 September 2026 (14:00-18:00), Luxembourg Before The Vulnopticon Conference - Registration

GCVE-1988-2026-0079

Vulnerability from gna-1988 – Published: 2026-09-07 13:20 – Updated: 2026-09-07 13:20
VLAI
Title
Escargot v4.3.0-214-gfaee4437 Debugger WebSocket Off-by-One Stack Buffer Overflow
Summary
Escargot contains a remotely triggerable one-byte stack-based out-of-bounds write in the WebSocket message handling logic used by the debugger. When Escargot::DebuggerTcp::receive() receives a binary WebSocket payload that completely fills the caller-provided stack buffer, the function successfully copies the payload into the available buffer space but subsequently appends an additional NUL byte without verifying that space remains for the terminator. A 125-byte binary WebSocket payload causes the debugger to write the terminating NUL byte to buffer[125], immediately beyond the end of the 125-byte stack allocation. A proof-of-concept client establishes a valid WebSocket connection to the Escargot debugger endpoint and sends the boundary-sized binary frame. AddressSanitizer consistently detects the resulting stack-buffer overflow inside Escargot::DebuggerTcp::receive(). The vulnerability results in stack memory corruption and can remotely terminate an Escargot process exposing the debugger interface. The current proof of concept demonstrates reliable denial of service and memory corruption but does not establish arbitrary code execution. Vulnerable Code The debugger decodes the incoming masked WebSocket payload directly into a caller-provided buffer: const uint8_t* source = mask_end; uint8_t* buffer_end = buffer + m_payloadLength; while (buffer < buffer_end) { *buffer++ = *source++ ^ *mask++; if (mask >= mask_end) { mask -= 4; } } *buffer_end = 0; The payload copy itself does not exceed the destination when the payload length exactly equals the destination capacity. The vulnerability occurs immediately afterward: *buffer_end = 0; Because buffer_end is calculated as: buffer + m_payloadLength a payload that completely fills the destination causes buffer_end to point exactly one byte beyond the allocated object. The implementation does not receive or validate the destination buffer capacity before performing this additional write. Root Cause The vulnerability is an off-by-one error caused by treating a fixed-size binary buffer as though it always contains sufficient additional capacity for a NUL terminator. The affected caller uses a 125-byte stack buffer. With a 125-byte payload, the copy operation occupies the complete valid range: buffer[0] ... buffer[124] After the copy completes: buffer_end == &buffer[125]; The subsequent operation: *buffer_end = 0; is therefore equivalent to: buffer[125] = '\0'; For a 125-byte allocation, index 125 is outside the object. Valid indexes are only 0 through 124. This results in a one-byte stack-based out-of-bounds write. Proof of Concept The PoC was executed against an AddressSanitizer-instrumented Escargot build: [*] Target binary : /work/escargot/security-poc/build-debugger-asan/escargot [*] Debugger URL : ws://127.0.0.1:6611/escargot-debugger [*] Payload : 125-byte binary frame [*] Bug trigger : DebuggerTcp::receive() writes NUL at buffer[payloadLength] The client first performs a legitimate WebSocket handshake. The Escargot debugger accepts the connection: [+] WebSocket handshake accepted HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: voBbwZEm0j70WZ2O4Hx37ERFeqA= This confirms that the PoC reaches the debugger through the expected WebSocket protocol rather than invoking the vulnerable function directly. The client then sends the boundary-sized binary frame: [*] Sending binary frame: opcode=0x2 payload_len=125 The test reports successful reproduction: [+] Confirmed: True[*] Process return code: -6 The -6 return code corresponds to process termination through SIGABRT. In this test configuration, the important evidence is not the return code itself but the accompanying AddressSanitizer report identifying the invalid stack write. AddressSanitizer Evidence AddressSanitizer reports a stack-buffer overflow directly within the vulnerable receive function: [evidence] SUMMARY: AddressSanitizer: stack-buffer-overflow (/work/escargot/security-poc/build-debugger-asan/escargot+0x4fe03c) (BuildId: 1545896c0ed347436f48a03cdab84e73c634fadd) in Escargot::DebuggerTcp::receive(unsigned char*, unsigned long&) The top of the stack trace identifies DebuggerTcp::receive() as the location of the invalid memory access: [evidence] #0 0xaaaadfd0e03c in Escargot::DebuggerTcp::receive(unsigned char*, unsigned long&) (/work/escargot/security-poc/build-debugger-asan/escargot+0x4fe03c) [evidence] #1 0xaaaadfcfeb98 in Escargot::DebuggerEscargot::processEvents( Escargot::ExecutionState*, Escargot::Optional<Escargot::ByteCodeBlock*>, bool ) /work/escargot/src/debugger/DebuggerEscargot.cpp:767 Most importantly, AddressSanitizer identifies the precise stack object that is exceeded: [evidence] [800, 925) 'buffer' (line 762) <== Memory access at offset 925 overflows this variable The buffer object occupies stack offsets: [800, 925) This represents exactly: 925 - 800 = 125 bytes The first byte outside the allocation is offset 925. AddressSanitizer reports the invalid access at exactly that offset: Memory access at offset 925 overflows this variable The runtime evidence therefore precisely matches the source-level defect. For a 125-byte buffer: Stack object: [800, 925) Buffer size: 125 bytes Valid offsets: 800 through 924 Invalid write: 925 Overflow distance: 1 byte Ron Edgerson Vulnerability Researcher & Exploit Developer CVE Research | Binary Exploitation | Application & Systems Security Responsible Disclosure β€’ Proof-of-Concept Development 🌐 https://github.com/ob1sec πŸ”— https://www.linkedin.com/in/ronedgerson1 <https://linkedin.com/in/yourhandle> _______________________________________________ Sent through the Full Disclosure mailing list https://nmap.org/mailman/listinfo/fulldisclosure Web Archives & RSS: https://seclists.org/fulldisclosure/
Severity
No CVSS data available.
Impacted products
Vendor Product Version CPE status
unknown Escargot Affected: unknown
guessed Create a notification for this product.
Credits

{
  "containers": {
    "cna": {
      "affected": [
        {
          "product": "Escargot",
          "vendor": "unknown",
          "versions": [
            {
              "status": "affected",
              "version": "unknown"
            }
          ]
        }
      ],
      "credits": [
        {
          "lang": "en",
          "type": "finder",
          "value": "Ron E"
        }
      ],
      "descriptions": [
        {
          "lang": "en",
          "value": "Escargot contains a remotely triggerable one-byte stack-based out-of-bounds\nwrite in the WebSocket message handling logic used by the debugger.\n\nWhen Escargot::DebuggerTcp::receive() receives a binary WebSocket payload\nthat completely fills the caller-provided stack buffer, the function\nsuccessfully copies the payload into the available buffer space but\nsubsequently appends an additional NUL byte without verifying that space\nremains for the terminator.\n\nA 125-byte binary WebSocket payload causes the debugger to write the\nterminating NUL byte to buffer[125], immediately beyond the end of the\n125-byte stack allocation.\n\nA proof-of-concept client establishes a valid WebSocket connection to the\nEscargot debugger endpoint and sends the boundary-sized binary frame.\nAddressSanitizer consistently detects the resulting stack-buffer overflow\ninside Escargot::DebuggerTcp::receive().\n\nThe vulnerability results in stack memory corruption and can remotely\nterminate an Escargot process exposing the debugger interface. The current\nproof of concept demonstrates reliable denial of service and memory\ncorruption but does not establish arbitrary code execution.\nVulnerable Code\n\nThe debugger decodes the incoming masked WebSocket payload directly into a\ncaller-provided buffer:\n\nconst uint8_t* source = mask_end;\nuint8_t* buffer_end = buffer + m_payloadLength;\n\nwhile (buffer \u003c buffer_end) {\n    *buffer++ = *source++ ^ *mask++;\n\n    if (mask \u003e= mask_end) {\n        mask -= 4;\n    }\n}\n\n*buffer_end = 0;\n\nThe payload copy itself does not exceed the destination when the payload\nlength exactly equals the destination capacity.\n\nThe vulnerability occurs immediately afterward:\n\n*buffer_end = 0;\n\nBecause buffer_end is calculated as:\n\nbuffer + m_payloadLength\n\na payload that completely fills the destination causes buffer_end to point\nexactly one byte beyond the allocated object.\n\nThe implementation does not receive or validate the destination buffer\ncapacity before performing this additional write.\nRoot Cause\n\nThe vulnerability is an off-by-one error caused by treating a fixed-size\nbinary buffer as though it always contains sufficient additional capacity\nfor a NUL terminator.\n\nThe affected caller uses a 125-byte stack buffer. With a 125-byte payload,\nthe copy operation occupies the complete valid range:\n\nbuffer[0] ... buffer[124]\n\nAfter the copy completes:\n\nbuffer_end == \u0026buffer[125];\n\nThe subsequent operation:\n\n*buffer_end = 0;\n\nis therefore equivalent to:\n\nbuffer[125] = \u0027\\0\u0027;\n\nFor a 125-byte allocation, index 125 is outside the object. Valid indexes\nare only 0 through 124.\n\nThis results in a one-byte stack-based out-of-bounds write.\nProof of Concept\n\nThe PoC was executed against an AddressSanitizer-instrumented Escargot\nbuild:\n\n[*] Target binary :\n    /work/escargot/security-poc/build-debugger-asan/escargot\n[*] Debugger URL :\n    ws://127.0.0.1:6611/escargot-debugger\n[*] Payload :\n    125-byte binary frame\n[*] Bug trigger :\n    DebuggerTcp::receive() writes NUL at buffer[payloadLength]\n\nThe client first performs a legitimate WebSocket handshake.\n\nThe Escargot debugger accepts the connection:\n\n[+] WebSocket handshake accepted\n\nHTTP/1.1 101 Switching Protocols\nUpgrade: websocket\nConnection: Upgrade\nSec-WebSocket-Accept: voBbwZEm0j70WZ2O4Hx37ERFeqA=\n\nThis confirms that the PoC reaches the debugger through the expected\nWebSocket protocol rather than invoking the vulnerable function directly.\n\nThe client then sends the boundary-sized binary frame:\n\n[*] Sending binary frame:\n    opcode=0x2\n    payload_len=125\n\nThe test reports successful reproduction:\n\n[+] Confirmed: True[*] Process return code: -6\n\nThe -6 return code corresponds to process termination through SIGABRT. In\nthis test configuration, the important evidence is not the return code\nitself but the accompanying AddressSanitizer report identifying the invalid\nstack write.\nAddressSanitizer Evidence\n\nAddressSanitizer reports a stack-buffer overflow directly within the\nvulnerable receive function:\n\n[evidence] SUMMARY: AddressSanitizer: stack-buffer-overflow\n(/work/escargot/security-poc/build-debugger-asan/escargot+0x4fe03c)\n(BuildId: 1545896c0ed347436f48a03cdab84e73c634fadd)\nin Escargot::DebuggerTcp::receive(unsigned char*, unsigned long\u0026)\n\nThe top of the stack trace identifies DebuggerTcp::receive() as the\nlocation of the invalid memory access:\n\n[evidence] #0 0xaaaadfd0e03c\nin Escargot::DebuggerTcp::receive(unsigned char*, unsigned long\u0026)\n(/work/escargot/security-poc/build-debugger-asan/escargot+0x4fe03c)\n[evidence] #1 0xaaaadfcfeb98\nin Escargot::DebuggerEscargot::processEvents(\n    Escargot::ExecutionState*,\n    Escargot::Optional\u003cEscargot::ByteCodeBlock*\u003e,\n    bool\n)\n/work/escargot/src/debugger/DebuggerEscargot.cpp:767\n\nMost importantly, AddressSanitizer identifies the precise stack object that\nis exceeded:\n\n[evidence] [800, 925) \u0027buffer\u0027 (line 762)\n           \u003c== Memory access at offset 925 overflows this variable\n\nThe buffer object occupies stack offsets:\n\n[800, 925)\n\nThis represents exactly:\n\n925 - 800 = 125 bytes\n\nThe first byte outside the allocation is offset 925.\n\nAddressSanitizer reports the invalid access at exactly that offset:\n\nMemory access at offset 925 overflows this variable\n\nThe runtime evidence therefore precisely matches the source-level defect.\n\nFor a 125-byte buffer:\n\nStack object:       [800, 925)\nBuffer size:        125 bytes\nValid offsets:      800 through 924\nInvalid write:      925\nOverflow distance:  1 byte\n\n\nRon Edgerson\nVulnerability Researcher \u0026 Exploit Developer\n\nCVE Research | Binary Exploitation | Application \u0026 Systems Security\nResponsible Disclosure \u2022 Proof-of-Concept Development\n\n\ud83c\udf10 https://github.com/ob1sec\n\ud83d\udd17 https://www.linkedin.com/in/ronedgerson1\n\u003chttps://linkedin.com/in/yourhandle\u003e\n_______________________________________________\nSent through the Full Disclosure mailing list\nhttps://nmap.org/mailman/listinfo/fulldisclosure\nWeb Archives \u0026 RSS: https://seclists.org/fulldisclosure/"
        }
      ],
      "providerMetadata": {
        "dateUpdated": "2026-09-07T13:20:21Z",
        "orgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
        "shortName": "VULNARCHIVE"
      },
      "references": [
        {
          "tags": [
            "technical-description",
            "exploit"
          ],
          "url": "https://vuln.freearchive.org/archive/full-disclosure/2026/Aug/107"
        },
        {
          "tags": [
            "technical-description"
          ],
          "url": "https://seclists.org/fulldisclosure/2026/Aug/107"
        },
        {
          "url": "https://github.com/ob1sec"
        },
        {
          "url": "https://linkedin.com/in/yourhandle"
        },
        {
          "url": "https://nmap.org/mailman/listinfo/fulldisclosure"
        },
        {
          "url": "https://seclists.org/fulldisclosure/"
        },
        {
          "url": "https://www.linkedin.com/in/ronedgerson1"
        }
      ],
      "source": {
        "defect": [
          "https://seclists.org/fulldisclosure/2026/Aug/107"
        ],
        "discovery": "EXTERNAL"
      },
      "title": "Escargot v4.3.0-214-gfaee4437 Debugger WebSocket Off-by-One Stack Buffer Overflow",
      "x_gcve": [
        {
          "recordType": "advisory",
          "relationships": [],
          "vulnId": "GCVE-1988-2026-0079",
          "x_vulnarchive": {
            "archiveUrl": "https://vuln.freearchive.org/archive/full-disclosure/2026/Aug/107",
            "automated": true,
            "contentSha256": "6f519fea0759d29f0585a9df71b4ffec8f8b9e4a738c15c3324b929ad2764a89",
            "evidenceScore": 9,
            "messageId": "",
            "originalUrl": "https://seclists.org/fulldisclosure/2026/Aug/107",
            "policy": "vulnarchive-1",
            "sourceFormat": "text/html",
            "sourcePublishedAt": "2026-08-22T12:44:45Z"
          }
        }
      ]
    }
  },
  "cveMetadata": {
    "assignerOrgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
    "assignerShortName": "VULNARCHIVE",
    "datePublished": "2026-09-07T13:20:21Z",
    "dateUpdated": "2026-09-07T13:20:21Z",
    "state": "PUBLISHED",
    "vulnId": "GCVE-1988-2026-0079"
  },
  "dataType": "CVE_RECORD",
  "dataVersion": "5.2"
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.

Loading…

Detection rules are retrieved from Rulezet.

Loading…

Loading…

Loading…