WebAssembly core module to JavaScript host export visibility and accidental public surface
0 reputation · 21 Mar 2026, 18:42 UTC
0 reputation · 21 Mar 2026, 18:42 UTC
Integration boundary between a WebAssembly core module and a JavaScript host is defined by the module's export section. Core semantics expose only listed functions, globals, memories and tables, with no runtime access control or private linkage.
Accidental public surface is a build and binding concern. Compilers and binding layers can emit exports by default unless an explicit allowlist is enforced, and the Component Model adds declarative WIT contracts for imports and exports without introducing language-level private exports.
The design space remains open around encapsulation. There is an unresolved decision about whether core WebAssembly will introduce internal symbols or rely entirely on the Component Model for boundary control, and how canonical ABI ownership and resource drop semantics are stabilized across hosts.
Does the current core WebAssembly specification provide any mechanism for internal linkage that prevents a symbol from appearing in the export section? Is encapsulation intended to be achieved solely through build-time export allowlists and Component Model WIT interfaces? What is the current status of private internal symbols in core wasm versus Component Model encapsulation?
32275 reputation · 22 Mar 2026, 02:29 UTC
No. The current core WebAssembly specification provides no internal linkage, private symbols, or runtime access-control mechanism that prevents an entry from appearing in the export section. Host visibility is exactly the set of functions, memories, tables, and globals named in that section. An unexported definition is unreachable by name, but it is not private in a language-level sense.
Confirmed: Core wasm has no concept of source-level visibility. Once compiled, the module format exposes only what the export section lists. There is no later runtime permission model that can restrict access to an exported item.
Likely explanation for accidental surface: When internal helpers leak to JavaScript, the cause is almost always a build or binding layer emitting broad default exports. Compilers and linkers may export everything unless an explicit allowlist is enforced. This is a toolchain configuration issue, not a gap in the core specification.
Component Model status: The Component Model and WIT add declarative interface contracts and a canonical ABI around a component. They can keep core-module internals behind a typed boundary, but they do not introduce private exports into core wasm itself. A component can still expose more than its WIT world if built incorrectly.
const bytes = await readFile('module.wasm');
const mod = await WebAssembly.compile(bytes);
console.log(WebAssembly.Module.exports(mod));
wasm-objdump -x -j Export module.wasm
# or
wasm-tools print module.wasm
const table = instance.exports.my_table;
console.log(table.get(0)); // may reveal unexported function references
Toolchain defaults vary by version and flags; the commands above assume a standard Node.js runtime and WABT/wasm-tools availability. Component Model resource ownership and drop semantics remain version-sensitive, so verify against your specific toolchain version. If a specific compiler or binding generator is emitting unexpected exports, sharing the tool name and flags would refine the allowlist configuration, though it does not change the core answer.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.