Security
Sandbox model, restrictions, and what's locked down
Overview
Tide runs workflow code in a locked-down JavaScript sandbox. The runtime blocks code generation, removes dangerous globals, freezes prototypes, and restricts imports. This prevents workflows from escaping the sandbox, accessing host resources, or modifying the runtime itself.
Code Generation
Both eval() and the Function constructor are disabled:
eval("1 + 1"); // Error: eval() is disabled in Tide for security.
new Function("return 1"); // Error: Function constructor is disabled in Tide for security.
Function("return 1"); // Error: Function constructor is disabled in Tide for security.All constructor escape routes are blocked:
(() => {}).constructor("code")-- Arrow function constructor(async () => {}).constructor("code")-- Async function constructor(function*(){}).constructor("code")-- Generator function constructor(async function*(){}).constructor("code")-- Async generator function constructor
Removed Globals
The following globals are removed (set to undefined and frozen):
| Global | Why |
|---|---|
Deno | Runtime internals -- would allow file/network/process access |
process | Node.js global -- would allow env/argv/exit access |
WebAssembly | WASM execution -- could bypass sandbox restrictions |
SharedArrayBuffer | Cross-thread primitives -- removed for isolation |
Atomics | Cross-thread primitives -- removed for isolation |
WebSocket | Network access |
XMLHttpRequest | Network access |
Worker | Threading -- would allow parallel execution outside sandbox |
navigator | Browser API -- not applicable |
location | Browser API -- not applicable |
window | Browser API -- not applicable |
self | Browser API -- not applicable |
setTimeout | Use sleep() instead -- setTimeout is non-deterministic |
importScripts | Dynamic script loading |
Frozen Prototypes
All core JavaScript prototypes are frozen with Object.freeze():
Object.prototype,Array.prototype,String.prototype,Number.prototype,Boolean.prototypeRegExp.prototype,Error.prototype(and all error subtypes)Map.prototype,Set.prototype,WeakMap.prototype,WeakSet.prototypePromise.prototype,Symbol.prototype,ArrayBuffer.prototype,DataView.prototypeJSON,Math,Reflect- All typed array prototypes (
Int8Array,Uint8Array,Float64Array, etc.)
This prevents prototype pollution attacks:
Object.prototype.polluted = true; // TypeError: Cannot add property polluted, object is not extensibleImport Restrictions
Only local file imports are allowed. The module loader checks the URL scheme and rejects anything that isn't file://:
import { helper } from "./utils.ts"; // OK -- local file
import "https://deno.land/std/path/mod.ts"; // Error: Importing from 'https://' is not allowedError message: Importing from 'https://' is not allowed. Only local file imports are permitted.
File System Sandbox
All file operations (readFile, writeFile, readFileBytes, writeFileBytes, removeFile, listFiles) operate on the in-memory VFS, never the host filesystem. There is no API to access the real filesystem.
What IS Available
Despite the restrictions, workflows have access to:
- All standard JavaScript built-ins (String, Array, Object, Map, Set, Promise, etc.)
console.log()andconsole.error()(journaled for deterministic replay)Date.now()andnew Date()(frozen timestamp)- File operations on the virtual filesystem
sleep()for timed delaysstep()for transactional operationsSschema builder for input validation- TypeScript support (transpiled on the fly)
- JSON and regular expressions
Math(exceptMath.random-- works but produces the same value each time since prototypes are frozen)
Sandbox Initialization Order
- Runtime snapshot is loaded (includes
console,readFile,writeFile, etc.) - Frozen time is initialized (
Date.nowoverridden,performance.nowreturns 0) - Sandbox is initialized (eval disabled, globals removed, prototypes frozen)
- User module is loaded and evaluated
The sandbox is initialized AFTER frozen time but BEFORE user code runs, ensuring user code never has access to an unsandboxed environment.
Security Test Example
Tide includes a security test (examples/security-test/main.ts) that verifies all 10 protections:
eval()is blockednew Function()is blockedFunction()(without new) is blocked- Arrow function constructor escape is blocked
- Async function constructor escape is blocked
Denoglobal is undefinedWebAssemblyis undefined- Prototype pollution is blocked
- Normal operations (readFile/writeFile) still work
- Steps still work
Run it: tide run examples/security-test/main.ts
Related
- Workflow API — the capabilities workflows can use.
- Virtual file system — why file ops are sandboxed.
- Architecture — how the sandbox fits into the runtime.
- Your first workflow — what you can use in workflows.