mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-05-12 12:54:07 -07:00
Unmarshall update (#21721)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
This commit is contained in:
@@ -124,4 +124,30 @@ describe('recursivelyHydrateStrings', () => {
|
|||||||
const result = recursivelyHydrateStrings(obj, context);
|
const result = recursivelyHydrateStrings(obj, context);
|
||||||
expect(result).toEqual(obj);
|
expect(result).toEqual(obj);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not allow prototype pollution via __proto__', () => {
|
||||||
|
const payload = JSON.parse('{"__proto__": {"polluted": "yes"}}');
|
||||||
|
const result = recursivelyHydrateStrings(payload, context);
|
||||||
|
|
||||||
|
expect(result.polluted).toBeUndefined();
|
||||||
|
expect(Object.prototype.hasOwnProperty.call(result, 'polluted')).toBe(
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not allow prototype pollution via constructor', () => {
|
||||||
|
const payload = JSON.parse(
|
||||||
|
'{"constructor": {"prototype": {"polluted": "yes"}}}',
|
||||||
|
);
|
||||||
|
const result = recursivelyHydrateStrings(payload, context);
|
||||||
|
|
||||||
|
expect(result.polluted).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not allow prototype pollution via prototype', () => {
|
||||||
|
const payload = JSON.parse('{"prototype": {"polluted": "yes"}}');
|
||||||
|
const result = recursivelyHydrateStrings(payload, context);
|
||||||
|
|
||||||
|
expect(result.polluted).toBeUndefined();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -8,6 +8,16 @@ import * as path from 'node:path';
|
|||||||
import { type VariableSchema, VARIABLE_SCHEMA } from './variableSchema.js';
|
import { type VariableSchema, VARIABLE_SCHEMA } from './variableSchema.js';
|
||||||
import { GEMINI_DIR } from '@google/gemini-cli-core';
|
import { GEMINI_DIR } from '@google/gemini-cli-core';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a set of keys that will be considered invalid while unmarshalling
|
||||||
|
* JSON in recursivelyHydrateStrings.
|
||||||
|
*/
|
||||||
|
const UNMARSHALL_KEY_IGNORE_LIST: Set<string> = new Set<string>([
|
||||||
|
'__proto__',
|
||||||
|
'constructor',
|
||||||
|
'prototype',
|
||||||
|
]);
|
||||||
|
|
||||||
export const EXTENSIONS_DIRECTORY_NAME = path.join(GEMINI_DIR, 'extensions');
|
export const EXTENSIONS_DIRECTORY_NAME = path.join(GEMINI_DIR, 'extensions');
|
||||||
export const EXTENSIONS_CONFIG_FILENAME = 'gemini-extension.json';
|
export const EXTENSIONS_CONFIG_FILENAME = 'gemini-extension.json';
|
||||||
export const INSTALL_METADATA_FILENAME = '.gemini-extension-install.json';
|
export const INSTALL_METADATA_FILENAME = '.gemini-extension-install.json';
|
||||||
@@ -65,7 +75,10 @@ export function recursivelyHydrateStrings<T>(
|
|||||||
if (typeof obj === 'object' && obj !== null) {
|
if (typeof obj === 'object' && obj !== null) {
|
||||||
const newObj: Record<string, unknown> = {};
|
const newObj: Record<string, unknown> = {};
|
||||||
for (const key in obj) {
|
for (const key in obj) {
|
||||||
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
if (
|
||||||
|
!UNMARSHALL_KEY_IGNORE_LIST.has(key) &&
|
||||||
|
Object.prototype.hasOwnProperty.call(obj, key)
|
||||||
|
) {
|
||||||
newObj[key] = recursivelyHydrateStrings(
|
newObj[key] = recursivelyHydrateStrings(
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||||
(obj as Record<string, unknown>)[key],
|
(obj as Record<string, unknown>)[key],
|
||||||
|
|||||||
Reference in New Issue
Block a user