fix(desktop): address security scan findings

This commit is contained in:
Brooklyn Nicholson
2026-05-04 23:43:00 -05:00
parent 023730314b
commit 301c698491
6 changed files with 151 additions and 28 deletions
@@ -0,0 +1,23 @@
import { describe, expect, it } from 'vitest'
import type { HermesConfigRecord } from '@/types/hermes'
import { getNested, setNested } from './helpers'
describe('settings helpers', () => {
it('reads and writes nested config paths', () => {
const config: HermesConfigRecord = { display: { theme: 'mono' } }
const next = setNested(config, 'display.theme', 'slate')
expect(getNested(next, 'display.theme')).toBe('slate')
expect(getNested(config, 'display.theme')).toBe('mono')
})
it('rejects prototype-polluting config paths', () => {
const config: HermesConfigRecord = {}
expect(() => setNested(config, '__proto__.polluted', true)).toThrow('Unsafe config path')
expect(() => setNested(config, 'constructor.prototype.polluted', true)).toThrow('Unsafe config path')
expect(({} as Record<string, unknown>).polluted).toBeUndefined()
})
})
+14 -2
View File
@@ -23,10 +23,22 @@ export const providerGroup = (key: string) => PROVIDER_GROUPS.find(g => key.star
export const providerPriority = (name: string) => PROVIDER_GROUPS.find(g => g.name === name)?.priority ?? 99
const POLLUTING_PATH_PARTS = new Set(['__proto__', 'constructor', 'prototype'])
function configPathParts(path: string): string[] {
const parts = path.split('.')
if (parts.some(part => !part || POLLUTING_PATH_PARTS.has(part))) {
throw new Error(`Unsafe config path: ${path}`)
}
return parts
}
export function getNested(obj: HermesConfigRecord, path: string): unknown {
let cur: unknown = obj
for (const part of path.split('.')) {
for (const part of configPathParts(path)) {
if (cur == null || typeof cur !== 'object') {
return undefined
}
@@ -39,7 +51,7 @@ export function getNested(obj: HermesConfigRecord, path: string): unknown {
export function setNested(obj: HermesConfigRecord, path: string, value: unknown): HermesConfigRecord {
const clone = structuredClone(obj)
const parts = path.split('.')
const parts = configPathParts(path)
let cur: Record<string, unknown> = clone
for (let i = 0; i < parts.length - 1; i += 1) {