You're Invited:Meet the Socket Team at RSAC and BSidesSF 2026, March 23–26.RSVP
Socket
Book a DemoSign in
Socket

@bytecodealliance/preview2-shim

Package Overview
Dependencies
Maintainers
4
Versions
43
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@bytecodealliance/preview2-shim - npm Package Compare versions

Comparing version
0.17.6
to
0.17.7
+72
-0
lib/browser/filesystem.js

@@ -9,2 +9,21 @@ import { streams } from './io.js';

/**
* @typedef {Object} FileDataEntry
* @property {Record<string, FileDataEntry>} [dir] - Directory contents (present for directories)
* @property {Uint8Array|string} [source] - File contents (present for files)
*/
/**
* @typedef {FileDataEntry} FileData
* Root file data structure representing a filesystem tree.
* Each entry is either a directory (has `dir` property) or a file (has `source` property).
* @example
* // A simple filesystem with one directory containing one file:
* const fileData = {
* dir: {
* 'myfile.txt': { source: new Uint8Array([72, 101, 108, 108, 111]) }
* }
* };
*/
export function _setFileData(fileData) {

@@ -326,2 +345,55 @@ _fileData = fileData;

/**
* Replace all preopens with the given set.
* @param {Record<string, FileData>} preopensConfig - Map of virtual paths to file data entries
*/
export function _setPreopens(preopensConfig) {
_preopens = [];
for (const [virtualPath, fileData] of Object.entries(preopensConfig)) {
_addPreopen(virtualPath, fileData);
}
}
/**
* Add a single preopen mapping.
* @param {string} virtualPath - The virtual path visible to the guest
* @param {FileData} fileData - The file data object representing the directory
*/
export function _addPreopen(virtualPath, fileData) {
const descriptor = new Descriptor(fileData);
_preopens.push([descriptor, virtualPath]);
if (virtualPath === '/') {
_rootPreopen = [descriptor, virtualPath];
}
}
/**
* Clear all preopens, giving the guest no filesystem access.
*
* This functionality exists mostly to maintain backwards compatibility. Prefer setting preopens
* via `WASIShim` rather than making top level changes to preopens using these functions.
*/
export function _clearPreopens() {
_preopens = [];
_rootPreopen = null;
}
/**
* Get current preopens configuration.
* @returns {Array<[Descriptor, string]>} Array of [descriptor, virtualPath] pairs
*/
export function _getPreopens() {
return [..._preopens];
}
/**
* Create a preopen descriptor for file data.
* This is used internally to create isolated preopen instances.
* @param {FileData} fileData - The file data object representing the directory
* @returns {Descriptor} A preopen descriptor
*/
export function _createPreopenDescriptor(fileData) {
return new Descriptor(fileData);
}
export const types = {

@@ -328,0 +400,0 @@ Descriptor,

+126
-3

@@ -47,2 +47,29 @@ import * as wasi from '@bytecodealliance/preview2-shim';

*
* For sandboxing, you can configure preopens, environment variables, and other
* capabilities via the `sandbox` option:
*
* ```js
* import { WASIShim } from "@bytecodealliance/preview2-shim/instantiation"
*
* // Fully sandboxed - no filesystem, network, or env access
* const sandboxedShim = new WASIShim({
* sandbox: {
* preopens: {}, // No filesystem access
* env: {}, // No environment variables
* args: ['program'], // Custom arguments
* enableNetwork: false, // Disable network (default: true for backward compat)
* }
* });
*
* // Limited filesystem access
* const limitedShim = new WASIShim({
* sandbox: {
* preopens: {
* '/data': '/tmp/guest-data', // Guest sees /data, maps to /tmp/guest-data
* '/config': '/etc/app' // Guest sees /config, maps to /etc/app
* }
* }
* });
* ```
*
* Note that this object is similar but not identical to the Node `WASI` object --

@@ -70,4 +97,16 @@ * it is solely concerned with shimming of preview2 when dealing with a WebAssembly

#http;
/** Isolated preopens for this instance */
#preopens;
/** Isolated environment for this instance */
#environment;
constructor(shims) {
/**
* Create a new WASIShim instance.
*
* @param {import('../types/instantiation.d.ts').WASIShimConfig} [config] - Configuration options
*/
constructor(config) {
// Support both old 'shims' parameter name and new 'config' style
const shims = config;
this.#cli = shims?.cli ?? wasi.cli;

@@ -80,2 +119,33 @@ this.#filesystem = shims?.filesystem ?? wasi.filesystem;

this.#http = shims?.http ?? wasi.http;
// Extract sandbox options
const sandbox = shims?.sandbox;
// Create isolated preopens if configured
if (sandbox?.preopens !== undefined) {
this.#preopens = createIsolatedPreopens(sandbox.preopens);
}
// Create isolated environment if env or args are configured
if (sandbox?.env !== undefined || sandbox?.args !== undefined) {
this.#environment = createIsolatedEnvironment(
sandbox?.env,
sandbox?.args,
this.#cli
);
}
// Apply network restrictions if disabled
if (sandbox?.enableNetwork === false) {
// Use the sockets module's built-in deny functions
if (this.#sockets._denyTcp) {
this.#sockets._denyTcp();
}
if (this.#sockets._denyUdp) {
this.#sockets._denyUdp();
}
if (this.#sockets._denyDnsLookup) {
this.#sockets._denyDnsLookup();
}
}
}

@@ -99,3 +169,4 @@

const obj = {};
obj[`wasi:cli/environment${versionSuffix}`] = this.#cli.environment;
obj[`wasi:cli/environment${versionSuffix}`] = this.#environment ?? this.#cli.environment;
obj[`wasi:cli/exit${versionSuffix}`] = this.#cli.exit;

@@ -119,3 +190,3 @@ obj[`wasi:cli/stderr${versionSuffix}`] = this.#cli.stderr;

obj[`wasi:filesystem/preopens${versionSuffix}`] = this.#filesystem.preopens;
obj[`wasi:filesystem/preopens${versionSuffix}`] = this.#preopens ?? this.#filesystem.preopens;
obj[`wasi:filesystem/types${versionSuffix}`] = this.#filesystem.types;

@@ -140,1 +211,53 @@

}
/**
* Create an isolated preopens object with its own preopen entries.
*
* @param {Record<string, string>} preopensConfig - Map of virtual paths to host paths
* @returns {object} A preopens object with Descriptor and getDirectories()
*/
function createIsolatedPreopens(preopensConfig) {
const { types, _createPreopenDescriptor } = wasi.filesystem;
const entries = [];
// Populate entries using the filesystem's descriptor creation
if (_createPreopenDescriptor) {
for (const [virtualPath, hostPath] of Object.entries(preopensConfig)) {
const descriptor = _createPreopenDescriptor(hostPath);
entries.push([descriptor, virtualPath]);
}
}
return {
Descriptor: types.Descriptor,
getDirectories() {
return entries;
},
};
}
/**
* Create an isolated CLI environment with its own env and args.
*
* @param {Record<string, string>} env - Environment variables
* @param {string[]} args - Command-line arguments
* @param {object} baseCli - The base CLI module to extend
* @returns {object} An isolated CLI environment object
*/
function createIsolatedEnvironment(env, args, baseCli) {
const envEntries = env ? Object.entries(env) : null;
const argsArray = args || null;
return {
...baseCli.environment,
getEnvironment() {
return envEntries ?? baseCli.environment.getEnvironment();
},
getArguments() {
return argsArray ?? baseCli.environment.getArguments();
},
initialCwd() {
return baseCli.environment.initialCwd();
},
};
}

@@ -741,2 +741,6 @@ import {

/**
* Replace all preopens with the given set.
* @param {Record<string, string>} preopens - Map of virtual paths to host paths
*/
export function _setPreopens(preopens) {

@@ -749,2 +753,7 @@ preopenEntries = [];

/**
* Add a single preopen mapping.
* @param {string} virtualPath - The virtual path visible to the guest
* @param {string} hostPreopen - The host filesystem path
*/
export function _addPreopen(virtualPath, hostPreopen) {

@@ -755,2 +764,32 @@ const preopenEntry = [descriptorCreatePreopen(hostPreopen), virtualPath];

/**
* Clear all preopens, giving the guest no filesystem access.
* Call this immediately after import to disable default full filesystem access.
*
* @example
* import { _clearPreopens } from '@bytecodealliance/preview2-shim/filesystem';
* _clearPreopens(); // Now guest has no filesystem access by default
*/
export function _clearPreopens() {
preopenEntries = [];
}
/**
* Get current preopens configuration.
* @returns {Array<[Descriptor, string]>} Array of [descriptor, virtualPath] pairs
*/
export function _getPreopens() {
return [...preopenEntries];
}
/**
* Create a preopen descriptor for a host path.
* This is used internally to create isolated preopen instances.
* @param {string} hostPreopen - The host filesystem path
* @returns {Descriptor} A preopen descriptor
*/
export function _createPreopenDescriptor(hostPreopen) {
return descriptorCreatePreopen(hostPreopen);
}
function convertFsError(e) {

@@ -757,0 +796,0 @@ switch (e.code) {

+1
-1
{
"name": "@bytecodealliance/preview2-shim",
"version": "0.17.6",
"version": "0.17.7",
"description": "WASI Preview2 shim for JS environments",

@@ -5,0 +5,0 @@ "author": "Guy Bedford, Eduardo Rodrigues<16357187+eduardomourar@users.noreply.github.com>",

@@ -54,2 +54,50 @@ # Preview2 Shim

## Sandboxing
By default, the preview2-shim provides full access to the host filesystem, environment variables,
and network - matching the default behavior of Node.js libraries. However, you can configure
sandboxing to restrict what guests can access.
### Using WASIShim for sandboxing
The `WASIShim` class accepts a `sandbox` configuration option to control access:
```js
import { WASIShim } from '@bytecodealliance/preview2-shim/instantiation';
// Fully sandboxed - no filesystem, network, or env access
const sandboxedShim = new WASIShim({
sandbox: {
preopens: {}, // No filesystem access
env: {}, // No environment variables
args: ['arg1'], // Custom arguments
enableNetwork: false, // Disable network access
}
});
// Limited filesystem access - map virtual paths to host paths
const limitedShim = new WASIShim({
sandbox: {
preopens: {
'/data': '/tmp/guest-data', // Guest sees /data, maps to /tmp/guest-data
'/config': '/etc/app' // Guest sees /config, maps to /etc/app
},
env: { 'ENV1': '42' }, // Only expose specific env vars
}
});
const component = await instantiate(loader, sandboxedShim.getImportObject());
```
### Notes on sandboxing
- By default (when no options are passed), the shim is providing full access to match typical
Node.js library behavior.
- Each `WASIShim` instance has its own isolated preopens, environment variables, and arguments.
Multiple instances with different configurations will not affect each other.
- The direct preopen functions (`_setPreopens`, `_clearPreopens`, etc.) modify global state and
affect all components not using `WASIShim` with explicit configuration. For isolation, prefer
using `WASIShim` with the `sandbox` option containing `preopens` and `env`.
- When `sandbox.enableNetwork: false`, all socket and HTTP operations will throw "access-denied" errors.
[jco]: https://www.npmjs.com/package/@bytecodealliance/jco

@@ -56,0 +104,0 @@

export type * as preopens from './interfaces/wasi-filesystem-preopens.d.ts';
export type * as types from './interfaces/wasi-filesystem-types.d.ts';
import type { Descriptor } from './interfaces/wasi-filesystem-types.d.ts';
/**
* Replace all preopens with the given set.
* @param preopens - Map of virtual paths to host paths
*/
export function _setPreopens(preopens: Record<string, string>): void;
/**
* Add a single preopen mapping.
* @param virtualPath - The virtual path visible to the guest
* @param hostPreopen - The host filesystem path
*/
export function _addPreopen(virtualPath: string, hostPreopen: string): void;
/**
* Clear all preopens, giving the guest no filesystem access.
* Call this immediately after import to disable default full filesystem access.
*/
export function _clearPreopens(): void;
/**
* Get current preopens configuration.
* @returns Array of [descriptor, virtualPath] pairs
*/
export function _getPreopens(): Array<[Descriptor, string]>;

@@ -68,2 +68,38 @@ /**

/**
* Sandbox configuration options for WASIShim
*/
interface SandboxConfig {
/** Filesystem preopens mapping (virtual path -> host path) */
preopens?: Record<string, string>;
/** Environment variables visible to the guest */
env?: Record<string, string>;
/** Command-line arguments */
args?: string[];
/** Whether to enable network access (sockets, HTTP). Default: true */
enableNetwork?: boolean;
}
/**
* Configuration options for WASIShim
*/
interface WASIShimConfig {
/** Custom CLI shim */
cli?: object;
/** Custom filesystem shim */
filesystem?: object;
/** Custom I/O shim */
io?: object;
/** Custom random shim */
random?: object;
/** Custom clocks shim */
clocks?: object;
/** Custom sockets shim */
sockets?: object;
/** Custom HTTP shim */
http?: object;
/** Sandbox configuration for restricting guest capabilities */
sandbox?: SandboxConfig;
}
/**
* (EXPERIMENTAL) A class that holds WASI shims and can be used to configure

@@ -112,2 +148,29 @@ * an instantiation of a WebAssembly component transpiled with jco

*
* For sandboxing, you can configure preopens, environment variables, and other
* capabilities via the `sandbox` option:
*
* ```js
* import { WASIShim } from "@bytecodealliance/preview2-shim/instantiation"
*
* // Fully sandboxed - no filesystem, network, or env access
* const sandboxedShim = new WASIShim({
* sandbox: {
* preopens: {}, // No filesystem access
* env: {}, // No environment variables
* args: ['program'], // Custom arguments
* enableNetwork: false, // Disable network
* }
* });
*
* // Limited filesystem access
* const limitedShim = new WASIShim({
* sandbox: {
* preopens: {
* '/data': '/tmp/guest-data', // Guest sees /data, maps to /tmp/guest-data
* '/config': '/etc/app' // Guest sees /config, maps to /etc/app
* }
* }
* });
* ```
*
* Note that this object is similar but not identical to the Node `WASI` object --

@@ -121,3 +184,3 @@ * it is solely concerned with shimming of preview2 when dealing with a WebAssembly

export class WASIShim {
constructor(shims?: Partial<WASIImportObject>);
constructor(config?: WASIShimConfig);

@@ -124,0 +187,0 @@ /**