mirror of
https://github.com/stablyai/orca.git
synced 2026-09-27 16:02:35 +00:00
fix: validate Chromium profile directories (#3674)
* fix: validate chromium profile directories * test: cover unsafe browser profile selection Co-authored-by: Orca <help@stably.ai> --------- Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com> Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
@@ -122,6 +122,71 @@ describe('detectInstalledBrowsers — Comet', () => {
|
||||
expect(names).toEqual(['Personal', 'Research', 'Work'])
|
||||
})
|
||||
|
||||
it('ignores Comet profile directories that escape the browser root', async () => {
|
||||
vi.doMock('node:fs', async () => {
|
||||
const actual = await vi.importActual<typeof fsModule>('node:fs')
|
||||
return {
|
||||
...actual,
|
||||
existsSync: (p: string) => {
|
||||
if (p.includes('Comet/Local State')) {
|
||||
return true
|
||||
}
|
||||
if (p.includes('Application Support/Outside/Network/Cookies')) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
},
|
||||
readFileSync: (p: string, enc?: string) => {
|
||||
if (typeof p === 'string' && p.includes('Comet/Local State')) {
|
||||
return JSON.stringify({
|
||||
profile: {
|
||||
info_cache: {
|
||||
'../Outside': { name: 'Outside' }
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
return actual.readFileSync(p as never, enc as never)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const { detectInstalledBrowsers } = await import('./browser-cookie-import')
|
||||
const detected = detectInstalledBrowsers()
|
||||
expect(detected.find((b) => b.family === 'comet')).toBeUndefined()
|
||||
})
|
||||
|
||||
it('rejects explicit Comet profile selections that escape the browser root', async () => {
|
||||
vi.doMock('node:fs', async () => {
|
||||
const actual = await vi.importActual<typeof fsModule>('node:fs')
|
||||
return {
|
||||
...actual,
|
||||
existsSync: (p: string) => {
|
||||
if (p.includes('Application Support/Outside/Network/Cookies')) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const { selectBrowserProfile } = await import('./browser-cookie-import')
|
||||
const selected = selectBrowserProfile(
|
||||
{
|
||||
family: 'comet',
|
||||
label: 'Comet',
|
||||
cookiesPath: '/Users/test/Library/Application Support/Comet/Default/Network/Cookies',
|
||||
keychainService: 'Comet Safe Storage',
|
||||
keychainAccount: 'Comet',
|
||||
profiles: [{ name: 'Outside', directory: '../Outside' }],
|
||||
selectedProfile: 'Default'
|
||||
},
|
||||
'../Outside'
|
||||
)
|
||||
|
||||
expect(selected).toBeNull()
|
||||
})
|
||||
|
||||
it('skips Comet when the data directory exists but no Cookies DB is present', async () => {
|
||||
vi.doMock('node:fs', async () => {
|
||||
const actual = await vi.importActual<typeof fsModule>('node:fs')
|
||||
|
||||
@@ -173,6 +173,17 @@ function resolveCookiesPath(profileDir: string): string | null {
|
||||
return null
|
||||
}
|
||||
|
||||
function isSafeBrowserProfileDirectory(directory: string): boolean {
|
||||
return (
|
||||
directory.length > 0 &&
|
||||
directory !== '.' &&
|
||||
!directory.includes('\0') &&
|
||||
!directory.includes('/') &&
|
||||
!directory.includes('\\') &&
|
||||
!directory.includes('..')
|
||||
)
|
||||
}
|
||||
|
||||
// Why: Chrome's Local State JSON contains profile.info_cache which maps profile
|
||||
// directory names (e.g. "Default", "Profile 1") to metadata including the
|
||||
// user-visible display name. This lets us show human-readable names in the picker.
|
||||
@@ -190,6 +201,10 @@ function discoverProfiles(browserRoot: string): BrowserProfile[] {
|
||||
}
|
||||
const profiles: BrowserProfile[] = []
|
||||
for (const [dir, info] of Object.entries(infoCache)) {
|
||||
// Why: Local State is external metadata, but profile dirs become path segments.
|
||||
if (!isSafeBrowserProfileDirectory(dir)) {
|
||||
continue
|
||||
}
|
||||
const profileName = (info as { name?: string })?.name ?? dir
|
||||
profiles.push({ name: profileName, directory: dir })
|
||||
}
|
||||
@@ -362,6 +377,9 @@ export function selectBrowserProfile(
|
||||
browser: DetectedBrowser,
|
||||
profileDirectory: string
|
||||
): DetectedBrowser | null {
|
||||
if (!isSafeBrowserProfileDirectory(profileDirectory)) {
|
||||
return null
|
||||
}
|
||||
if (browser.family === 'firefox') {
|
||||
const profilesRoot = firefoxProfilesRoot()
|
||||
if (!profilesRoot) {
|
||||
|
||||
Reference in New Issue
Block a user