test: service worker contextBridge leak (#45852)
* test: contextBridge prototype leak in service workers * test: deep prototype checks
This commit is contained in:
parent
add374ef6a
commit
21ad7cdda5
2 changed files with 81 additions and 1 deletions
|
@ -388,6 +388,13 @@ describe('ServiceWorkerMain module', () => {
|
|||
const result = await runTest(serviceWorker, { name: 'testEvaluate', args: ['evalConstructorName'] });
|
||||
expect(result).to.equal('ServiceWorkerGlobalScope');
|
||||
});
|
||||
|
||||
it('does not leak prototypes', async () => {
|
||||
loadWorkerScript();
|
||||
const serviceWorker = await waitForServiceWorker('running');
|
||||
const result = await runTest(serviceWorker, { name: 'testPrototypeLeak', args: [] });
|
||||
expect(result).to.be.true();
|
||||
});
|
||||
});
|
||||
|
||||
describe('extensions', () => {
|
||||
|
|
75
spec/fixtures/api/preload-realm/preload-tests.js
vendored
75
spec/fixtures/api/preload-realm/preload-tests.js
vendored
|
@ -18,6 +18,76 @@ const tests = {
|
|||
? contextBridge.executeInMainWorld({ func, args })
|
||||
: contextBridge.executeInMainWorld({ func });
|
||||
return result;
|
||||
},
|
||||
testPrototypeLeak: () => {
|
||||
const checkPrototypes = (value) => {
|
||||
// Get prototype in preload world
|
||||
const prototype = Object.getPrototypeOf(value);
|
||||
const constructorName = prototype.constructor.name;
|
||||
|
||||
const result = contextBridge.executeInMainWorld({
|
||||
func: (value) => {
|
||||
// Deeply check that value prototypes exist in the local world
|
||||
const check = (v) => {
|
||||
if (typeof v === 'undefined' || v === null) return true;
|
||||
const prototype = Object.getPrototypeOf(v);
|
||||
const constructorName = prototype.constructor.name;
|
||||
const localPrototype = globalThis[constructorName].prototype;
|
||||
if (prototype !== localPrototype) return false;
|
||||
if (Array.isArray(v)) return v.every(check);
|
||||
if (typeof v === 'object') return Object.values(v).every(check);
|
||||
if (typeof v === 'function') return check(v());
|
||||
return true;
|
||||
};
|
||||
return { protoMatches: check(value), value };
|
||||
},
|
||||
args: [value, constructorName]
|
||||
});
|
||||
|
||||
// Deeply check that value prototypes exist in the local world
|
||||
const check = (v) => {
|
||||
if (typeof v === 'undefined' || v === null) return true;
|
||||
const prototype = Object.getPrototypeOf(v);
|
||||
const constructorName = prototype.constructor.name;
|
||||
const localPrototype = globalThis[constructorName].prototype;
|
||||
if (prototype !== localPrototype) return false;
|
||||
if (Array.isArray(v)) return v.every(check);
|
||||
if (typeof v === 'object') return Object.values(v).every(check);
|
||||
if (typeof v === 'function') return check(v());
|
||||
return true;
|
||||
};
|
||||
|
||||
return (
|
||||
// Prototype matched in main world
|
||||
result.protoMatches &&
|
||||
// Returned value matches prototype
|
||||
check(result.value)
|
||||
);
|
||||
};
|
||||
|
||||
const values = [
|
||||
123,
|
||||
'string',
|
||||
true,
|
||||
[],
|
||||
[123, 'string', true, ['foo']],
|
||||
Symbol('foo'),
|
||||
10n,
|
||||
{},
|
||||
Promise.resolve(),
|
||||
() => {},
|
||||
() => () => null,
|
||||
{ [Symbol('foo')]: 123 }
|
||||
];
|
||||
|
||||
for (const value of values) {
|
||||
if (!checkPrototypes(value)) {
|
||||
const constructorName = Object.getPrototypeOf(value).constructor.name;
|
||||
return `${constructorName} (${value}) leaked in service worker preload`;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -29,6 +99,9 @@ ipcRenderer.on('test', async (_event, uuid, name, ...args) => {
|
|||
ipcRenderer.send(`test-result-${uuid}`, { error: false, result });
|
||||
} catch (error) {
|
||||
console.debug(`erroring test ${name} for ${uuid}`);
|
||||
ipcRenderer.send(`test-result-${uuid}`, { error: true, result: error.message });
|
||||
ipcRenderer.send(`test-result-${uuid}`, {
|
||||
error: true,
|
||||
result: error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue