Two problems: 1) Sometimes toy_exec() needs to re-exec to gain dropped root permissions, 2) shouldn't recurse forever without exec, stack depth increases and we may leak other resources. Limit it to ~5 levels.
diff --git a/main.c b/main.c
index 5bd4460..cfa2cc9 100644
--- a/main.c
+++ b/main.c
@@ -119,12 +119,18 @@
 }
 
 // Like exec() but runs an internal toybox command instead of another file.
-// Only returns if it can't find the command, otherwise exit() when done.
+// Only returns if it can't run command internally, otherwise exit() when done.
 void toy_exec(char *argv[])
 {
   struct toy_list *which;
 
+  // Return if we can't find it, or need to re-exec to acquire root,
+  // or if stack depth is getting silly.
   if (!(which = toy_find(argv[0]))) return;
+  if (toys.recursion && (which->flags & TOYFLAG_ROOTONLY) && getuid()) return;
+  if (toys.recursion++ > 5) return;
+
+  // Run command
   toy_init(which, argv);
   if (toys.which) toys.which->toy_main();
   if (fflush(NULL) || ferror(stdout)) perror_exit("write");