@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
TypeScript
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 };