Skip to content

Commit

Permalink
preventively fix potential prototype pollution from server-side scene…
Browse files Browse the repository at this point in the history
…s structured merge
  • Loading branch information
sdumetz committed Jan 8, 2025
1 parent 82da925 commit e24bec6
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 4 deletions.
12 changes: 12 additions & 0 deletions source/server/utils/merge/apply.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,16 @@ describe("merge.apply()", function(){
it("merges special SOURCE_INDEX symbol", function(){
expect(apply({a:{[SOURCE_INDEX]:0}}, {a:{[SOURCE_INDEX]:1}})).to.deep.equal({a:{[SOURCE_INDEX]:1}});
});

it("prevents prototype pollution (create object)", function(){
//This is not a strict
let result:any = apply({}, {a:{__proto__: {isAdmin: true}, tick: 1} as any});
expect(result.a, `Expected prototype pollution to be filtered internally`).to.not.have.property("isAdmin");
});

it("prevents prototype pollution (update object)", function(){
let result :any = apply({a: {tick: 0}}, {a:{__proto__: {isAdmin: true}, tick: 1} as any});
expect(result).to.deep.equal({a:{tick: 1}});
expect(result.a).to.not.have.property("isAdmin");
});
});
6 changes: 2 additions & 4 deletions source/server/utils/merge/apply.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {Diff, DELETE_KEY, SOURCE_INDEX, withIndex} from "./pointers/types.js";
export default function apply<T extends Record<string, any>>(into :T, ...diffs :Diff<T>[]):T{
for(const diff of diffs){
if(SOURCE_INDEX in diff) into = withIndex(into, diff[SOURCE_INDEX] as number);
for(const key in diff){
for(const key of Object.getOwnPropertyNames(diff) as Extract<keyof Diff<T>, string>[]){
const value = diff[key] as T[Extract<keyof T, string>];

if(value === DELETE_KEY){
Expand All @@ -21,9 +21,7 @@ export default function apply<T extends Record<string, any>>(into :T, ...diffs :
delete into[key];
}

}else if(typeof value !== "object" //primitive
|| typeof into[key] === "undefined" //undefined target
){
}else if(typeof value !== "object" /*primitive*/){
into[key] = value;
}else if(Array.isArray(value)){
//Replace arrays without looking.
Expand Down

0 comments on commit e24bec6

Please sign in to comment.