Summary
Local-store namespace isolation is derived entirely from keccak256(module_name) — there is no check anywhere in the boot sequence that module names configured in engine.toml's [[modules]] list are actually unique. Two modules configured with the same [module].name share one local-store namespace outright: same prefix, same keys, same quota counter.
Affected code
crates/nexum-runtime/src/host/local_store_redb.rs — ModuleStore::module() / build_key()
crates/nexum-runtime/src/supervisor.rs — boot() (no uniqueness check across engine_cfg.modules)
Finding
ModuleStore::module(namespace) derives prefix = keccak256(namespace.as_bytes()), and build_key() always prepends the caller's own fixed prefix — there's no guest-suppliable namespace parameter, so a module can't forge its way into another module's range from inside the WIT surface (this part of the isolation design holds).
But Supervisor::boot() never checks that [module].name is unique across the configured module list before booting. If two entries share a name — accidentally, via copy-paste, or a deliberately malicious module manifest naming itself identically to a legitimate one already running — both get the identical keccak256 prefix and therefore full read/write/quota access to what the operator believed was an isolated store.
This is worse than the capability-escape issue in one respect: it's completely unlogged. No warning, no error — both modules boot and run normally, silently sharing state.
Impact
A malicious or careless module author can collide with another module's local-store namespace simply by naming their module identically in module.toml — no code-level exploit needed, just a naming collision that nothing detects.
Suggested fix
Validate [module].name uniqueness across all configured modules at boot (Supervisor::boot), and fail loudly on a collision.
Found via
Internal red-team exercise (malicious module developer persona). Verified dynamically: two fixture modules configured with the same name in their manifests, booted together via Supervisor::boot, successfully read back a value one of them wrote via local-store using the other module's store handle. A control test confirms distinct names stay fully isolated.
Summary
Local-store namespace isolation is derived entirely from
keccak256(module_name)— there is no check anywhere in the boot sequence that module names configured inengine.toml's[[modules]]list are actually unique. Two modules configured with the same[module].nameshare one local-store namespace outright: same prefix, same keys, same quota counter.Affected code
crates/nexum-runtime/src/host/local_store_redb.rs—ModuleStore::module()/build_key()crates/nexum-runtime/src/supervisor.rs—boot()(no uniqueness check acrossengine_cfg.modules)Finding
ModuleStore::module(namespace)derivesprefix = keccak256(namespace.as_bytes()), andbuild_key()always prepends the caller's own fixed prefix — there's no guest-suppliable namespace parameter, so a module can't forge its way into another module's range from inside the WIT surface (this part of the isolation design holds).But
Supervisor::boot()never checks that[module].nameis unique across the configured module list before booting. If two entries share a name — accidentally, via copy-paste, or a deliberately malicious module manifest naming itself identically to a legitimate one already running — both get the identicalkeccak256prefix and therefore full read/write/quota access to what the operator believed was an isolated store.This is worse than the capability-escape issue in one respect: it's completely unlogged. No warning, no error — both modules boot and run normally, silently sharing state.
Impact
A malicious or careless module author can collide with another module's local-store namespace simply by naming their module identically in
module.toml— no code-level exploit needed, just a naming collision that nothing detects.Suggested fix
Validate
[module].nameuniqueness across all configured modules at boot (Supervisor::boot), and fail loudly on a collision.Found via
Internal red-team exercise (
malicious module developerpersona). Verified dynamically: two fixture modules configured with the samenamein their manifests, booted together viaSupervisor::boot, successfully read back a value one of them wrote vialocal-storeusing the other module's store handle. A control test confirms distinct names stay fully isolated.