File tree Expand file tree Collapse file tree 2 files changed +40
-1
lines changed
packages/cli/src/config/extensions Expand file tree Collapse file tree 2 files changed +40
-1
lines changed Original file line number Diff line number Diff line change @@ -124,4 +124,30 @@ describe('recursivelyHydrateStrings', () => {
124124 const result = recursivelyHydrateStrings ( obj , context ) ;
125125 expect ( result ) . toEqual ( obj ) ;
126126 } ) ;
127+
128+ it ( 'should not allow prototype pollution via __proto__' , ( ) => {
129+ const payload = JSON . parse ( '{"__proto__": {"polluted": "yes"}}' ) ;
130+ const result = recursivelyHydrateStrings ( payload , context ) ;
131+
132+ expect ( result . polluted ) . toBeUndefined ( ) ;
133+ expect ( Object . prototype . hasOwnProperty . call ( result , 'polluted' ) ) . toBe (
134+ false ,
135+ ) ;
136+ } ) ;
137+
138+ it ( 'should not allow prototype pollution via constructor' , ( ) => {
139+ const payload = JSON . parse (
140+ '{"constructor": {"prototype": {"polluted": "yes"}}}' ,
141+ ) ;
142+ const result = recursivelyHydrateStrings ( payload , context ) ;
143+
144+ expect ( result . polluted ) . toBeUndefined ( ) ;
145+ } ) ;
146+
147+ it ( 'should not allow prototype pollution via prototype' , ( ) => {
148+ const payload = JSON . parse ( '{"prototype": {"polluted": "yes"}}' ) ;
149+ const result = recursivelyHydrateStrings ( payload , context ) ;
150+
151+ expect ( result . polluted ) . toBeUndefined ( ) ;
152+ } ) ;
127153} ) ;
Original file line number Diff line number Diff line change @@ -8,6 +8,16 @@ import * as path from 'node:path';
88import { type VariableSchema , VARIABLE_SCHEMA } from './variableSchema.js' ;
99import { GEMINI_DIR } from '@google/gemini-cli-core' ;
1010
11+ /**
12+ * Represents a set of keys that will be considered invalid while unmarshalling
13+ * JSON in recursivelyHydrateStrings.
14+ */
15+ const UNMARSHALL_KEY_IGNORE_LIST : Set < string > = new Set < string > ( [
16+ '__proto__' ,
17+ 'constructor' ,
18+ 'prototype' ,
19+ ] ) ;
20+
1121export const EXTENSIONS_DIRECTORY_NAME = path . join ( GEMINI_DIR , 'extensions' ) ;
1222export const EXTENSIONS_CONFIG_FILENAME = 'gemini-extension.json' ;
1323export const INSTALL_METADATA_FILENAME = '.gemini-extension-install.json' ;
@@ -65,7 +75,10 @@ export function recursivelyHydrateStrings<T>(
6575 if ( typeof obj === 'object' && obj !== null ) {
6676 const newObj : Record < string , unknown > = { } ;
6777 for ( const key in obj ) {
68- if ( Object . prototype . hasOwnProperty . call ( obj , key ) ) {
78+ if (
79+ ! UNMARSHALL_KEY_IGNORE_LIST . has ( key ) &&
80+ Object . prototype . hasOwnProperty . call ( obj , key )
81+ ) {
6982 newObj [ key ] = recursivelyHydrateStrings (
7083 // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
7184 ( obj as Record < string , unknown > ) [ key ] ,
You can’t perform that action at this time.
0 commit comments