mirror of
https://github.com/pnpm/pnpm.git
synced 2026-05-31 12:10:49 -04:00
fix(pkg-manifest.utils): use Object.defineProperty for runtime-dep write
CodeQL alert 159 (js/prototype-polluting-assignment) stayed open after #11609 was merged: the barrier I added in convertEnginesRuntimeToDependencies checked a re-aliased `key` variable, but the actual write went through the original loop variable `runtimeName`. CodeQL's local data-flow analysis followed `runtimeName` and didn't see the barrier. Replace the inline barrier + dynamic assignment with `Object.defineProperty`, which is the CodeQL-blessed sanitiser for this pattern. The dependency-map write now produces a regular own data property even if a future entry in `RUNTIME_NAMES` happens to match an inherited name like `__proto__`, so the analyser is happy without depending on any pre-write check.
This commit is contained in:
6
.changeset/codeql-alert-159-followup.md
Normal file
6
.changeset/codeql-alert-159-followup.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"@pnpm/pkg-manifest.utils": patch
|
||||
"pnpm": patch
|
||||
---
|
||||
|
||||
`convertEnginesRuntimeToDependencies`: switch the runtime-dependency write to `Object.defineProperty` so CodeQL's `js/prototype-polluting-assignment` analyser recognises the assignment as safe regardless of the property name (follow-up to [#11609](https://github.com/pnpm/pnpm/pull/11609)).
|
||||
@@ -29,14 +29,17 @@ export function convertEnginesRuntimeToDependencies (
|
||||
if ('webcontainer' in process.versions) {
|
||||
globalWarn(`Installation of ${runtimeName} versions is not supported in WebContainer`)
|
||||
} else {
|
||||
// Inline barrier — CodeQL js/prototype-polluting-assignment recognizes
|
||||
// the literal equality checks but not the equivalent helper call on this
|
||||
// code path. Unreachable for the current RUNTIME_NAMES, but keeps the
|
||||
// dynamic assignment safe if a future entry is added.
|
||||
const key: string = runtimeName
|
||||
if (key === '__proto__' || key === 'constructor' || key === 'prototype') continue
|
||||
const deps = (manifest[dependenciesFieldName] ??= {})
|
||||
deps[runtimeName] = `runtime:${runtime.version}`
|
||||
// Use Object.defineProperty so a future RUNTIME_NAMES entry that
|
||||
// happens to match an inherited property name (`__proto__`,
|
||||
// `constructor`, `prototype`) becomes a regular own data property
|
||||
// instead of altering Object.prototype.
|
||||
Object.defineProperty(deps, runtimeName, {
|
||||
value: `runtime:${runtime.version}`,
|
||||
enumerable: true,
|
||||
writable: true,
|
||||
configurable: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user