PROMPTLOG: DYNAMIC WORKER LOADER POC
Run user code in sandboxed Workers via Dynamic Worker Loader API
CLOUDFLARE WORKERS 2025.01.29
View source on GitHub
THE CONCEPT
Problem: How do you safely run user-provided JavaScript in a serverless environment?
Solution: Use Cloudflare's Dynamic Worker Loader API to create isolated Workers on-demand. Each piece of user code gets its own sandboxed environment with zero network access.
POST /submit → Hash code → Create Worker → Execute safely
1. WRANGLER CONFIG
Enable the Dynamic Worker Loader API in your wrangler.json:
{ "name": "promptlog", "main": "src/index.ts", "compatibility_date": "2024-01-15", "experimental": { "worker_loader": true } }
2. MAIN WORKER
Accept code, hash it, create a dynamic worker:
import { Hono } from 'hono'; const app = new Hono(); // Submit user code and get execution hash app.post('/submit', async (c) => { const { code } = await c.req.json(); // Hash the code to create unique worker ID const hash = await hashCode(code); // Create dynamic worker from user code await createDynamicWorker(hash, code, c.env); return c.json({ hash, url: `/run/${hash}` }); }); // Execute the user's code app.get('/run/:hash', async (c) => { const hash = c.req.param('hash'); const prompt = c.req.query('prompt') || ''; // Get the dynamic worker and run it const worker = c.env.WORKER_LOADER.get(hash); const response = await worker.fetch( new Request(`https://dummy/?prompt=${encodeURIComponent(prompt)}`) ); return response; }); async function hashCode(code: string): Promise<string> { const encoder = new TextEncoder(); const data = encoder.encode(code); const hashBuffer = await crypto.subtle.digest('SHA-256', data); const hashArray = Array.from(new Uint8Array(hashBuffer)); return hashArray.map(b => b.toString(16).padStart(2, '0')).join('').slice(0, 8); } export default app;
3. DYNAMIC WORKER CREATION
The core: create isolated workers from user code:
async function createDynamicWorker(hash: string, userCode: string, env: any) { // Wrap user code in a secure worker template const workerCode = ` export default { async fetch(request) { const url = new URL(request.url); const prompt = url.searchParams.get('prompt') || ''; try { // Execute user code ${userCode} // Return the result return new Response(JSON.stringify(result), { headers: { 'content-type': 'application/json' } }); } catch (error) { return new Response(JSON.stringify({ error: error.message }), { status: 500, headers: { 'content-type': 'application/json' } }); } } }; `; // Create the worker with network isolation await env.WORKER_LOADER.put(hash, workerCode, { globalOutbound: null // No network access }); }
4. USER CODE EXAMPLE
What users can submit (gets wrapped and executed):
// User submits this JavaScript: const words = prompt.split(' '); const reversed = words.reverse().join(' '); const result = { original: prompt, reversed: reversed, wordCount: words.length, timestamp: new Date().toISOString() }; // The wrapper will return this as JSON
HOW IT WORKS
- Submit code: POST JavaScript to
/submit
- Hash creation: Generate SHA-256 hash of the code
- Worker creation: Use Dynamic Worker Loader to create isolated environment
- Execute safely: Run user code with
globalOutbound: null
(no network) - Return result: Send back JSON response
SECURITY
- Network isolation:
globalOutbound: null
blocks all external requests - Memory limits: 128MB per Worker isolate
- CPU limits: 50ms execution time
- Sandboxed execution: Complete V8 isolate per user code
USE CASES
- Code playgrounds and educational platforms
- User-defined data transformations
- Custom business logic execution
- Serverless function-as-a-service