fix(config): ignore inherited keys when restoring env refs (#109463)

* fix(config): use Object.hasOwn in restoreEnvVarRefs to avoid prototype pollution

When key comes from Object.entries(incoming) on user config data,
'key in parsed' traverses the prototype chain. If a config key
collides with an Object.prototype property (e.g. 'toString'),
the check incorrectly returns true and calls restoreEnvVarRefs
with a prototype function instead of a config value.

Replace with Object.hasOwn(parsed, key) to check only own properties.

* test(config): prove inherited env refs are ignored

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Peter Steinberger <peter@steipete.me>
This commit is contained in:
zengLingbiao
2026-07-18 10:49:53 +01:00
committed by GitHub
co-authored by Peter Steinberger Peter Steinberger
parent 7752e33f79
commit fcdf06ed29
2 changed files with 13 additions and 1 deletions
+12
View File
@@ -833,4 +833,16 @@ describe("restoreEnvVarRefs", () => {
resolved: "${MY_TOKEN}", // should restore ref
});
});
it("does not restore env refs from inherited parsed properties", () => {
// isPlainObject accepts custom prototypes, but only own properties represent authored config.
const parsed = Object.create({
toString: "${TEST_VALUE}",
}) as Record<string, unknown>;
const testEnv = { TEST_VALUE: "resolved-value" } as unknown as NodeJS.ProcessEnv;
expect(restoreEnvVarRefs({ toString: "resolved-value" }, parsed, testEnv)).toEqual({
toString: "resolved-value",
});
});
});
+1 -1
View File
@@ -820,7 +820,7 @@ export function restoreEnvVarRefs(
if (isPlainObject(incoming) && isPlainObject(parsed)) {
const result: Record<string, unknown> = {};
for (const [key, value] of Object.entries(incoming)) {
if (key in parsed) {
if (Object.hasOwn(parsed, key)) {
result[key] = restoreEnvVarRefs(value, parsed[key], env);
} else {
// New key added by caller — keep as-is