Hardened JavaScript for fearless cooperation through secure execution contexts and object-capability security
—
Source transformation and scope manipulation utilities for advanced SES use cases. These tools provide low-level access to SES's code transformation pipeline and scope management system.
import { transforms, scopeTerminators } from 'ses/tools.js';Collection of source-to-source JavaScript transformation functions used internally by SES for secure code execution.
/**
* Source transformation function signature
* @param source - JavaScript source code to transform
* @returns Transformed JavaScript source code
*/
type Transform = (source: string) => string;
/**
* Object containing all available transformation functions
*/
interface TransformLibrary {
rejectHtmlComments: Transform;
evadeHtmlCommentTest: Transform;
rejectImportExpressions: Transform;
evadeImportExpressionTest: Transform;
rejectSomeDirectEvalExpressions: Transform;
mandatoryTransforms: Transform;
applyTransforms: (source: string, transforms: Transform[]) => string;
}
const transforms: TransformLibrary;Usage Examples:
import { transforms } from 'ses/tools.js';
// Reject potentially dangerous HTML comments
const safeSource = transforms.rejectHtmlComments(`
// This would throw: <!-- comment -->
const x = 1;
`);
// Reject dynamic import expressions for security
const secureSource = transforms.rejectImportExpressions(`
// This would throw: import('dangerous-module')
const y = 2;
`);
// Apply all mandatory security transforms
const mandatorySecure = transforms.mandatoryTransforms(originalSource);
// Apply custom transform pipeline
const customTransforms = [
transforms.rejectHtmlComments,
transforms.rejectImportExpressions
];
const processedSource = transforms.applyTransforms(originalSource, customTransforms);Rejects source code containing HTML-like comment syntax to prevent parser confusion.
/**
* Reject source code containing HTML-like comments (<!-- or -->)
* @param source - JavaScript source code to check
* @returns Original source if safe
* @throws SyntaxError if HTML comments found
*/
function rejectHtmlComments(source: string): string;
/**
* Transform HTML-like comments to space-separated operators
* @param source - JavaScript source code to transform
* @returns Source with HTML comments converted to operators
*/
function evadeHtmlCommentTest(source: string): string;Usage Examples:
import { transforms } from 'ses/tools.js';
try {
// This will throw SyntaxError
transforms.rejectHtmlComments('const x = 1; <!-- comment -->');
} catch (error) {
console.log(error.message); // "Possible HTML comment rejected..."
}
// Evade rejection by converting to operators
const converted = transforms.evadeHtmlCommentTest('const x = 1; <!-- comment -->');
console.log(converted); // "const x = 1; < ! -- comment -- >"Prevents dynamic import expressions that could bypass module system security.
/**
* Reject source code containing dynamic import expressions
* @param source - JavaScript source code to check
* @returns Original source if safe
* @throws SyntaxError if import expressions found
*/
function rejectImportExpressions(source: string): string;
/**
* Transform import expressions to __import__ to evade rejection
* @param source - JavaScript source code to transform
* @returns Source with import expressions converted
*/
function evadeImportExpressionTest(source: string): string;Usage Examples:
import { transforms } from 'ses/tools.js';
try {
// This will throw SyntaxError
transforms.rejectImportExpressions("import('module').then(m => m.run())");
} catch (error) {
console.log(error.message); // "Possible import expression rejected..."
}
// Evade rejection by renaming import
const converted = transforms.evadeImportExpressionTest("import('module')");
console.log(converted); // "__import__('module')"Heuristically rejects some direct eval expressions that cannot be properly shimmed.
/**
* Reject source code that appears to contain direct eval expressions
* @param source - JavaScript source code to check
* @returns Original source if safe
* @throws SyntaxError if direct eval expressions found
* @note May have false positives and negatives - designed for innocent code
*/
function rejectSomeDirectEvalExpressions(source: string): string;Usage Examples:
import { transforms } from 'ses/tools.js';
try {
// This will throw SyntaxError
transforms.rejectSomeDirectEvalExpressions('eval("console.log(\'hello\')")');
} catch (error) {
console.log(error.message); // "Possible direct eval expression rejected..."
}
// This might not be caught (false negative)
const trickyEval = '(eval)("code")'; // Might pass throughBundles together transforms that must always be applied for security.
/**
* Apply all mandatory security transforms in the correct order
* @param source - JavaScript source code to secure
* @returns Source with all mandatory transforms applied
* @throws SyntaxError if dangerous patterns found
*/
function mandatoryTransforms(source: string): string;Usage Examples:
import { transforms } from 'ses/tools.js';
// Apply all security-critical transforms at once
const secureSource = transforms.mandatoryTransforms(`
function userCode() {
// User-provided code that needs security transforms
return Math.random();
}
`);
// Use in compartment
const compartment = new Compartment({
transforms: [transforms.mandatoryTransforms],
__options__: true
});Utility for applying multiple transforms in sequence.
/**
* Apply a sequence of transforms to source code
* @param source - Initial JavaScript source code
* @param transforms - Array of transform functions to apply in order
* @returns Source with all transforms applied sequentially
*/
function applyTransforms(source: string, transforms: Transform[]): string;Usage Examples:
import { transforms } from 'ses/tools.js';
// Custom transform pipeline
const myTransforms = [
transforms.rejectHtmlComments,
transforms.rejectImportExpressions,
(source) => source.replace(/console\.log/g, '/* console.log */')
];
const processedSource = transforms.applyTransforms(originalSource, myTransforms);
// Use in compartment
const compartment = new Compartment({
transforms: myTransforms,
__options__: true
});Utilities for managing scope boundaries and global object behavior in different execution modes.
/**
* Scope termination utilities for controlling variable scoping behavior
*/
interface ScopeTerminatorLibrary {
/** Scope terminator for strict mode execution */
strictScopeTerminator: any;
/** Factory function for creating sloppy mode scope terminators */
createSloppyGlobalsScopeTerminator: () => any;
}
const scopeTerminators: ScopeTerminatorLibrary;Usage Examples:
import { scopeTerminators } from 'ses/tools.js';
const { strictScopeTerminator, createSloppyGlobalsScopeTerminator } = scopeTerminators;
// Access strict mode scope terminator
const strictTerminator = strictScopeTerminator;
// Create sloppy mode scope terminator
const sloppyTerminator = createSloppyGlobalsScopeTerminator();
// These are typically used internally by SES's evaluation system
// but can be accessed for advanced use cases involving custom
// evaluation contexts and scope managementUsing transforms in compartment creation for custom code processing:
import 'ses';
import { transforms } from 'ses/tools.js';
lockdown();
// Create compartment with security transforms
const secureCompartment = new Compartment({
transforms: [transforms.mandatoryTransforms],
globals: { console: harden(console) },
__options__: true
});
// Create compartment with custom transform pipeline
const customCompartment = new Compartment({
transforms: [
transforms.rejectHtmlComments,
transforms.rejectImportExpressions,
// Add custom transforms
(source) => `"use strict";\n${source}`
],
__options__: true
});
// Evaluate code with applied transforms
const result = secureCompartment.evaluate(`
function calculate(x, y) {
return x + y;
}
calculate(5, 3);
`);Transforms are applied in the order specified. Security-critical transforms should typically come first:
// Correct order - security first
const transforms = [
transforms.mandatoryTransforms, // Security critical
myCustomTransform // Custom logic
];
// Incorrect order - custom transform might introduce vulnerabilities
const badTransforms = [
myCustomTransform, // Might add dangerous patterns
transforms.mandatoryTransforms // Too late to catch them
];The "evade" transforms are designed to work around the rejection transforms, but they may change code semantics:
// Original code
const code = 'const result = import("module");';
// Evade transform changes semantics
const evaded = transforms.evadeImportExpressionTest(code);
// Result: 'const result = __import__("module");'
// Note: __import__ is not the same as import()Transforms are applied synchronously and may impact performance for large codebases:
// For performance-critical applications, consider caching
const transformCache = new Map();
const cachedTransform = (source) => {
if (transformCache.has(source)) {
return transformCache.get(source);
}
const result = transforms.mandatoryTransforms(source);
transformCache.set(source, result);
return result;
};Install with Tessl CLI
npx tessl i tessl/npm-ses