Hi! Congrats on the Okojo release - it looks great, especially the performance claims and the low-allocation design.
I ran Okojo 0.1.0-preview.1 through AFL++ / SharpFuzz (coverage-guided fuzzing) for about an hour. I know this is an early preview and a lot of things are explicitly marked "not implemented yet" (~211 NotImplementedException crashes, which I'm ignoring as expected for a 0.1 preview). But two findings look like things you'd want to fix before a wider release, so posting them here as a single heads-up.
Both findings also reproduce against main at commit f9997ab (2026-04-12).
Finding 1 - Unbounded parser recursion → StackOverflowException
Deeply nested expressions overflow the stack because the recursive-descent parser has no depth limit. StackOverflow in .NET is uncatchable - it terminates the host process immediately.
Minimal repro:
using Okojo.Runtime;
using var rt = JsRuntime.Create();
rt.MainRealm.Evaluate(new string('[', 10000));
// Process is killed - no try/catch can save it
Representative stack (the top frame varies depending on which parse function is in flight when the stack tips over):
Stack overflow.
at Okojo.Parsing.JsParser.ParsePrimary()
at Okojo.Parsing.JsParser.ParseMemberAndCall()
at Okojo.Parsing.JsParser.ParsePostfix()
at Okojo.Parsing.JsParser.ParseUnary()
at Okojo.Parsing.JsParser.ParseExponentiation()
at Okojo.Parsing.JsParser.ParseMultiplicative()
...
at Okojo.Parsing.JavaScriptParser.ParseScript(...)
at Okojo.Runtime.JsRealm.CompileScript(...)
at Okojo.Runtime.JsRealm.Evaluate(...)
Fuzzing found 117 inputs that hit this; they all trace back to the same class of bug (unlimited parser recursion). Smallest was 29 bytes: v[[k[[[{[[[[[[[[[[[[F=Qe[[[[[.
Standard fix is an explicit depth counter in the parser that throws JsParseException past some reasonable limit (e.g. Jint uses 200, Acornima uses 1000, etc.). Acornima just hard-errors with MaximumDepthReached.
Finding 2 - SetExecutionTimeout / SetMaxInstructions don't stop tight loops
The agent options expose SetExecutionTimeout(TimeSpan) and SetMaxInstructions(ulong), but they don't appear to fire for the simplest possible infinite loop:
using var rt = JsRuntime.CreateBuilder()
.UseAgent(agent =>
{
agent.SetExecutionTimeout(TimeSpan.FromSeconds(2));
agent.SetMaxInstructions(100_000);
})
.Build();
rt.MainRealm.Evaluate("while(true){}");
// Never returns. The 2s timeout and 100K instruction limit are both ignored.
Setting SetExecutionCancellationToken with a CancellationTokenSource that cancels after 2s also doesn't help - same hang.
Not sure if this is "known, will wire up in a later preview" or a bug - just wanted to flag it, since for anyone sandboxing untrusted JS with Okojo this is the core guarantee they'd rely on. If it's planned work, feel free to close this part.
Setup
- Okojo 0.1.0-preview.1 (NuGet) + verified against
main at f9997ab
- .NET 10 on Linux (WSL2)
- Fuzzer: AFL++ 4.x + SharpFuzz 2.2.0
- Seed corpus: ~10 small JS snippets (arrow, async, classes, destructure, loops, regex, try/catch, JSON, etc.)
- Run time: ~1 hour, ~2.6M executions, 328 saved crashes, 19 hangs
Thanks again for the library - looking forward to the next release.
Hi! Congrats on the Okojo release - it looks great, especially the performance claims and the low-allocation design.
I ran Okojo 0.1.0-preview.1 through AFL++ / SharpFuzz (coverage-guided fuzzing) for about an hour. I know this is an early preview and a lot of things are explicitly marked "not implemented yet" (~211
NotImplementedExceptioncrashes, which I'm ignoring as expected for a 0.1 preview). But two findings look like things you'd want to fix before a wider release, so posting them here as a single heads-up.Both findings also reproduce against
mainat commitf9997ab(2026-04-12).Finding 1 - Unbounded parser recursion → StackOverflowException
Deeply nested expressions overflow the stack because the recursive-descent parser has no depth limit. StackOverflow in .NET is uncatchable - it terminates the host process immediately.
Minimal repro:
Representative stack (the top frame varies depending on which parse function is in flight when the stack tips over):
Fuzzing found 117 inputs that hit this; they all trace back to the same class of bug (unlimited parser recursion). Smallest was 29 bytes:
v[[k[[[{[[[[[[[[[[[[F=Qe[[[[[.Standard fix is an explicit depth counter in the parser that throws
JsParseExceptionpast some reasonable limit (e.g. Jint uses 200, Acornima uses 1000, etc.). Acornima just hard-errors withMaximumDepthReached.Finding 2 -
SetExecutionTimeout/SetMaxInstructionsdon't stop tight loopsThe agent options expose
SetExecutionTimeout(TimeSpan)andSetMaxInstructions(ulong), but they don't appear to fire for the simplest possible infinite loop:Setting
SetExecutionCancellationTokenwith a CancellationTokenSource that cancels after 2s also doesn't help - same hang.Not sure if this is "known, will wire up in a later preview" or a bug - just wanted to flag it, since for anyone sandboxing untrusted JS with Okojo this is the core guarantee they'd rely on. If it's planned work, feel free to close this part.
Setup
mainatf9997abThanks again for the library - looking forward to the next release.