Skip to content

Prototype pollution: api.add() mount path with a __proto__/constructor.prototype segment writes to Object.prototype #302

Description

@Shinrai

Summary

api.slothlet.api.add(path, fn, …) splits its dotted path argument into segments and writes each into a nested object without guarding the prototype-chain segment names. A path containing __proto__ or constructor.prototype therefore mutates Object.prototype (and Function.prototype) globally, not the api tree — classic prototype pollution.

This is distinct from the documented __-prefixed export name convention (module-private members): here __proto__ is a mount-path segment, and the effect is global object-graph contamination, not an api member named __proto__.

Reproduce

Verified against @cldmv/slothlet@3.14.0 (repo v3.13.3-9-g0dd03b7), eager mode, empty api dir:

const api = await slothlet({ base: emptyDirUrl, silent: true, mode: "eager" });

await api.slothlet.api.add("__proto__.x", () => "polluted", { moduleID: "p" });
// no throw

({}).x;                              // → [Function (anonymous)]  ← a fresh, unrelated object is contaminated
Object.create(Object.prototype).x;   // → the function too

await api.slothlet.api.add("constructor.prototype.pwn", () => "x", { moduleID: "p2" });
({}).pwn;                            // → function

Expected

A mount-path segment of __proto__, constructor, or prototype should be refused with a named error (the same treatment reserved names already get — MODULE_RESERVED_EXPORT / a new MODULE_UNSAFE_PATH), never written through to the real prototype chain. slothlet already ships sanitizePropertyName and guards slothlet/shutdown/destroy; the dotted-path split in add() appears to bypass that guard for these three segments.

Impact

Any consumer that mounts from a path string it doesn't fully control is exposed to global prototype pollution. It surfaced while building @cldmv/slothlet-vine, which mounts forwarding leaves at paths taken from a remote peer — vine guards these segments on its own side, but the underlying add() allowing them is a latent footgun for every consumer.

Severity

Security — prototype pollution. Low exploitability where mount paths are always literal/trusted, but the fix is a cheap segment allowlist and the failure is silent + global.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: coreTouches core library / runtime source codepriority: highNeeds attention soon — not blocking, but don't let it sitsemver: patchThis release contains only backwards-compatible bug fixesstatus: confirmedThe issue has been verified and reproduced by a maintainertype: bugSomething is broken or not behaving as expected

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions