UNPKG

@stevenleep/sandbox

Version:

A powerful JavaScript sandbox library that provides multiple sandbox implementation options for safely executing untrusted code in browser environments.

764 lines (750 loc) 21.6 kB
declare enum SandboxType { Proxy = "Proxy", WithEval = "WithEval", ShadowRealm = "ShadowRealm", Snapshot = "Snapshot" } /** * Base sandbox interface */ interface ISandbox { /** Sandbox name */ name: string; /** Sandbox type */ type: SandboxType; /** Sandbox proxy object */ proxy: WindowProxy | Record<PropertyKey, any>; /** Activate sandbox */ activate(): void; /** Deactivate sandbox */ deactivate(): void; /** Execute code */ execScript(code: string, timeoutMs?: number): any; /** Execute code asynchronously (supports await) */ execScriptAsync?(code: string, timeoutMs?: number): Promise<any>; /** Load ES module */ loadModule?(url: string): Promise<any>; /** Clean up resources */ destroy?(): void; /** Reset sandbox */ reset?(): void; } /** * Base sandbox options */ interface BaseSandboxOptions { /** Sandbox name */ name: string; /** Enable strict mode - disallows modifying global variables */ strictMode?: boolean; /** Timeout for code execution in milliseconds (0 means no timeout) */ timeLimit?: number; /** Memory limit in bytes (0 means no limit) */ memoryLimit?: number; /** Enable performance measurement */ enablePerformanceMeasure?: boolean; /** Custom error handler */ errorHandler?: (error: Error, code: string) => void; } /** * Proxy-based sandbox options */ interface ProxySandboxOptions extends BaseSandboxOptions { /** Additional blacklisted properties that won't be proxied */ blacklist?: string[]; /** Additional whitelisted properties that will be proxied */ whitelist?: string[]; /** Enable async execution (supports await) */ enableAsyncExecution?: boolean; /** Support ES modules */ supportESModule?: boolean; /** Security options */ security?: { /** Prevent prototype pollution attacks */ preventPrototypePollution?: boolean; /** Prevent access to sensitive APIs */ preventSensitiveAPIs?: boolean; /** Log security violations */ logViolations?: boolean; }; /** Custom error handler */ errorHandler?: (error: Error, code: string) => void; } /** * With+eval-based sandbox options */ interface WithEvalSandboxOptions extends BaseSandboxOptions { /** Global variables to inject into the sandbox */ globals?: Record<string, any>; /** Custom unscopables - properties that should not be proxied */ unscopables?: Record<string, boolean>; /** Validate code for potentially dangerous patterns before execution */ validateCode?: boolean; /** Allow access to network APIs (fetch, XMLHttpRequest, etc.) */ allowNetwork?: boolean; } /** * ShadowRealm-based sandbox options */ interface ShadowRealmSandboxOptions extends BaseSandboxOptions { /** Initialization code to run when the ShadowRealm is created */ initScript?: string; /** Force using polyfill even if native ShadowRealm is available */ forcePolyfill?: boolean; /** Force using iframe fallback even if ShadowRealm or polyfill is available */ forceIframe?: boolean; /** Options for module loading */ moduleOptions?: { /** Base URL for module resolution */ baseURL?: string; /** Trusted module sources (for security) */ trustedSources?: string[]; }; /** Security options */ security?: { /** Prevent access to sensitive APIs */ preventSensitiveAPIs?: boolean; /** Allow access to network APIs */ allowNetwork?: boolean; }; } /** * Snapshot-based sandbox options */ interface SnapshotSandboxOptions extends BaseSandboxOptions { /** Properties to ignore when taking snapshot */ ignoreProperties?: string[]; /** Validate code for potentially dangerous patterns before execution */ validateCode?: boolean; /** Allow access to network APIs (fetch, XMLHttpRequest, etc.) */ allowNetwork?: boolean; } /** * Proxy-based sandbox implementation */ declare class ProxySandbox implements ISandbox { /** Sandbox name */ name: string; /** Sandbox type */ type: SandboxType; /** Sandbox proxy object */ proxy: WindowProxy | Record<PropertyKey, any>; /** Sandbox's isolated context */ private sandboxContext; /** Whether the sandbox is active */ private active; /** Strict mode - disallows modifying global variables */ private strictMode; /** Blacklisted properties - these properties won't be proxied */ private blacklist; /** Whitelisted properties - these properties will be proxied */ private whitelist; /** Resource monitor for this sandbox */ private resourceMonitor; /** Sandbox options */ private options; constructor(options: ProxySandboxOptions); /** * Initialize sandbox context with a copy of necessary window properties */ private initSandboxContext; /** * Create proxy object for sandbox context */ private createProxy; /** * Activate the sandbox */ activate(): void; /** * Deactivate the sandbox */ deactivate(): void; /** * Execute code within the sandbox */ execScript(code: string, timeoutMs?: number): any; /** * Execute code with timeout */ private execScriptWithTimeout; /** * Execute code asynchronously within the sandbox */ execScriptAsync(code: string, timeoutMs?: number): Promise<any>; /** * Reset the sandbox */ reset(): void; /** * Destroy the sandbox */ destroy(): void; } /** * With + eval based sandbox implementation * Uses with statement and eval to execute code, isolating global variables */ declare class WithEvalSandbox implements ISandbox { /** Sandbox name */ name: string; /** Sandbox type */ type: SandboxType; /** Sandbox proxy object */ proxy: Record<PropertyKey, any>; /** Sandbox context object, stores global variables within the sandbox */ private context; /** Whether the sandbox is active */ private active; /** Strict mode - disallows modifying global variables */ private strictMode; /** Global properties that should not be proxied */ private unscopables; /** Resource monitor for this sandbox */ private resourceMonitor; /** Sandbox options */ private options; constructor(options: WithEvalSandboxOptions); /** * Initialize the isolated context */ private initContext; /** * Activate the sandbox */ activate(): void; /** * Deactivate the sandbox */ deactivate(): void; /** * Execute code within the sandbox */ execScript(code: string, timeoutMs?: number): any; /** * Execute code with timeout */ private execScriptWithTimeout; /** * Create a code executor */ private createExecuter; /** * Copy basic properties from the window object */ private copyWindowProperties; /** * Create sandbox proxy object */ private createProxy; /** * Reset sandbox context */ reset(): void; /** * Destroy sandbox */ destroy(): void; /** * Execute code asynchronously within the sandbox */ execScriptAsync(code: string, timeoutMs?: number): Promise<any>; } /** * ShadowRealm-based sandbox implementation * * Note: ShadowRealm API is currently an experimental feature not supported by all browsers * Reference: https://github.com/tc39/proposal-shadowrealm */ declare class ShadowRealmSandbox implements ISandbox { /** Sandbox name */ name: string; /** Sandbox type */ type: SandboxType; /** Sandbox proxy object */ proxy: Record<PropertyKey, any>; /** Whether the sandbox is active */ private active; /** ShadowRealm instance - TypeScript definition, the actual API might not be implemented yet */ private realm; /** Map of functions and values exported from ShadowRealm */ private exports; /** Resource monitor */ private resourceMonitor; /** Sandbox options */ private options; constructor(options: ShadowRealmSandboxOptions); /** * Initialize ShadowRealm */ private initializeShadowRealm; /** * Generate a script to set up security measures in the ShadowRealm */ private generateSecuritySetupScript; /** * Generate script to restrict access to sensitive APIs */ private generateRestrictedAPIsScript; /** * Generate script to block network access */ private generateNetworkBlockingScript; /** * Use iframe to simulate ShadowRealm as a final fallback */ private usePolyfill; /** * Create proxy object */ private createProxy; /** * Activate sandbox */ activate(): void; /** * Deactivate sandbox */ deactivate(): void; /** * Execute code in sandbox */ execScript(code: string, timeoutMs?: number): any; /** * Export function from main environment to ShadowRealm */ exportFunction(name: string, fn: Function): void; /** * Import function from ShadowRealm to main environment */ importFunction(name: string): Function; /** * Destroy sandbox */ destroy(): void; /** * Prepare code for execution by adding strict mode and validation */ private prepareCodeForExecution; /** * Execute code with resource monitoring */ private executeWithTimeout; /** * Execute code asynchronously with timeout */ execScriptAsync(code: string, timeoutMs?: number): Promise<any>; } /** * Snapshot-based sandbox implementation * * This sandbox has TWO modes: * 1. Traditional Mode (strictMode = false): Takes snapshot of window state and restores it when deactivated * 2. Isolation Mode (strictMode = true): Uses an isolated context instead of directly modifying window */ declare class SnapshotSandbox implements ISandbox { /** Sandbox name */ name: string; /** Sandbox type */ type: SandboxType; /** Sandbox proxy object */ proxy: WindowProxy | Record<PropertyKey, any>; /** Window object snapshot */ private windowSnapshot; /** Records modified properties */ private modifiedPropsMap; /** Isolated context for strict mode */ private isolatedContext; /** Whether the sandbox is active */ private active; /** Strict mode - uses isolated context instead of modifying window */ private strictMode; /** Properties to ignore when taking snapshots */ private ignoreProperties; /** Resource monitor for this sandbox */ private resourceMonitor; /** Sandbox options */ private options; constructor(options: SnapshotSandboxOptions); /** * Initialize isolated context for strict mode */ private initIsolatedContext; /** * Create proxy for isolated context in strict mode */ private createIsolatedProxy; /** * Activate the sandbox */ activate(): void; /** * Deactivate the sandbox */ deactivate(): void; /** * Execute code within the sandbox */ execScript(code: string, timeoutMs?: number): any; /** * Execute code asynchronously within the sandbox */ execScriptAsync(code: string, timeoutMs?: number): Promise<any>; /** * Execute code with timeout */ private execScriptWithTimeout; /** * Destroy the sandbox */ destroy(): void; /** * Create a snapshot of the current window object */ private takeWindowSnapshot; /** * Record current window object changes to the sandbox modification record */ private recordWindowSnapshot; /** * Restore window object to pre-activation state */ private restoreWindowSnapshot; /** * Restore sandbox modifications to window object */ private restoreSandboxSnapshot; } /** * Event Manager * Tracks event listeners added in the sandbox for proper cleanup when the sandbox is destroyed */ declare class EventManager { private listeners; /** * Add event listener */ addEventListener(sandboxName: string, target: EventTarget, type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; /** * Remove event listener */ removeEventListener(sandboxName: string, target: EventTarget, type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; /** * Clear all event listeners for a sandbox */ clearAllEventListeners(sandboxName: string): void; /** * Release all resources */ destroy(): void; } declare const eventManager: EventManager; /** * Performance measurement helper class */ declare class PerformanceMeasure { /** Measurement metrics */ private measures; /** Whether performance measurement is enabled */ private enabled; /** * Enable performance measurement */ enable(): void; /** * Disable performance measurement */ disable(): void; /** * Measure function execution time */ measure<T>(name: string, category: string, fn: () => T): T; /** * Record measurement result */ private recordMeasure; /** * Get measurement results */ getMeasures(category?: string): Record<string, any>; /** * Calculate average execution time */ getAverageDuration(category: string, name?: string): number; /** * Clear measurement results */ clearMeasures(category?: string): void; } declare const performanceMeasure: PerformanceMeasure; /** * Module Loader Interface */ interface ModuleLoader { /** * Load module */ loadModule(url: string): Promise<any>; /** * Register module */ registerModule(name: string, moduleExports: any): void; /** * Get registered module */ getModule(name: string): any; /** * Clear modules */ clearModules(): void; } /** * ES Module Loader * For loading ES modules in the sandbox */ declare class ESModuleLoader implements ModuleLoader { /** Registered modules */ private modules; /** Module loading cache */ private moduleCache; /** * Load ES module */ loadModule(url: string): Promise<any>; /** * Register module */ registerModule(name: string, moduleExports: any): void; /** * Get registered module */ getModule(name: string): any; /** * Clear modules */ clearModules(): void; /** * Fetch and evaluate module */ private fetchAndEvaluateModule; /** * Extract module name from URL */ private extractModuleName; } declare const moduleLoader: ESModuleLoader; /** * Sandbox error class * Enhances error information in sandbox */ declare class SandboxError extends Error { originalError: Error; sandboxName: string; code?: string; constructor(message: string, originalError: Error, sandboxName: string, code?: string); } /** * Format error information */ declare function formatError(error: Error, sandboxName: string, code?: string): SandboxError; /** * Wrap execution function, enhance error information */ declare function wrapExecution<T>(fn: () => T, sandboxName: string, code?: string): T; /** * Security helper for sandbox * Provides methods to enhance security of sandbox implementations */ declare class SecurityHelper { /** * Prevent prototype pollution attacks by freezing critical prototypes */ static preventPrototypePollution(): void; /** * Create a comprehensive list of properties that should be restricted in a sandbox * @returns Set of property keys that should be restricted */ static getDefaultRestrictedProperties(): Set<PropertyKey>; /** * Get a secure Function constructor wrapper that adds additional safety measures * @param timeout Timeout in milliseconds for code execution * @returns Secure Function constructor */ static getSecureFunction(timeout?: number): typeof Function; /** * Verify if code contains known dangerous patterns * @param code Code to check * @returns Whether the code passes security checks */ static validateCode(code: string): { safe: boolean; issues: string[]; }; } /** * Default global exports that should be provided to sandboxes */ declare function getDefaultSandboxGlobals(): Record<string, any>; /** * Resource monitor for sandbox * Monitors and limits resource usage within sandboxes */ declare class ResourceMonitor { /** Memory usage tracking */ private memoryUsage; /** CPU usage tracking (approximated by execution time) */ private cpuUsage; /** Start timestamp for performance measuring */ private startTime; /** Name of the sandbox being monitored */ private sandboxName; /** Memory limit in bytes (0 means no limit) */ private memoryLimit; /** Execution time limit in milliseconds (0 means no limit) */ private timeLimit; /** Whether to collect detailed metrics */ private collectMetrics; constructor(sandboxName: string, options?: { memoryLimit?: number; timeLimit?: number; collectMetrics?: boolean; }); /** * Start monitoring resources */ start(): void; /** * Stop monitoring and return execution metrics */ stop(): { executionTime: number; memoryUsage: number; exceededLimits: boolean; }; /** * Record current memory usage */ private recordMemoryUsage; /** * Get current memory usage */ private getCurrentMemoryUsage; /** * Check if resource limits are exceeded */ private checkLimits; /** * Get usage metrics */ getMetrics(): { sandboxName: string; memoryUsage: { timestamp: number; bytes: number; }[]; cpuUsage: { timestamp: number; duration: number; }[]; memoryLimit: number; timeLimit: number; }; /** * Reset monitoring */ reset(): void; } /** * Execute a function with timeout * @param fn Function to execute * @param timeoutMs Timeout in milliseconds * @returns Promise that resolves with the function result or rejects if timeout is exceeded */ declare function executeWithTimeout<T>(fn: () => T | Promise<T>, timeoutMs: number): Promise<T>; /** * Helper class for managing resource limits */ declare class ResourceLimiter { private monitors; /** * Create or get a resource monitor for a sandbox */ getMonitor(sandboxName: string, options?: { memoryLimit?: number; timeLimit?: number; collectMetrics?: boolean; }): ResourceMonitor; /** * Remove a monitor for a sandbox */ removeMonitor(sandboxName: string): void; /** * Get all monitors */ getAllMonitors(): Map<string, ResourceMonitor>; /** * Reset all monitors */ resetAllMonitors(): void; } declare const resourceLimiter: ResourceLimiter; /** * Memory management helper for sandbox * Helps detect and prevent memory leaks in sandbox */ declare class MemoryManager { /** Weak references to sandbox instances */ private sandboxRefs; /** Registry cleanup interval ID */ private cleanupIntervalId; /** Cleanup interval in milliseconds */ private cleanupInterval; constructor(); /** * Register a sandbox instance for memory management */ register(sandboxName: string, sandboxInstance: any): void; /** * Unregister a sandbox instance */ unregister(sandboxName: string): void; /** * Start automatic cleanup */ private startCleanup; /** * Stop automatic cleanup */ stopCleanup(): void; /** * Clean up references to garbage collected sandboxes */ cleanup(): void; /** * Destroy all registered sandboxes */ destroyAll(): void; /** * Check if a sandbox instance is still alive */ isAlive(sandboxName: string): boolean; /** * Break circular references within an object to help garbage collection */ static breakCircularReferences(obj: any, seen?: WeakSet<object>): void; } declare const memoryManager: MemoryManager; /** * Factory function to create sandbox */ declare function createSandbox(type: SandboxType, options: any): ISandbox; /** * Check if ShadowRealm is supported in the current environment * First checks native implementation, then checks for polyfill */ declare const isShadowRealmSupported: () => boolean; /** * Get the best available sandbox type for the current environment */ declare const getBestSandboxType: () => SandboxType; export { BaseSandboxOptions, ISandbox, MemoryManager, ProxySandbox, ProxySandboxOptions, ResourceMonitor, SandboxError, SandboxType, SecurityHelper, ShadowRealmSandbox, ShadowRealmSandboxOptions, SnapshotSandbox, SnapshotSandboxOptions, WithEvalSandbox, WithEvalSandboxOptions, createSandbox, createSandbox as default, eventManager, executeWithTimeout, formatError, getBestSandboxType, getDefaultSandboxGlobals, isShadowRealmSupported, memoryManager, moduleLoader, performanceMeasure, resourceLimiter, wrapExecution };