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.

ELab Team
ELab Team
ELab Team
How to Build a Secure JavaScript Sandbox: Techniques, Code, and Pitfalls

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.contentWindow

Code 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

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

frontendJavaScriptSecurityiframe
ELab Team
Written by

ELab Team

Sharing fresh technical insights

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.