CVE-2026-38755: BusyBox ash function-recursion stack overflow
Summary
CVE-2026-38755 is uncontrolled shell-function recursion in BusyBox ash. A function can call itself indefinitely, causing the evalcommand() → evalfun() → evaltree() cycle to consume the native process stack until the applet terminates.
The CNA describes this as a “heap overflow in evalcommand()” in BusyBox v1.38.0.
The bug is scored as CVSS 7.5 (High) by CISA-ADP.
Affected versions
BusyBox builds containing the ash applet are affected from version 0.52 through 1.38.0, inclusive. The latest tested development commit after the 1.38.0 release, ec0c5cc142f1, is also affected. No fixed release is available at the time of writing.
Root cause
After command lookup, evalcommand() dispatches a shell function to evalfun():
case CMDFUNCTION:
if (evalfun(cmdentry.u.func, argc, argv, flags))
goto raise;
break;
evalfun() saves the caller’s shell state and evaluates the function body:
evaltree(func->n.ndefun.body, flags & EV_TESTED);
If that body invokes the same function, evaltree() reaches evalcommand() again, which dispatches another evalfun() call. The vulnerable code has no active-function depth check before this recursion.
The simple input below therefore creates an unbounded native call chain:
f(){ f; }; f
The eventual fault may land in argument expansion or a libc helper because those are the operations executing when the nearly exhausted stack crosses its guard page. That landing site does not change the root cause; the repeating evaluator frames identify it.
Evidence
AddressSanitizer builds of Git tag 1_37_0 (be7d1b7b1701), the official 1.38.0 source tarball, and development commit ec0c5cc142f1 all terminated with a stack overflow. The tarball’s shell/ash.c is byte-for-byte identical to the file at the 1.38.0 release commit, fc71374dfccd. The ec0c5cc142f1 run produced:
ERROR: AddressSanitizer: stack-overflow
#0 strcspn
#1 argstr shell/ash.c:7115
#2 expandarg shell/ash.c:8408
#3 fill_arglist shell/ash.c:9199
#4 evalcommand shell/ash.c:10965
#5 evaltree shell/ash.c:9755
#6 evalfun shell/ash.c:10339
#7 evalcommand shell/ash.c:11189
#8 evaltree shell/ash.c:9755
#9 evalfun shell/ash.c:10339
GDB stopped on SIGSEGV and showed the evalfun() / evalcommand() / evaltree() triple repeating down the native stack. This is runtime evidence against the public record’s heap-overflow wording.
On a non-sanitized build at commit 244c0a01eece, the same input exited with status 139 (SIGSEGV). The denial of service therefore reproduces without sanitizer instrumentation.
Fix
I submitted a patch that tracks active shell-function calls and raises a normal shell error at a fixed limit. The decrement is placed on the existing funcdone cleanup path so an error raised inside the function body unwinds the counter:
if (func_depth >= MAX_ASH_FUNC_DEPTH)
ash_msg_and_raise_error("function recursion limit exceeded");
func->count++;
func_depth++;
/* evaluate the function body */
funcdone:
/* restore shell state */
func_depth--;
After applying the submitted patch to the current upstream source, the default-stack sanitizer build returned:
ash: line 0: function recursion limit exceeded
The patch was public on 2026-06-16 and is waiting for review.
As with the AWK recursion patch, the submitted limit is 1000 and is not a stack-size-independent guarantee. My -O0 sanitizer build hit the guard with the normal 8 MiB stack but still overflowed at 1 MiB and below. Sanitizer frame sizes are not production sizing data; this result means constrained targets should validate or lower the limit rather than treating 1000 as universal.
Exploit
The attacker needs the ability to make ash execute crafted shell text. The demonstrated effect is reliable process-stack exhaustion and termination.
I did not observe a heap overflow, out-of-bounds heap access, controlled memory write, code execution, privilege transition, or cross-process effect. The result supports process denial of service and a CWE-674 uncontrolled-recursion classification.
Mitigation
As of 2026-07-16 there is no merged upstream fix. Do not execute untrusted shell programs with an affected BusyBox ash. Integrators can backport the public function-depth patch, but should select and test a conservative limit for the smallest stack supported by their target.
References
- CVE.org: CVE-2026-38755
- NVD: CVE-2026-38755
- BusyBox patch:
ash: fix stack overflow in evalfun() - BusyBox
ashsource introduction:cb57d551a207 - BusyBox 0.52 tag commit
- BusyBox 1.37.0 tag commit
- BusyBox 1.38.0 release announcement and changelog
- BusyBox 1.38.0 source tarball
- BusyBox 1.38.0 release commit:
fc71374dfccd - BusyBox upstream head used for re-verification