Skip to content

release: v3.14.1 - refuse prototype-polluting mount-path segments in… - #308

Open
cldmv-bot[bot] wants to merge 10 commits into
masterfrom
next
Open

release: v3.14.1 - refuse prototype-polluting mount-path segments in…#308
cldmv-bot[bot] wants to merge 10 commits into
masterfrom
next

Conversation

@cldmv-bot

@cldmv-bot cldmv-bot Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

🚀 What's Changed

💥 Breaking Changes

No breaking changes

✨ Features

No new features

🐛 Bug Fixes

📦 Dependencies

No dependency updates

🔧 Other Changes

👥 Contributors

coverage

Metric Coverage
Statements 100.0%
Branches 100.0%
Functions 100.0%
Lines 100.0%

Avg: 100.0% · f4ce594 · Node lts/*

Shinrai and others added 10 commits August 24, 2026 04:25
A dotted or array mount path passed to api.slothlet.api.add() was split into
segments and written into the api tree without guarding prototype-chain segment
names. A path containing __proto__, constructor, or prototype therefore mutated
Object.prototype / Function.prototype globally instead of the api tree — classic
prototype pollution — with no error raised.

normalizeApiPath now refuses any of these three names in any segment position
(both the dotted-string and array path forms) with INVALID_CONFIG_API_PATH_INVALID
and the new API_PATH_REASON_UNSAFE_SEGMENT reason, mirroring the existing
reserved-name guard. Adds the reason string to all 12 language packs and
coverage for both path forms plus a no-pollution assertion.

This corrects never-intended behavior (a silent global write), so it ships as a
patch — no legitimate consumer mounts at __proto__/constructor/prototype.

Fixes #302
…dpoints

The wrapper get trap resolved a property read to `impl[prop]` and, for any
function-valued result, wrapped it as a child endpoint and registered ownership.
On a callable leaf, that meant merely READING an inherited Function.prototype
member — `apply`, `call`, `bind`, `constructor` — (or the non-enumerable own
`prototype` slot) rewrote the leaf's loader record: it flipped from
kind "function" to "namespace" and grew a phantom child (`leaf.apply`, …). A
later leaves() or re-composition then surfaced Function.prototype.apply in place
of the leaf. `leaf.apply(thisArg, args)` — a common forwarding idiom — silently
corrupted the served surface (Reflect.apply was the only safe workaround).

The get trap now returns the function's own built-in members directly instead of
wrapping them: for a function impl, a property that is not a user-added
ENUMERABLE own property is returned as-is. Genuine enumerable own children of a
callable still materialize as endpoints. Covered in eager and lazy modes,
including a callable that carries a real user child.

Fixes #304
The prototype-pollution guard added to normalizeApiPath preempted the dedicated
LOOSE_SET_RESERVED_KEY error that setOwnedProperty raises for `self.<key> = …`
assignments: setOwnedProperty calls normalizeApiPath first, so a
`self.prototype = {}` / `self['__proto__'] = obj` now threw the generic
INVALID_CONFIG_API_PATH_INVALID instead, breaking
runtime/self-assign-prototype-pollution.

Run the reserved-segment check (LOOSE_SET_RESERVED_KEY) before normalizeApiPath
so the self-assign surface keeps its own error while the api.add() mount-path
surface keeps the new unsafe-segment error. Both guards stay reachable and tested.
Address Copilot review on #305:
- The "__-prefixed still accepted" test mounted at "plugins", so it never
  exercised a __-prefixed segment. Mount "__config.value" and a
  ["prototypeName","leaf"] substring path instead, proving the guard matches
  whole segments (only __proto__/constructor/prototype), not prefixes/substrings.
- Capitalize the ru-ru API_PATH_REASON_UNSAFE_SEGMENT string to match that
  locale's sentence-cased sibling messages.
…port

Address Copilot review on #307: add an afterAll that removes the per-run temp
fixture dir under tmp/ (it was left behind on every run), and drop the unused
`dirname` import.
…dProperty

Address Copilot review on #305: the loose-set prototype-pollution guard
allocated a fresh Set on every call and coerced via a template literal, which
throws a raw TypeError on a Symbol instead of the intended SlothletError path.
Reuse the module-level UNSAFE_PATH_SEGMENTS and coerce with String() — branchless
and Symbol-safe.
@cldmv-bot cldmv-bot Bot added ! release → master v4 flow: persistent next → master release PR (carries the next feature release) release Marks a pull request as a pending release — merge to publish a new version semver: patch This release contains only backwards-compatible bug fixes type: bug Something is broken or not behaving as expected area: core Touches core library / runtime source code area: tests Touches test files, fixtures, or test infrastructure type: dependencies Relates to dependency updates, version bumps, or package management labels Aug 24, 2026
@github-actions

Copy link
Copy Markdown

🔒 Dependency Review

  • 0 vulnerable package(s)
  • 0 package(s) with incompatible licenses
  • 0 package(s) with invalid SPDX license definitions
  • 0 package(s) with unknown licenses
  • 0 denied package(s)
  • 0 package(s) with OpenSSF Scorecard score < 3

Full job summary

@cldmv-bot

cldmv-bot Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor Author

⚠️ Bundle size increased

File Raw Δ Raw Gzipped Δ Gzipped
dist/lib/builders/api-assignment.mjs 15.5 kB 3.4 kB
dist/lib/builders/api_builder.mjs 48.8 kB 9.9 kB
dist/lib/builders/builder.mjs 2.7 kB 1.2 kB
dist/lib/builders/modes-processor.mjs 40.6 kB 6.9 kB
dist/lib/errors.mjs 4.4 kB 1.7 kB
dist/lib/factories/component-base.mjs 1.7 kB 866 B
dist/lib/factories/context.mjs 1010 B 525 B
dist/lib/handlers/api-cache-manager.mjs 3.4 kB 1.4 kB
dist/lib/handlers/api-manager.mjs 56.8 kB +686 B (+1.2%) ⚠️ 11.8 kB +104 B
dist/lib/handlers/context-async.mjs 4.0 kB 1.4 kB
dist/lib/handlers/context-live.mjs 7.0 kB 2.2 kB
dist/lib/handlers/framework-internals.mjs 1.1 kB 611 B
dist/lib/handlers/hook-manager.mjs 19.6 kB 4.9 kB
dist/lib/handlers/lifecycle-token.mjs 959 B 540 B
dist/lib/handlers/lifecycle.mjs 2.2 kB 1010 B
dist/lib/handlers/materialize-manager.mjs 1.2 kB 672 B
dist/lib/handlers/metadata.mjs 12.2 kB 3.2 kB
dist/lib/handlers/module-manager.mjs 9.3 kB 3.0 kB
dist/lib/handlers/ownership.mjs 6.3 kB 2.1 kB
dist/lib/handlers/permission-manager.mjs 15.9 kB 4.0 kB
dist/lib/handlers/trusted-root.mjs 3.1 kB 1.2 kB
dist/lib/handlers/unified-wrapper.mjs 74.8 kB +164 B (+0.2%) 13.3 kB +32 B
dist/lib/handlers/version-manager.mjs 14.4 kB 3.7 kB
dist/lib/helpers/caller-pinning.mjs 804 B 496 B
dist/lib/helpers/class-instance-wrapper.mjs 2.7 kB 1.1 kB
dist/lib/helpers/config.mjs 14.5 kB 3.8 kB
dist/lib/helpers/eventemitter-context.mjs 9.0 kB 1.8 kB
dist/lib/helpers/eventtarget-context.mjs 3.3 kB 1.2 kB
dist/lib/helpers/generate-manifest.mjs 10.6 kB 3.3 kB
dist/lib/helpers/hint-detector.mjs 1.3 kB 756 B
dist/lib/helpers/manifest-resolver.mjs 1004 B 611 B
dist/lib/helpers/modes-utils.mjs 1.1 kB 696 B
dist/lib/helpers/module-discovery.mjs 7.5 kB 2.5 kB
dist/lib/helpers/module-manifest-validator.mjs 8.7 kB 1.9 kB
dist/lib/helpers/module-sort.mjs 1.0 kB 593 B
dist/lib/helpers/pattern-matcher.mjs 2.6 kB 1.2 kB
dist/lib/helpers/platform.mjs 1.8 kB 953 B
dist/lib/helpers/resolve-from-caller.mjs 3.0 kB 1.3 kB
dist/lib/helpers/sanitize.mjs 7.7 kB 2.3 kB
dist/lib/helpers/scheduler-context.mjs 1.9 kB 876 B
dist/lib/helpers/utilities.mjs 1.7 kB 909 B
dist/lib/i18n/languages/de-de.json 64.4 kB +153 B (+0.2%) 18.4 kB +69 B
dist/lib/i18n/languages/en-gb.json 56.8 kB +141 B (+0.2%) 16.0 kB +45 B
dist/lib/i18n/languages/en-us.json 56.8 kB +141 B (+0.2%) 16.0 kB +46 B
dist/lib/i18n/languages/es-es.json 63.9 kB +148 B (+0.2%) 17.8 kB +62 B
dist/lib/i18n/languages/es-mx.json 64.0 kB +148 B (+0.2%) 17.8 kB +61 B
dist/lib/i18n/languages/fr-fr.json 64.9 kB +150 B (+0.2%) 17.9 kB +63 B
dist/lib/i18n/languages/hi-in.json 107.3 kB +257 B (+0.2%) 20.2 kB +94 B
dist/lib/i18n/languages/ja-jp.json 76.5 kB +176 B (+0.2%) 18.9 kB +75 B
dist/lib/i18n/languages/ko-kr.json 66.3 kB +170 B (+0.3%) 17.9 kB +77 B
dist/lib/i18n/languages/pt-br.json 63.2 kB +141 B (+0.2%) 17.6 kB +77 B
dist/lib/i18n/languages/ru-ru.json 78.0 kB +208 B (+0.3%) 19.0 kB +82 B
dist/lib/i18n/languages/zh-cn.json 55.7 kB +120 B (+0.2%) 17.5 kB +39 B
dist/lib/i18n/translations.mjs 5.0 kB 1.8 kB
dist/lib/modes/eager.mjs 2.0 kB 1006 B
dist/lib/modes/lazy.mjs 2.5 kB 1.2 kB
dist/lib/processors/flatten.mjs 9.9 kB 2.4 kB
dist/lib/processors/loader.mjs 12.3 kB 4.0 kB
dist/lib/processors/type-generator.mjs 6.7 kB 2.6 kB
dist/lib/processors/typescript.mjs 10.7 kB 4.0 kB
dist/lib/runtime/runtime-asynclocalstorage.mjs 3.0 kB 1.1 kB
dist/lib/runtime/runtime-livebindings.mjs 3.1 kB 1.1 kB
dist/lib/runtime/runtime.mjs 2.2 kB 800 B
dist/lib/typegen/typegen.mjs 2.1 kB 1.0 kB
dist/slothlet.mjs 17.9 kB 5.1 kB
Total 1.29 MB +2.7 kB 346.5 kB +926 B

📊 Generated by bundle-size. Brotli sizes also measured but omitted from the table for brevity.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: core Touches core library / runtime source code area: tests Touches test files, fixtures, or test infrastructure ! release → master v4 flow: persistent next → master release PR (carries the next feature release) release Marks a pull request as a pending release — merge to publish a new version semver: patch This release contains only backwards-compatible bug fixes type: bug Something is broken or not behaving as expected type: dependencies Relates to dependency updates, version bumps, or package management

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants