Files
vuln-osv/data/Go/GHSA-56cj-wgg3-x943.json
T

1 line
6.8 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{"schema_version":"1.9.0","id":"GHSA-56cj-wgg3-x943","published":"2026-03-10T18:30:58Z","modified":"2026-03-13T20:26:07.599912Z","aliases":["BIT-envoy-2026-26309","CVE-2026-26309"],"summary":"Envoy affected by off-by-one write in JsonEscaper::escapeString()","details":"### Summary\n\n An off-by-one write in Envoy::JsonEscaper::escapeString() can corrupt\n std::string null-termination, causing undefined behavior and potentially\n leading to crashes or out-of-bounds reads when the resulting string is later\n treated as a C-string.\n\n ### Details\n\n The bug is in the control-character escaping path in source/common/common/\n json_escape_string.h:67.\n\n - The function pre-sizes result to the final length: std::string\n result(input.size() + required_size, '\\\\');\n - For control characters (0x00..0x1f), it emits a JSON escape sequence of\n length 6: \\u00XX.\n - It uses sprintf(&result[position + 1], \"u%04x\", ...), which writes 5 chars +\n a trailing NUL (\\0) starting at result[position + 1].\n - Then it does position += 6; and writes result[position] = '\\\\'; to overwrite\n the NUL.\n - If the control character occurs at the end of the output (e.g., the input\n ends with \\x01), then after position += 6, position == result.size(), so\n result[position] is one past the end (off-by-one), violating std::string\n bounds/contract.\n\n Concretely, the problematic lines are:\n\n - source/common/common/json_escape_string.h:69 (sprintf(...))\n - source/common/common/json_escape_string.h:72 (result[position] = '\\\\';)\n\n Potentially reachable from request-driven paths that escape untrusted data,\n e.g. invalid header reporting:\n\n - source/common/http/header_utility.cc:538 ~ source/common/http/\n header_utility.cc:546 (escapes invalid header key for error text)\n\n Even when this doesn’t immediately crash, it can break the std::string\n requirement that c_str()[size()] == '\\0', which can later trigger UB (e.g., if\n passed to strlen, printf(\"%s\"), or any C API that expects NUL termination).\n \n \n ```cpp\n//clang++ -std=c++20 -O0 -g -fsanitize=address -fno-omit-frame-pointer\n repro_json_escape_asan.cc -o repro_json_escape_asan\n ASAN_OPTIONS=abort_on_error=1 ./repro_json_escape_asan\n#include <cstdint>\n #include <cstdio>\n #include <cstring>\n #include <string>\n #include <string_view>\n\n static uint64_t extraSpace(std::string_view input) {\n uint64_t result = 0;\n for (unsigned char c : input) {\n switch (c) {\n case '\\\"':\n case '\\\\':\n case '\\b':\n case '\\f':\n case '\\n':\n case '\\r':\n case '\\t':\n result += 1;\n break;\n default:\n if (c == 0x00 || (c > 0x00 && c <= 0x1f)) {\n result += 5;\n }\n break;\n }\n }\n return result;\n }\n\n static std::string escapeString(std::string_view input, uint64_t\n required_size) {\n std::string result(input.size() + required_size, '\\\\');\n uint64_t position = 0;\n\n for (unsigned char character : input) {\n switch (character) {\n case '\\\"':\n result[position + 1] = '\\\"';\n position += 2;\n break;\n case '\\\\':\n position += 2;\n break;\n case '\\b':\n result[position + 1] = 'b';\n position += 2;\n break;\n case '\\f':\n result[position + 1] = 'f';\n position += 2;\n break;\n case '\\n':\n result[position + 1] = 'n';\n position += 2;\n break;\n case '\\r':\n result[position + 1] = 'r';\n position += 2;\n break;\n case '\\t':\n result[position + 1] = 't';\n position += 2;\n break;\n default:\n if (character == 0x00 || (character > 0x00 && character <= 0x1f)) {\n std::sprintf(&result[position + 1], \"u%04x\",\n static_cast<int>(character));\n position += 6;\n // Off-by-one when this escape is the last output chunk:\n // position can become result.size(), so result[position] is out of\n bounds.\n result[position] = '\\\\';\n } else {\n result[position++] = static_cast<char>(character);\n }\n break;\n }\n }\n\n return result;\n }\n\n int main() {\n std::string input(4096, 'A');\n input.push_back('\\x01'); // ends with a control char -> triggers the buggy\n path at the end\n\n const uint64_t required = extraSpace(input);\n std::string escaped = escapeString(input, required);\n\n std::printf(\"escaped.size=%zu\\n\", escaped.size());\n unsigned char terminator = static_cast<unsigned char>(escaped.c_str()\n [escaped.size()]);\n std::printf(\"escaped.c_str()[escaped.size()] = 0x%02x\\n\", terminator);\n\n // If NUL termination is corrupted, this can read past the logical end.\n std::printf(\"strlen(escaped.c_str()) = %zu\\n\",\n std::strlen(escaped.c_str()));\n return 0;\n }```","affected":[{"package":{"name":"github.com/envoyproxy/envoy","ecosystem":"Go","purl":"pkg:golang/github.com/envoyproxy/envoy"},"versions":["1.37.0"],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/03/GHSA-56cj-wgg3-x943/GHSA-56cj-wgg3-x943.json"}},{"package":{"name":"github.com/envoyproxy/envoy","ecosystem":"Go","purl":"pkg:golang/github.com/envoyproxy/envoy"},"ranges":[{"type":"SEMVER","events":[{"introduced":"1.36.0"},{"last_affected":"1.36.4"}]}],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/03/GHSA-56cj-wgg3-x943/GHSA-56cj-wgg3-x943.json"}},{"package":{"name":"github.com/envoyproxy/envoy","ecosystem":"Go","purl":"pkg:golang/github.com/envoyproxy/envoy"},"ranges":[{"type":"SEMVER","events":[{"introduced":"1.35.0"},{"last_affected":"1.35.8"}]}],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/03/GHSA-56cj-wgg3-x943/GHSA-56cj-wgg3-x943.json"}},{"package":{"name":"github.com/envoyproxy/envoy","ecosystem":"Go","purl":"pkg:golang/github.com/envoyproxy/envoy"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"last_affected":"1.34.12"}]}],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/03/GHSA-56cj-wgg3-x943/GHSA-56cj-wgg3-x943.json"}}],"references":[{"type":"WEB","url":"https://github.com/envoyproxy/envoy/security/advisories/GHSA-56cj-wgg3-x943"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-26309"},{"type":"PACKAGE","url":"https://github.com/envoyproxy/envoy"}],"database_specific":{"cwe_ids":["CWE-193"],"github_reviewed":true,"github_reviewed_at":"2026-03-10T18:30:58Z","nvd_published_at":"2026-03-10T20:16:35Z","severity":"MODERATE"},"severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L"}]}