fix: validate browser cookie replay partitions (#3672)

This commit is contained in:
Neil 2026-05-30 12:38:17 -07:00 committed by GitHub
parent d3a9c5a2b8
commit 369f77a69f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 57 additions and 13 deletions

View File

@ -243,4 +243,37 @@ describe('BrowserSessionRegistry persistence', () => {
expect(written.pendingCookieImports).toEqual({ [importedPartition]: '/staged/imported' })
expect(written.pendingCookieDbPath).toBeNull()
})
it('ignores pending cookie imports for invalid persisted profile partitions', async () => {
const invalidPartition = 'persist:../../outside'
const fsState = createFsState()
seedMeta(fsState, {
defaultSource: null,
userAgent: null,
userAgentByPartition: {},
pendingCookieDbPath: null,
pendingCookieImports: {
[invalidPartition]: '/staged/evil'
},
profiles: [
{
id: 'profile-1',
scope: 'imported',
partition: invalidPartition,
label: 'Invalid',
source: null
}
]
})
fsState.present.add('/staged/evil')
installModuleMocks(fsState)
const { browserSessionRegistry } = await import('./browser-session-registry')
browserSessionRegistry.applyPendingCookieImport()
const written = JSON.parse(fsState.files.get(META_PATH) ?? '{}')
expect(written.pendingCookieImports).toEqual({})
expect(fsState.present.has('/outside/Cookies')).toBe(false)
})
})

View File

@ -192,10 +192,14 @@ class BrowserSessionRegistry {
if (pendingEntries.length === 0) {
return
}
const knownPartitions = new Set([
ORCA_BROWSER_PARTITION,
...meta.profiles.map((p) => p.partition)
])
// Why: replay writes to partition-derived file paths, so corrupted
// metadata must pass the same validation as the webview allowlist.
const knownPartitions = new Set([ORCA_BROWSER_PARTITION])
for (const profile of meta.profiles) {
if (BrowserSessionRegistry.isValidPersistedProfile(profile)) {
knownPartitions.add(profile.partition)
}
}
const remainingEntries = { ...meta.pendingCookieImports }
for (const [partition, stagedPath] of pendingEntries) {
@ -426,17 +430,24 @@ class BrowserSessionRegistry {
// registering anything.
private static readonly PARTITION_RE = /^persist:orca-browser-session-[\da-f-]{36}$/
private static isValidPersistedProfile(profile: unknown): profile is BrowserSessionProfile {
if (!profile || typeof profile !== 'object') {
return false
}
const candidate = profile as Partial<BrowserSessionProfile>
return (
candidate.id !== 'default' &&
candidate.scope !== 'default' &&
typeof candidate.id === 'string' &&
typeof candidate.partition === 'string' &&
typeof candidate.label === 'string' &&
BrowserSessionRegistry.PARTITION_RE.test(candidate.partition)
)
}
hydrateFromPersisted(profiles: BrowserSessionProfile[]): void {
for (const profile of profiles) {
if (profile.id === 'default' || profile.scope === 'default') {
continue
}
if (
typeof profile.id !== 'string' ||
typeof profile.partition !== 'string' ||
typeof profile.label !== 'string' ||
!BrowserSessionRegistry.PARTITION_RE.test(profile.partition)
) {
if (!BrowserSessionRegistry.isValidPersistedProfile(profile)) {
continue
}
this.profiles.set(profile.id, profile)