mirror of
https://github.com/oven-sh/bun
synced 2026-02-09 10:28:47 +00:00
fix: Use putDirectMayBeIndex for potentially numeric properties and fix __proto__ handling
- Use putDirectMayBeIndex instead of putDirect for properties that could be numeric - Fix __proto__ handling to create parent objects but skip the __proto__ property itself - Update tests to match correct behavior 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -52,7 +52,8 @@ static void parseRailsStyleParams(JSC::JSGlobalObject* globalObject, JSC::JSObje
|
||||
return;
|
||||
|
||||
// Simple key-value assignment - last value wins
|
||||
result->putDirect(vm, Identifier::fromString(vm, key), jsString(vm, value));
|
||||
// Use putDirectMayBeIndex since key could be numeric
|
||||
result->putDirectMayBeIndex(globalObject, Identifier::fromString(vm, key), jsString(vm, value));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -130,9 +131,7 @@ static void parseRailsStyleParams(JSC::JSGlobalObject* globalObject, JSC::JSObje
|
||||
return; // Malformed
|
||||
|
||||
String innerKey = remainder.substring(1, closeBracket - 1);
|
||||
if (innerKey == "__proto__"_s)
|
||||
return;
|
||||
|
||||
|
||||
// Determine if this should be an array (numeric index) or object (string key)
|
||||
unsigned index = 0;
|
||||
bool isIndex = isArrayIndex(innerKey, index);
|
||||
@@ -185,13 +184,18 @@ static void parseRailsStyleParams(JSC::JSGlobalObject* globalObject, JSC::JSObje
|
||||
array->putDirectIndex(globalObject, index, nestedObj);
|
||||
}
|
||||
} else {
|
||||
// Skip __proto__ for security
|
||||
if (innerKey == "__proto__"_s)
|
||||
return;
|
||||
|
||||
JSValue existingNested = container->getDirect(vm, Identifier::fromString(vm, innerKey));
|
||||
|
||||
if (!existingNested.isEmpty() && existingNested.isObject()) {
|
||||
nestedObj = asObject(existingNested);
|
||||
} else {
|
||||
nestedObj = constructEmptyObject(vm, globalObject->nullPrototypeObjectStructure());
|
||||
container->putDirect(vm, Identifier::fromString(vm, innerKey), nestedObj);
|
||||
// Use putDirectMayBeIndex since innerKey could be numeric
|
||||
container->putDirectMayBeIndex(globalObject, Identifier::fromString(vm, innerKey), nestedObj);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,7 +227,11 @@ static void parseRailsStyleParams(JSC::JSGlobalObject* globalObject, JSC::JSObje
|
||||
JSArray* array = jsCast<JSArray*>(container);
|
||||
array->putDirectIndex(globalObject, index, jsString(vm, value));
|
||||
} else {
|
||||
container->putDirect(vm, Identifier::fromString(vm, innerKey), jsString(vm, value));
|
||||
// Skip __proto__ for security
|
||||
if (innerKey != "__proto__"_s) {
|
||||
// Use putDirectMayBeIndex since innerKey could be numeric
|
||||
container->putDirectMayBeIndex(globalObject, Identifier::fromString(vm, innerKey), jsString(vm, value));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,9 +104,10 @@ test("parseQueryParams - complex nested structure", () => {
|
||||
|
||||
test("parseQueryParams - __proto__ is ignored for security", () => {
|
||||
const result = parseQueryParams("__proto__=evil&user[__proto__]=bad&normal=ok");
|
||||
// When __proto__ is the only key for an object, the object is not created
|
||||
// __proto__ keys are ignored, but the parent object is still created
|
||||
expect(result).toEqual({
|
||||
normal: "ok",
|
||||
user: {},
|
||||
});
|
||||
|
||||
// Verify prototype wasn't polluted
|
||||
|
||||
Reference in New Issue
Block a user