Skip to content

Commit fa17698

Browse files
DavidAPiercegemini-code-assist[bot]
authored andcommitted
Unmarshall update (google-gemini#21721)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
1 parent 4273a4f commit fa17698

File tree

2 files changed

+40
-1
lines changed

2 files changed

+40
-1
lines changed

packages/cli/src/config/extensions/variables.test.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff 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
});

packages/cli/src/config/extensions/variables.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,16 @@ import * as path from 'node:path';
88
import { type VariableSchema, VARIABLE_SCHEMA } from './variableSchema.js';
99
import { 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+
1121
export const EXTENSIONS_DIRECTORY_NAME = path.join(GEMINI_DIR, 'extensions');
1222
export const EXTENSIONS_CONFIG_FILENAME = 'gemini-extension.json';
1323
export 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],

0 commit comments

Comments
 (0)