mirror of
https://github.com/denoland/std.git
synced 2024-11-21 20:50:22 +00:00
fix(encoding/yaml): avoid prototype pollution in Node.js and Browser (#3173)
This commit is contained in:
parent
64d2544048
commit
dba98165cb
@ -246,7 +246,7 @@ const directiveHandlers: DirectiveHandlers = {
|
||||
}
|
||||
|
||||
if (typeof state.tagMap === "undefined") {
|
||||
state.tagMap = {};
|
||||
state.tagMap = Object.create(null) as common.ArrayObject;
|
||||
}
|
||||
state.tagMap[handle] = prefix;
|
||||
},
|
||||
@ -300,7 +300,12 @@ function mergeMappings(
|
||||
for (let i = 0, len = keys.length; i < len; i++) {
|
||||
const key = keys[i];
|
||||
if (!hasOwn(destination, key)) {
|
||||
destination[key] = (source as ArrayObject)[key];
|
||||
Object.defineProperty(destination, key, {
|
||||
value: source[key],
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
});
|
||||
overridableKeys[key] = true;
|
||||
}
|
||||
}
|
||||
@ -371,7 +376,12 @@ function storeMappingPair(
|
||||
state.position = startPos || state.position;
|
||||
return throwError(state, "duplicated mapping key");
|
||||
}
|
||||
result[keyNode] = valueNode;
|
||||
Object.defineProperty(result, keyNode, {
|
||||
value: valueNode,
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
});
|
||||
delete overridableKeys[keyNode];
|
||||
}
|
||||
|
||||
@ -750,7 +760,7 @@ function readFlowCollection(state: LoaderState, nodeIndent: number): boolean {
|
||||
isPair = (isExplicitPair = false);
|
||||
let following = 0,
|
||||
line = 0;
|
||||
const overridableKeys: ArrayObject<boolean> = {};
|
||||
const overridableKeys: ArrayObject<boolean> = Object.create(null);
|
||||
while (ch !== 0) {
|
||||
skipSeparationSpace(state, true, nodeIndent);
|
||||
|
||||
@ -1067,7 +1077,7 @@ function readBlockMapping(
|
||||
const tag = state.tag,
|
||||
anchor = state.anchor,
|
||||
result = {},
|
||||
overridableKeys = {};
|
||||
overridableKeys = Object.create(null);
|
||||
let following: number,
|
||||
allowCompact = false,
|
||||
line: number,
|
||||
@ -1609,8 +1619,8 @@ function readDocument(state: LoaderState) {
|
||||
|
||||
state.version = null;
|
||||
state.checkLineBreaks = state.legacy;
|
||||
state.tagMap = {};
|
||||
state.anchorMap = {};
|
||||
state.tagMap = Object.create(null);
|
||||
state.anchorMap = Object.create(null);
|
||||
|
||||
while ((ch = state.input.charCodeAt(state.position)) !== 0) {
|
||||
skipSeparationSpace(state, true, -1);
|
||||
|
@ -4,7 +4,7 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
import { parse, parseAll } from "./parse.ts";
|
||||
import { assertEquals, assertThrows } from "../../testing/asserts.ts";
|
||||
import { assert, assertEquals, assertThrows } from "../../testing/asserts.ts";
|
||||
import { DEFAULT_SCHEMA, EXTENDED_SCHEMA } from "./schema/mod.ts";
|
||||
import { YAMLError } from "./error.ts";
|
||||
import { Type } from "./type.ts";
|
||||
@ -172,3 +172,47 @@ regexp: !!js/regexp bar
|
||||
assertEquals(callback.calls(), 2);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "parse __proto__",
|
||||
async fn() {
|
||||
// Tests if the value is set using `Object.defineProperty(target, key, {value})`
|
||||
// instead of `target[key] = value` when parsing the object.
|
||||
// This makes a difference in behavior when __proto__ is set in Node.js and browsers.
|
||||
// Using `Object.defineProperty` avoids prototype pollution in Node.js and browsers.
|
||||
// reference: https://github.com/advisories/GHSA-9c47-m6qq-7p4h (CVE-2022-46175)
|
||||
|
||||
const yaml1 = `
|
||||
__proto__:
|
||||
isAdmin: true
|
||||
`;
|
||||
|
||||
const yaml2 = `
|
||||
anchor: &__proto__
|
||||
__proto__: 1111
|
||||
alias_test:
|
||||
aaa: *__proto__
|
||||
merge_test:
|
||||
bbb: 2222
|
||||
<<: *__proto__
|
||||
`;
|
||||
|
||||
const testCode = `
|
||||
Object.defineProperty(Object.prototype, "__proto__", {
|
||||
set() {
|
||||
throw new Error("Don't try to set the value directly to the key __proto__.")
|
||||
}
|
||||
});
|
||||
import { parse } from "${import.meta.resolve("./parse.ts")}";
|
||||
parse(\`${yaml1}\`);
|
||||
parse(\`${yaml2}\`);
|
||||
`;
|
||||
const command = new Deno.Command(Deno.execPath(), {
|
||||
stdout: "inherit",
|
||||
stderr: "inherit",
|
||||
args: ["eval", testCode],
|
||||
});
|
||||
const { success } = await command.output();
|
||||
assert(success);
|
||||
},
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user