# Sandbox escape via host Function and guard bypass

Untrusted LLM code run with new Function, with(sandbox), or string-prefix guards that subclasses can override

_Area: AI and LLM app security. Seen in 3 disclosed reports; latest 2026-06-18. Updated 2026-10-31._

## How it works
A "sandbox" is built from language features that were never isolation boundaries. In JS, `new Function` compiles code in the host V8 context; wrapping it in `with (sandbox)` only prepends a scope, so the real global object stays reachable through the prototype chain or `Function('return this')()`. In Python, a guard that filters attribute names by `name.startswith('_')` assumes `name` is a plain `str`; `isinstance` accepts subclasses, so a subclass with an overridden `startswith` returns False and the underscore check is defeated. The broken assumption in both: the guard's own primitives (the global object, the string type) are trusted and cannot be reached or reshaped by the code being checked.

## Where it shows up
- `new Function(...)` or `eval` executing LLM- or user-supplied code, especially under `with (sandbox)` [E2](https://bugbountylibrary.com/r/ghsa%3AGHSA-p69m-4f92-2v84.md)[E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-vmmj-pfw7-fjwp.md)
- A regex blocklist as the only defense, matching literal strings like `require` or `fs` [E2](https://bugbountylibrary.com/r/ghsa%3AGHSA-p69m-4f92-2v84.md)[E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-vmmj-pfw7-fjwp.md)
- Globals shadowed as `undefined` in a plain object rather than removed from the scope chain [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-vmmj-pfw7-fjwp.md)
- Attribute-name filters using `isinstance(name, str)` plus `startswith('_')` [E1](https://bugbountylibrary.com/r/ghsa%3AGHSA-6vh2-h83c-9294.md)
- `type`, `getattr`, or `Function`/`constructor` left reachable in a "safe" builtins set [E1](https://bugbountylibrary.com/r/ghsa%3AGHSA-6vh2-h83c-9294.md)[E2](https://bugbountylibrary.com/r/ghsa%3AGHSA-p69m-4f92-2v84.md)
- A tool advertising `sandbox: true` while running in the host process [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-vmmj-pfw7-fjwp.md)

## How to review
Identify the exact isolation primitive. If it is `with` + `new Function`, or a name-prefix filter, it is not a boundary: confirm the code runs in a separate process, VM context, or container with no host globals. The invariant: untrusted code must not be able to obtain a reference to the host global object, the real `Function` constructor, or `process`/`require`/`Popen`, by any path including prototype chains and subclass overrides. Check that guards compare against exact types (`type(name) is str`), not `isinstance`, and that blocklists are not the sole control.

## Variants seen
- Python: `str` subclass overrides `startswith` to bypass underscore guard, then `__subclasses__` walk to `Popen` [E1](https://bugbountylibrary.com/r/ghsa%3AGHSA-6vh2-h83c-9294.md)
- Node: `Function('return this')()` plus string-concatenated `require` defeats regex blocklist [E2](https://bugbountylibrary.com/r/ghsa%3AGHSA-p69m-4f92-2v84.md)
- Node: prototype-chain `({}).constructor.constructor('return process')()` recovers `process`, reaching `fs`/`child_process` [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-vmmj-pfw7-fjwp.md)

## Impact and severity
All three reached host OS command execution or arbitrary module access from LLM-controlled code, so severity is high to critical. It is worse because the tool advertises sandboxing, inviting callers to pass untrusted model output, and because a single missed path (one regex, one subclass) is enough.

## Evidence
- E1: https://bugbountylibrary.com/r/ghsa%3AGHSA-6vh2-h83c-9294.md
- E2: https://bugbountylibrary.com/r/ghsa%3AGHSA-p69m-4f92-2v84.md
- E3: https://bugbountylibrary.com/r/ghsa%3AGHSA-vmmj-pfw7-fjwp.md
