How to Build a Secure JavaScript Sandbox: Techniques, Code, and Pitfalls
This article explains the concept of JavaScript sandboxing, outlines common use cases, walks through several implementation strategies—from simple eval wrappers to with‑Proxy‑iframe combos—and discusses sandbox escape techniques and how to mitigate them, providing practical code examples throughout.
What Is a Sandbox?
In computer security, a sandbox is an isolation mechanism that runs untrusted code in a separate environment so that its execution cannot affect the surrounding program.
Typical Application Scenarios
Running JSONP responses or unknown third‑party libraries.
Vue template expressions, which are evaluated in a restricted scope.
Online code editors (e.g., CodeSandbox) that need to prevent scripts from affecting the host page.
Plugin systems where plugins must be confined to a controlled environment.
Implementing a JavaScript Sandbox
1. The Simplest Sandbox
const ctx = {
func: variable => {
console.log(variable)
},
foo: 'foo'
}
function poorestSandbox(code, ctx) {
eval(code) // executed in the function scope
}
const code = `
ctx.foo = 'bar'
ctx.func(ctx.foo)
`
poorestSandbox(code, ctx) // logs "bar"This approach forces every variable access to be prefixed with the context object, which is impractical for third‑party code.
2. Using with
function veryPoorSandbox(code, ctx) {
with (ctx) {
eval(code)
}
}
const code = `
foo = 'bar'
func(foo)
`
veryPoorSandbox(code, ctx) // logs "bar"The with statement adds the context object to the top of the scope chain, allowing unprefixed variable access.
3. with + Proxy
By wrapping the context in a Proxy and intercepting the has trap, we can enforce a whitelist and throw errors for undefined variables.
function withedYourCode(code) {
code = 'with(globalObj){' + code + '}'
return new Function('globalObj', code)
}
const access_white_list = ['Math', 'Date']
const ctxProxy = new Proxy(ctx, {
has(target, prop) {
if (access_white_list.includes(prop)) return target.hasOwnProperty(prop)
if (!target.hasOwnProperty(prop)) throw new Error(`Invalid expression - ${prop}!`)
return true
}
})
function littlePoorSandbox(code, ctx) {
withedYourCode(code).call(ctx, ctx)
}4. Native Isolation with iframe
Creating an iframe provides a native browser sandbox where the global object is isolated from the parent page.
const iframe = document.createElement('iframe')
document.body.appendChild(iframe)
const sandboxGlobal = iframe.contentWindowCode executed inside the iframe cannot affect the main page unless explicitly shared.
5. Combining iframe , with , and Proxy
By using the iframe’s global object as the with target and a Proxy to control access, we can isolate most globals while allowing a configurable whitelist of shared properties.
class SandboxGlobalProxy {
constructor(sharedState) {
const iframe = document.createElement('iframe')
document.body.appendChild(iframe)
const sandboxGlobal = iframe.contentWindow
return new Proxy(sandboxGlobal, {
has(target, prop) {
if (sharedState.includes(prop)) return false
if (!target.hasOwnProperty(prop)) throw new Error(`Invalid expression - ${prop}!`)
return true
}
})
}
}Sandbox Escape Techniques
Accessing parent objects via window.parent bypasses the sandbox.
Modifying prototypes (e.g., ({}).constructor.prototype) can reach the outer environment.
// Example of prototype escape
({}).constructor.prototype.toString = () => console.log('Escape!')
({}).toString() // logs "Escape!"Towards a Perfect Sandbox
Some projects build custom interpreters that parse the source code and execute statements under strict control, eliminating many escape vectors.
function almostPerfectSandbox(code, ctx, illegalOperations) {
return myInterpreter(code, ctx, illegalOperations)
}Conclusion
The sandbox concept is flexible; the right implementation depends on the specific requirements, such as the level of isolation, performance, and the need to share certain globals. Preventing sandbox escape remains an ongoing challenge.
References
Writing a JavaScript framework – Sandboxed Code Evaluation
说说 JS 中的沙箱
MDN – with statement
MDN – Proxy object
CodeSandbox website
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
