Engineering

JavaScript Transforms Now Run in a Secure QuickJS Sandbox

JavaScript transforms are now executed inside a QuickJS WebAssembly sandbox with memory isolation, CPU time limits, and no network access. Same API, stronger security.

Hookbase Team
3 min read

A Better Runtime for JavaScript Transforms

JavaScript transforms are one of the most flexible tools in Hookbase. You write a transform(data) function, and Hookbase runs it against every incoming webhook payload before delivery. It is powerful, but running arbitrary user code on shared infrastructure requires careful isolation.

Today we are shipping a new execution engine for JavaScript transforms: QuickJS compiled to WebAssembly. This replaces the previous evaluation approach with a fully sandboxed runtime that provides stronger security guarantees without changing the transform API.

What Changed

Memory Isolation

Each transform execution gets its own 4 MB memory sandbox. The JavaScript code cannot access the host environment, other customers' transforms, or any Hookbase internals. The sandbox is created fresh for each execution and destroyed afterward -- there is no shared state between runs.

CPU Time Limits

Transforms are interrupted after 5 seconds of execution. If your code enters an infinite loop, hits an exponential algorithm on a large input, or otherwise takes too long, it is terminated cleanly with an error message. This prevents a single runaway transform from affecting other deliveries.

No Network Access

The sandbox has no access to fetch, import, require, or any I/O operations. JavaScript transforms are pure data transformations: data in, data out. This eliminates an entire class of potential security issues (SSRF, data exfiltration, etc.) by design.

Writing Transforms

The API is unchanged. Write a transform(data) function that receives the webhook payload and returns the result:

function transform(data) {
  return {
    id: data.id,
    email: data.customer?.email || null,
    total: data.amount / 100,
    items: data.line_items.map(item => ({
      name: item.description,
      qty: item.quantity
    }))
  };
}

You have access to these global variables:

| Variable | Description | |----------|-------------| | data / payload | The full webhook payload (parsed JSON object) | | headers | The original request headers | | eventId | The Hookbase event ID | | sourceId | The source that received the webhook |

Standard JavaScript built-ins are available: JSON, Date, Math, String, Array, Object, parseInt, parseFloat, RegExp, and all standard prototype methods.

What Is QuickJS?

QuickJS is a small, embeddable JavaScript engine created by Fabrice Bellard. It implements the full ES2023 specification in a compact codebase that compiles to WebAssembly. Running it inside Cloudflare Workers gives us:

  • Deterministic execution -- Same input always produces the same output, regardless of the host environment
  • Fast startup -- The WASM module is cached after first load; subsequent executions start in microseconds
  • Spec compliance -- Full ES2023 support including optional chaining, nullish coalescing, array methods, and destructuring

Migration

This is a transparent change. All existing JavaScript transforms continue to work without modification. If you encounter any issues with a transform that previously worked, please reach out at [email protected] and we will investigate.

What's Next

We are exploring support for TypeScript transforms (compiled to JavaScript before execution) and the ability to include shared utility functions across transforms. Stay tuned.

engineeringsecuritytransformsjavascriptquickjswasmsandbox

Ready to Try Hookbase?

Start receiving, transforming, and routing webhooks in minutes.

Get Started Free