From 81822c1c3d8879c19963fcc7b8c32972da621226 Mon Sep 17 00:00:00 2001 From: mohammadmseet-hue Date: Thu, 26 Mar 2026 00:54:08 +0100 Subject: [PATCH] security: sanitize schema strings in code generators to prevent injection The .fbs parser processes escape sequences in string constants, but the C++, PHP, and Rust code generators concatenate the parsed (unescaped) values directly into generated source code. A crafted file_extension or native_include value containing newlines and quotes can inject arbitrary code into the generated output. This adds SanitizeStringForCodeGen() which escapes backslashes, quotes, newlines, and other control characters before embedding schema strings in generated source code. Applied to: - C++ generator: file_extension (line 705) and native_include (line 266) - PHP generator: file_extension (line 801) - Rust generator: file_extension (line 2660) Similar to the fix for CVE-2023-36665 in protobuf's ruby_package generator. The Python generator already hex-escapes file_identifier, confirming this risk was previously recognized. --- include/flatbuffers/util.h | 21 +++++++++++++++++++++ src/idl_gen_cpp.cpp | 4 ++-- src/idl_gen_php.cpp | 2 +- src/idl_gen_rust.cpp | 2 +- 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/include/flatbuffers/util.h b/include/flatbuffers/util.h index d8387e175d..5b67417692 100644 --- a/include/flatbuffers/util.h +++ b/include/flatbuffers/util.h @@ -708,6 +708,27 @@ inline bool EscapeString(const char* s, size_t length, std::string* _text, return true; } +// Sanitize a string for safe embedding in generated source code string +// literals. Escapes backslashes, quotes, and newlines to prevent code +// injection via crafted .fbs schema fields (file_extension, native_include, +// native_type). +inline std::string SanitizeStringForCodeGen(const std::string& s) { + std::string result; + result.reserve(s.size()); + for (char c : s) { + switch (c) { + case '\\': result += "\\\\"; break; + case '"': result += "\\\""; break; + case '\n': result += "\\n"; break; + case '\r': result += "\\r"; break; + case '\t': result += "\\t"; break; + case '\0': result += "\\0"; break; + default: result += c; break; + } + } + return result; +} + inline std::string BufferToHexText(const void* buffer, size_t buffer_size, size_t max_length, const std::string& wrapped_line_prefix, diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index 9ad18a7b48..a10705fda3 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -263,7 +263,7 @@ class CppGenerator : public BaseGenerator { if (opts_.generate_object_based_api) { for (const std::string& native_included_file : parser_.native_included_files_) { - code_ += "#include \"" + native_included_file + "\""; + code_ += "#include \"" + flatbuffers::SanitizeStringForCodeGen(native_included_file) + "\""; } } @@ -702,7 +702,7 @@ class CppGenerator : public BaseGenerator { if (parser_.file_extension_.length()) { // Return the extension code_ += "inline const char *{{STRUCT_NAME}}Extension() {"; - code_ += " return \"" + parser_.file_extension_ + "\";"; + code_ += " return \"" + flatbuffers::SanitizeStringForCodeGen(parser_.file_extension_) + "\";"; code_ += "}"; code_ += ""; } diff --git a/src/idl_gen_php.cpp b/src/idl_gen_php.cpp index 4b05703e8e..480b2600bd 100644 --- a/src/idl_gen_php.cpp +++ b/src/idl_gen_php.cpp @@ -798,7 +798,7 @@ class PhpGenerator : public BaseGenerator { code += Indent + "public static function " + struct_def.name; code += "Extension()\n"; code += Indent + "{\n"; - code += Indent + Indent + "return \"" + parser_.file_extension_; + code += Indent + Indent + "return \"" + flatbuffers::SanitizeStringForCodeGen(parser_.file_extension_); code += "\";\n"; code += Indent + "}\n\n"; } diff --git a/src/idl_gen_rust.cpp b/src/idl_gen_rust.cpp index d62bbffa4d..045d154524 100644 --- a/src/idl_gen_rust.cpp +++ b/src/idl_gen_rust.cpp @@ -2657,7 +2657,7 @@ class RustGenerator : public BaseGenerator { if (parser_.file_extension_.length()) { // Return the extension code_ += "pub const {{STRUCT_CONST}}_EXTENSION: &str = \\"; - code_ += "\"" + parser_.file_extension_ + "\";"; + code_ += "\"" + flatbuffers::SanitizeStringForCodeGen(parser_.file_extension_) + "\";"; code_ += ""; }