🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@memberjunction/code-execution

Package Overview
Dependencies
Maintainers
4
Versions
106
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@memberjunction/code-execution

Sandboxed code execution service for MemberJunction actions and agents

Source
npmnpm
Version
2.111.1
Version published
Weekly downloads
1.5K
-51.47%
Maintainers
4
Weekly downloads
 
Created
Source

@memberjunction/code-execution

Sandboxed JavaScript code execution service for MemberJunction AI agents and workflows.

Overview

This package provides secure, isolated execution of JavaScript code in a sandboxed environment using isolated-vm with worker process isolation. It's designed to enable AI agents to generate and run code for data analysis, transformations, and calculations without compromising system security or stability.

⚠️ Security: This package handles untrusted code execution. Please review security-research.md for comprehensive security analysis, threat model, and implementation details.

Features

  • Multi-Layer Security: 5 independent defense layers (process isolation, V8 isolates, module blocking, resource limits, library allowlist)
  • Fault Isolation: Workers run in separate processes - crashes don't affect main application
  • Automatic Recovery: Crashed workers automatically restart with circuit breaker protection
  • Timeout Protection: Configurable execution timeouts (default: 30 seconds)
  • Memory Limits: Configurable per-execution memory limits (default: 128MB)
  • Safe Library Access: Curated allowlist of npm packages with inline implementations
  • Console Logging: Captures console output for debugging
  • Type Safety: Full TypeScript support with comprehensive interfaces
  • Audit Trail: Integrated with MemberJunction action logging

Installation

npm install @memberjunction/code-execution

Usage

Direct TypeScript Usage

import { CodeExecutionService } from '@memberjunction/code-execution';

// Create service with optional worker pool configuration
const service = new CodeExecutionService({
  poolSize: 2,              // Number of worker processes (default: 2)
  maxQueueSize: 100,        // Max queued requests (default: 100)
  maxCrashesPerWorker: 3,   // Crashes before marking unhealthy (default: 3)
  crashTimeWindow: 60000    // Time window for crash counting (default: 60s)
});

// Initialize the worker pool (can also be done automatically on first execute)
await service.initialize();

// Execute code
const result = await service.execute({
  code: `
    const sum = input.values.reduce((a, b) => a + b, 0);
    const average = sum / input.values.length;
    output = { sum, average };
  `,
  language: 'javascript',
  inputData: { values: [10, 20, 30, 40, 50] },
  timeoutSeconds: 30,       // Optional: execution timeout (default: 30)
  memoryLimitMB: 128        // Optional: memory limit (default: 128)
});

if (result.success) {
  console.log(result.output); // { sum: 150, average: 30 }
  console.log(result.logs);   // Any console.log output from the code
} else {
  console.error(result.error);
  console.error(result.errorType); // 'TIMEOUT' | 'MEMORY_LIMIT' | 'SYNTAX_ERROR' | etc.
}

// Check worker pool health
const stats = service.getStats();
console.log('Active workers:', stats.activeWorkers);
console.log('Busy workers:', stats.busyWorkers);
console.log('Queue length:', stats.queueLength);

// Graceful shutdown (important for clean application exit)
await service.shutdown();

With Actions (for AI Agents)

Agents use the "Execute Code" action:

{
  "type": "Action",
  "action": {
    "name": "Execute Code",
    "params": {
      "code": "const total = input.prices.reduce((sum, p) => sum + p, 0); output = total;",
      "language": "javascript",
      "inputData": "{\"prices\": [10, 20, 30]}"
    }
  }
}

Supported Libraries

The sandbox includes these pre-approved npm packages:

  • lodash - Data manipulation and utilities
  • date-fns - Modern date library
  • mathjs - Advanced mathematics
  • papaparse - CSV parsing
  • uuid - UUID generation
  • validator - String validation and sanitization

Using Libraries in Code

const result = await service.execute({
  code: `
    const _ = require('lodash');
    const { format, addDays } = require('date-fns');
    const math = require('mathjs');

    // Group data by category
    const grouped = _.groupBy(input.data, 'category');

    // Calculate statistics
    const stats = {};
    for (const [category, items] of Object.entries(grouped)) {
      const values = items.map(i => i.value);
      stats[category] = {
        mean: math.mean(values),
        median: math.median(values),
        total: math.sum(values)
      };
    }

    output = stats;
  `,
  language: 'javascript',
  inputData: {
    data: [
      { category: 'A', value: 10 },
      { category: 'B', value: 20 },
      { category: 'A', value: 15 }
    ]
  }
});

Security Model

For detailed security analysis, see security-research.md

This package uses a defense-in-depth approach with five independent security layers:

  • Process Isolation - Workers run in separate OS processes
  • V8 Isolates - Each execution runs in isolated V8 context (via isolated-vm)
  • Module Blocking - Dangerous Node.js modules are blocked
  • Resource Limits - Enforced timeout and memory limits
  • Library Allowlist - Only pre-vetted libraries available

What Code CAN Do

  • Access input data via input variable
  • Set output data via output variable
  • Use console methods (log, error, warn, info)
  • Require allowed npm packages (lodash, date-fns, uuid, validator)
  • Perform calculations and data transformations
  • Use safe built-in objects (JSON, Math, Date, Array, Object, String, Number, Boolean)

What Code CANNOT Do

  • Access filesystem (fs, path modules blocked)
  • Make network requests (http, https, net, axios modules blocked, fetch() API disabled)
  • Spawn processes (child_process, cluster blocked)
  • Access system information (os, process blocked)
  • Access environment variables
  • Use eval() or Function constructor (for user code)
  • Run indefinitely (timeout enforced)
  • Exceed memory limits (128MB default)

API Reference

CodeExecutionService

execute(params: CodeExecutionParams): Promise<CodeExecutionResult>

Executes code in a sandboxed environment.

Parameters:

interface CodeExecutionParams {
  code: string;              // JavaScript code to execute
  language: 'javascript';    // Currently only 'javascript' supported
  inputData?: any;           // Data available as 'input' variable
  timeoutSeconds?: number;   // Execution timeout (default: 30)
  memoryLimitMB?: number;    // Memory limit (default: 128)
}

Returns:

interface CodeExecutionResult {
  success: boolean;           // Whether execution succeeded
  output?: any;              // Value of 'output' variable
  logs?: string[];           // Console output
  error?: string;            // Error message if failed
  errorType?: 'TIMEOUT' | 'MEMORY_LIMIT' | 'SYNTAX_ERROR' | 'RUNTIME_ERROR' | 'SECURITY_ERROR';
  executionTimeMs?: number;  // Execution duration
}

Error Handling

The service handles various error conditions gracefully:

const result = await service.execute({
  code: 'invalid syntax here',
  language: 'javascript'
});

if (!result.success) {
  switch (result.errorType) {
    case 'SYNTAX_ERROR':
      console.error('Code has syntax errors:', result.error);
      break;
    case 'TIMEOUT':
      console.error('Code execution timed out');
      break;
    case 'RUNTIME_ERROR':
      console.error('Runtime error:', result.error);
      break;
    case 'SECURITY_ERROR':
      console.error('Security violation:', result.error);
      break;
  }
}

Examples

Data Analysis

const result = await service.execute({
  code: `
    const _ = require('lodash');

    // Calculate key metrics
    const metrics = {
      totalSales: _.sumBy(input.sales, 'amount'),
      avgSale: _.meanBy(input.sales, 'amount'),
      topProducts: _.chain(input.sales)
        .groupBy('product')
        .map((items, product) => ({
          product,
          revenue: _.sumBy(items, 'amount')
        }))
        .orderBy('revenue', 'desc')
        .take(5)
        .value()
    };

    output = metrics;
  `,
  language: 'javascript',
  inputData: {
    sales: [
      { product: 'Widget', amount: 100 },
      { product: 'Gadget', amount: 200 },
      // ... more sales
    ]
  }
});

Date Manipulation

const result = await service.execute({
  code: `
    const { format, addDays, differenceInDays } = require('date-fns');

    const start = new Date(input.startDate);
    const end = new Date(input.endDate);

    output = {
      duration: differenceInDays(end, start),
      milestones: [
        format(addDays(start, 30), 'yyyy-MM-dd'),
        format(addDays(start, 60), 'yyyy-MM-dd'),
        format(addDays(start, 90), 'yyyy-MM-dd')
      ]
    };
  `,
  language: 'javascript',
  inputData: {
    startDate: '2025-01-01',
    endDate: '2025-12-31'
  }
});

CSV Processing

const result = await service.execute({
  code: `
    const Papa = require('papaparse');

    const parsed = Papa.parse(input.csvData, {
      header: true,
      dynamicTyping: true
    });

    // Filter and transform
    const processed = parsed.data
      .filter(row => row.status === 'active')
      .map(row => ({
        id: row.id,
        name: row.name,
        value: row.value * 1.1 // 10% markup
      }));

    output = processed;
  `,
  language: 'javascript',
  inputData: {
    csvData: 'id,name,value,status\n1,Item A,100,active\n2,Item B,200,inactive'
  }
});

Best Practices

  • Initialize Once: Create one CodeExecutionService instance and reuse it (worker pool is shared)
  • Shutdown Gracefully: Call service.shutdown() during application shutdown to clean up workers
  • Set Appropriate Timeouts: Adjust timeoutSeconds based on expected workload
  • Validate Input Data: Ensure input data is in expected format before execution
  • Handle Errors Gracefully: Always check result.success before using result.output
  • Monitor Pool Health: Use service.getStats() to monitor worker health and queue depth
  • Use Console Logging: Add console.log() statements for debugging
  • Leverage Libraries: Use lodash, date-fns, etc. instead of reinventing the wheel
  • Keep Code Focused: Break complex logic into smaller execution chunks
  • Review Security Docs: Read security-research.md for threat model and security considerations

Architecture

Worker Process Pool

The service maintains a pool of worker processes for fault isolation:

┌─────────────────────────────────────┐
│   Main Application Process          │
│                                      │
│  ┌────────────────────────────┐    │
│  │  CodeExecutionService       │    │
│  │                              │    │
│  │  ┌──────────────────────┐   │    │
│  │  │   WorkerPool         │   │    │
│  │  │   - Queue Requests   │   │    │
│  │  │   - Monitor Health   │   │    │
│  │  │   - Auto Restart     │   │    │
│  │  └──────────────────────┘   │    │
│  └────────────────────────────┘    │
│          │          │               │
└──────────┼──────────┼───────────────┘
           │          │ IPC (JSON)
    ┌──────▼───┐  ┌───▼──────┐
    │ Worker 1 │  │ Worker 2 │  (Separate OS Processes)
    │          │  │          │
    │ isolated │  │ isolated │
    │   -vm    │  │   -vm    │
    │          │  │          │
    └──────────┘  └──────────┘

Benefits of Process Isolation

  • Fault Tolerance: Worker crashes don't affect main app or other workers
  • Resource Isolation: Per-process memory limits and cleanup
  • Automatic Recovery: Crashed workers restart automatically
  • Circuit Breaker: Too many crashes → worker disabled to prevent crash loops

Limitations

  • Language Support: Currently only JavaScript (Python may be added in future)
  • Async Code: No support for async/await or Promises (synchronous code only)
  • Library Expansion: New libraries require code changes (not configurable at runtime)
  • Throughput: ~100-200 executions/sec per worker (horizontal scaling recommended for higher loads)

Contributing

This package is part of the MemberJunction project. See the main repository for contribution guidelines.

License

ISC

Keywords

memberjunction

FAQs

Package last updated on 27 Oct 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts