mirror of
https://github.com/Kong/insomnia.git
synced 2026-08-04 03:42:20 -04:00
fix(sandbox): enforce path separator boundary in secureReadFile allowlist
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
|
||||
vi.mock('electron', () => ({ default: { app: { getPath: () => '/home/user/Insomnia' } } }));
|
||||
vi.mock('insomnia-data', () => ({ services: { settings: { getOrCreate: vi.fn() } } }));
|
||||
|
||||
import { isPathAllowed } from '../secure-read-file';
|
||||
|
||||
describe('isPathAllowed enforces a separator boundary on allowed roots', () => {
|
||||
const root = '/opt/allowed-root';
|
||||
|
||||
it('allows the allowed root itself and files inside it', () => {
|
||||
expect(isPathAllowed(root, [root]).isAllowed).toBe(true);
|
||||
expect(isPathAllowed(`${root}/sub/file.txt`, [root]).isAllowed).toBe(true);
|
||||
});
|
||||
|
||||
it('rejects a sibling directory that merely shares a name prefix', () => {
|
||||
expect(isPathAllowed(`${root}-evil/secret`, [root]).isAllowed).toBe(false);
|
||||
});
|
||||
|
||||
it('rejects a sibling install sharing a name prefix (e.g. Insomnia Nightly vs Insomnia)', () => {
|
||||
const insomnia = '/apps/Insomnia';
|
||||
expect(isPathAllowed('/apps/Insomnia Nightly/insomnia.OAuth2Token.db', [insomnia]).isAllowed).toBe(false);
|
||||
expect(isPathAllowed('/apps/Insomnia/insomnia.Request.db', [insomnia]).isAllowed).toBe(true);
|
||||
});
|
||||
});
|
||||
@@ -12,7 +12,16 @@ import { SECURITY_SETTINGS_PATH_LABEL } from '../common/misc';
|
||||
export const isPathAllowed = (filePath: string, userAllowList: string[]) => {
|
||||
const allowList = getSecuredFolderAllowList(userAllowList);
|
||||
const securedPath = securePath(filePath);
|
||||
const isAllowed = allowList.some(f => path.resolve(f) !== '' && securedPath.startsWith(path.resolve(f)));
|
||||
// Require an exact match or a separator-bounded prefix so a sibling dir sharing a name prefix
|
||||
// (e.g. ".../Insomnia Nightly" for a ".../Insomnia" root) can't pass a bare `startsWith`.
|
||||
const isAllowed = allowList.some(f => {
|
||||
const root = path.resolve(f);
|
||||
if (root === '') {
|
||||
return false;
|
||||
}
|
||||
const rootWithSep = root.endsWith(path.sep) ? root : root + path.sep;
|
||||
return securedPath === root || securedPath.startsWith(rootWithSep);
|
||||
});
|
||||
return { isAllowed, securedPath };
|
||||
};
|
||||
const securePath = (filePath: string) => path.resolve(decodeURIComponent(filePath));
|
||||
|
||||
Reference in New Issue
Block a user