LockFlare

The production runtime.

The original Cipher runtime, and the one that serves most of what runs on it today. Native Node.js with allowlisted access to the npm ecosystem, per-domain memory isolation, and hot reloads in seconds. Your code and the machinery that executes it exist only in volatile process memory, never on the host filesystem.

// payments.js — a normal Express route router.post('/payments', async (req) => { // req.body is already decrypted — just use it const { amount, currency, customer_id } = req.body; const charge = await stripe.charges.create({ amount: Math.round(amount * 100), currency, customer: customer_id }); // return plain JSON — Cipher encrypts it on the way out return { transaction_id: charge.id, status: 'success' }; });

One vm context per tenant

Each domain gets its own isolated memory context created through Node's built-in vm module — the same sandbox primitive Node itself uses for require(), REPLs and vm.Script. Each context holds its own globals; nothing crosses between contexts unless the runtime injects it at creation. Your .listen() is captured — no socket is ever bound by your code; the engine dispatches requests straight into your Express, Koa or Fastify handler.

  • Per-sandbox memory budgets, per-request execution timeouts (30 seconds by default), and no access to the host filesystem or child_process.
  • Cluster mode runs one worker per licensed core; a crashed worker respawns in about two seconds while the rest keep serving.
  • Allowlisted host APIs, injected as real references: require, console, Buffer, process.env; timers and Promises; crypto, fetch, URL; node-cron.
  • Packages are host-installed once and exposed through an allowlisted require() — there is no per-project node_modules to poison, audit or ship.
Worker models and the package set
# on disk — persistent lf-engine ~70 KB native launcher, bootstrap shim inside license ~100 B bound to this address node ~120 MB from the distribution hash backup ~1 KB only while sealed # in RAM — volatile interpreter image · per-domain vm contexts · your source pre-built HTML bundles · host-loaded packages · your variables per-request keys · auth tokens # ephemeral: an ~8 KB bootstrap stub on a RAM-backed tmpfs, 0600, # alive only while the node process is. never on durable storage.

From exec to serving, in ten steps

Environment check

The engine refuses to start if debugging or tracing tools are present. Debugger-attach detection and shared-library injection protection guard the process from the first instruction.

License validation

The engine reads its license and validates it against the control plane. Licenses are IP-bound; an invalid or expired one halts immediately.

Interpreter fetch

The encrypted interpreter image arrives from the control plane, encrypted under a per-request symmetric key delivered with the payload.

Worker integrity lock

The bootstrap shim is SHA-256 verified against a hash compiled into the native binary. A single modified byte aborts execution before any key is used.

Pipe handoff

The engine spawns a Node child process, creates an anonymous pipe, and streams the decrypted interpreter image straight to its standard input. No file is written.

In-memory load

The bootstrap shim reads the image from the pipe and evaluates it inside the Node process. From here on the runtime exists only in RAM.

RAM scrub

The engine zeroes its in-memory copy of the decrypted interpreter, scrubs the decryption keys, and enters a heartbeat loop.

Bundle fetch

The live interpreter authenticates with its license and fetches the application bundle: accounts, environments, projects, components, pre-built HTML per domain.

Compile and register

For each registered domain the interpreter creates a fresh vm context and compiles its endpoints, middleware and services into it.

Cluster and listen

The master process forks one worker per allocated core and the cluster begins serving traffic.

Hot reload: an atomic swap, no restart

Code pushed from the app reaches running engines without a process restart. The control plane posts an encrypted, timestamp-fresh payload over an authenticated reload channel — stale signals are rejected as replay defence. On verification, the master re-fetches the bundle, compiles every project into fresh vm contexts, and atomically replaces the live sandbox registry. Workers finish in-flight requests against the old sandboxes; requests arriving after the swap see the new code. Under two seconds across an entire fleet, typically.

Static assets never touch the disk either: express.static and sendFile stream straight out of RAM, and your .env loads into the sandbox with a dotenv shim so config().parsed works without a filesystem.

# reload — Live, 3 servers signal encrypted · fresh (t+0.4 s) accepted srv-01 bundle re-fetched · 4 contexts swapped 1.1 s srv-02 bundle re-fetched · 4 contexts swapped 1.3 s srv-03 bundle re-fetched · 4 contexts swapped 1.2 s # in-flight requests finished on the old code. no restart.

Controls at a glance

Interpreter delivery

AES-256 under a per-request key. The runtime image itself.

Integrity

SHA-256. The bootstrap shim and the interpreter, verified before load.

Application bundle

AES-256. Your projects, components and HTML.

Reload signal

AES-256 plus a timestamp freshness window. App → control plane → interpreter.

Enclave handshake and backup

An HMAC-signed, single-use nonce for seal and unseal; an AES-256 backup of the password hashes under a license-derived key while sealed.

Session tokens and transport

AES-256 tokens bound to the client's address; optional AES-256 per-project encryption of frontend ↔ backend payloads.

Defence in depth, before your code runs

Web application firewall

SQL injection, XSS, command injection, path traversal, prototype pollution, known attack-tool user agents — inspected before tenant code runs, and every block logged with its classification.

Rate limiter

Per-IP leaky bucket with escalating cooldowns. WAF violations penalise the bucket; five violations mean a five-minute block.

Debug tool refusal

The engine will not start with strace, gdb or ltrace present — a deliberate speed bump against post-exploitation inspection.

Request timeouts

Handlers are bounded by a per-request timeout. A runaway request aborts with a 504 while the sandbox keeps serving the others.

Body size limit

Requests above the configured limit are rejected at the transport layer, before any application code executes.

Security headers

X-Content-Type-Options, X-Frame-Options: DENY, Referrer-Policy and Permissions-Policy on every response.

What it defends against — and what it does not

A threat model with an out-of-scope column is the only kind worth reading.

Defends against

  • Filesystem search for customer source — there is no source on disk
  • Disassembly of the engine — no customer or interpreter code inside it
  • Man-in-the-middle on delivery — TLS plus SHA-256 integrity verification
  • Replay of old delivery responses — per-request key material
  • Replay of reload signals — timestamp freshness window
  • Debugger attach for memory inspection — refused at startup, shut down on sight
  • Supply-chain poisoning of per-project dependencies — there is no per-project node_modules
  • Post-seal compromise — a sealed server has no interactive credentials

Explicitly out of scope

  • A compromised customer license — the root of trust for Enclave, in your custody
  • A compromised control plane — protected under its own security model
  • Memory scraping by a privileged local attacker on a running, unsealed machine — the honest limit; Enclave is the answer
  • Side-channel attacks — cache timing, Spectre-class, power analysis
  • Vulnerabilities in your own handler code — the WAF is in front of it, not inside it

Real infrastructure. No slides.

Bring your engineering team for a technical walkthrough of the runtime on a test server of yours, or read what it cannot do first — the Node limitations are written for the engineer who will run it.

Contact us