Block prototype keys in config paths

This commit is contained in:
Codex Microtask Operator 2026-06-12 18:25:29 +02:00
parent 8f4691584c
commit cdba848866
2 changed files with 25 additions and 5 deletions

View file

@ -0,0 +1,10 @@
import { describe, expect, it } from "vitest";
import { getConfigValue, setConfigValue } from "./config.js";
describe("CLI config", () => {
it("rejects prototype-polluting path segments", () => {
expect(() => setConfigValue("__proto__.polluted", "true", {})).toThrow(/prototype keys/);
expect(() => getConfigValue("constructor.prototype.polluted", {})).toThrow(/prototype keys/);
expect(({} as Record<string, unknown>).polluted).toBeUndefined();
});
});

View file

@ -40,14 +40,12 @@ export function writeConfig(config: JsonObject) {
}
export function getConfigValue(path: string, config = readConfig()) {
return path.split(".").reduce<unknown>((current, key) => (isObject(current) ? current[key] : undefined), config);
const parts = splitConfigPath(path);
return parts.reduce<unknown>((current, key) => (isObject(current) ? current[key] : undefined), config);
}
export function setConfigValue(path: string, rawValue: string, config = readConfig()) {
const parts = path.split(".").filter(Boolean);
if (parts.length === 0) {
throw new Error("Config path cannot be empty.");
}
const parts = splitConfigPath(path);
let current: JsonObject = config;
for (const part of parts.slice(0, -1)) {
if (!isObject(current[part])) {
@ -59,6 +57,18 @@ export function setConfigValue(path: string, rawValue: string, config = readConf
return config;
}
function splitConfigPath(path: string) {
const parts = path.split(".");
const blocked = new Set(["__proto__", "constructor", "prototype"]);
if (parts.length === 0 || parts.some((part) => part.length === 0)) {
throw new Error("Config path cannot contain empty segments.");
}
if (parts.some((part) => blocked.has(part))) {
throw new Error("Config path cannot contain prototype keys.");
}
return parts;
}
export function parseConfigValue(value: string): unknown {
if (value === "true") return true;
if (value === "false") return false;