JavaScript AST interpreter for isolated execution in browsers and Node.js.
Use cases: Plugin systems, user scripts, controlled execution environments Not for: Security sandboxing of untrusted code
Read the "behind the scenes" blog post
- Complete ES5 Support: Full implementation of all ES5 language features
- ES6+ Transformation: Optional Babel-based transform to ES5 AST
- Scope Isolation: Custom global environment, blocks
constructor/__proto__on built-ins - Tree-shakeable: Separate parser (~300 KB) from interpreter (~10 KB)
- Universal: Works in browsers and Node.js
npm install @mariozechner/jailjsimport { Interpreter, parse } from '@mariozechner/jailjs';
const interpreter = new Interpreter();
const result = interpreter.evaluate(parse('2 + 2'));
console.log(result); // 4- web - Browser playground with ES6+ examples and security demos
- node - CLI demo with eval() and timeout protection
- chrome-extension - Manifest V3 extension with user scripts
import { Interpreter, parse } from '@mariozechner/jailjs';
// With custom globals
const interpreter = new Interpreter({
console: { log: (...args) => console.log('[Sandbox]', ...args) },
myAPI: { getData: () => fetchData() }
}, {
maxOps: 100000 // Operation limit for timeout protection (optional)
});
const ast = parse('myAPI.getData()');
const result = interpreter.evaluate(ast);import { Interpreter } from '@mariozechner/jailjs';
import { transformToES5 } from '@mariozechner/jailjs/transform';
const code = `
const double = (x) => x * 2;
[1, 2, 3].map(double);
`;
const ast = transformToES5(code);
const result = new Interpreter().evaluate(ast);
console.log(result); // [2, 4, 6]Supports: arrow functions, classes, template literals, destructuring, spread operators, async/await, TypeScript, JSX.
Top-level await: Wrap code in an async IIFE:
const code = `
(async () => {
await new Promise(resolve => setTimeout(resolve, 1000));
console.log('Done!');
})();
`;Parse ahead-of-time to bundle only the interpreter (~10 KB):
// Build-time
import { parse } from '@mariozechner/jailjs/parser';
const ast = parse(userScript);
fs.writeFileSync('script.ast.json', JSON.stringify(ast));
// Runtime (bundle only interpreter)
import { Interpreter } from '@mariozechner/jailjs';
const ast = JSON.parse(fs.readFileSync('script.ast.json'));
new Interpreter().evaluate(ast);// Built-ins
console, Math, JSON, Date, RegExp
// Constructors (prototypes can be polluted!)
Array, Object, String, Number, Boolean
// ES6+ (for transformed code)
Symbol, Promise
// Errors
Error, TypeError, ReferenceError, SyntaxError, RangeError, EvalError, URIError
// Global functions
parseInt, parseFloat, isNaN, isFinite
encodeURI, encodeURIComponent, decodeURI, decodeURIComponent
// Blocked
Function: undefined // Blocked to prevent eval-like behavior
eval: undefined // Disabled unless you provide parser via options- ❌ Prototype pollution is possible (
Array.prototype,Object.prototype) - ❌ No prototype method allowlisting
- ❌ Many escape vectors exist
- ❌ No memory or execution time limits (only basic operation counter)
What is blocked:
[].constructor→undefined(on built-in types)obj.__proto__→undefinedFunction()→undefined- Global scope (
window,globalThis, etc.)
For untrusted code, use:
- SandboxJS - Prototype whitelisting and comprehensive security
- isolated-vm - V8 isolates for Node.js
- Web Workers or separate processes
JailJS gives you tools to build isolation (custom globals, operation limits, AST interpretation), but cannot guarantee security. You are responsible for validating use cases and layering additional protections.
- ✅ All operators, control flow, functions, closures
- ✅ Objects, arrays, prototypes,
thisbinding - ✅
try/catch/finally, error handling - ✅ Variable hoisting,
arguments
- ✅ Classes, arrow functions, template literals
- ✅
let/const, destructuring, spread - ✅ Async/await, promises
- ✅ TypeScript, JSX (optional)
- ❌ Generators (WIP)
- ❌ ES6 modules
- ❌ Proxies, Reflect, WeakRef
- ❌ SharedArrayBuffer, Atomics
~10-100x slower than native JavaScript. Use maxOps for timeout protection.
npm install
npm run build
npm test
npm run dev # Watch modeMIT