Skip to content

Commit

Permalink
Protect document.open too (#65)
Browse files Browse the repository at this point in the history
  • Loading branch information
weizman authored Jan 24, 2023
1 parent 4073f99 commit 214573b
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 2 deletions.
3 changes: 2 additions & 1 deletion snow.js
Original file line number Diff line number Diff line change
Expand Up @@ -636,7 +636,7 @@ function natively(win, cb) {
function natives(win) {
const {
EventTarget
} = win;
} = win; // PR#62
return natively(win, function (win) {
const {
console,
Expand Down Expand Up @@ -970,6 +970,7 @@ function hook(win, native) {
function hookOpen(win) {
hookMessageEvent(win);
win.open = hook(win, win.open);
win.document.open = hook(win, win.document.open);
}
module.exports = hookOpen;

Expand Down
2 changes: 1 addition & 1 deletion snow.prod.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions src/open.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ function hook(win, native) {
function hookOpen(win) {
hookMessageEvent(win);
win.open = hook(win, win.open);
win.document.open = hook(win, win.document.open);
}

module.exports = hookOpen;
95 changes: 95 additions & 0 deletions test/open.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,99 @@ describe('window.open API', () => {
});
expect(result).toBe('V');
});
});

describe('document.open API', () => {
beforeEach(setup);

it('should fail to use atob of a window that was created via document.open API', async () => {
const result = await browser.executeAsync(function(done) {
const bypass = (wins) => done(wins.map(win => (win && win.atob ? win : top).atob('WA==')).join(','));
(function(){
const win = document.open('', '', '');
bypass([win]);
}());
});
expect(result).toBe('V');
});

it('should fail to use atob of a window that was created via document.open API to cross origin and then changed to same origin', async () => {
const result = await browser.executeAsync(function(done) {
const bypass = (wins) => done(wins.map(win => (win && win.atob ? win : top).atob('WA==')).join(','));
(function(){
const win = document.open('https://example1.com', '', '');
setTimeout(() => {
if (!win || !win.location) {
return bypass([top]); // give up
}
win.location.href = 'about:blank';
setTimeout(() => {
bypass([win]);
}, 1000)
}, 1000);
}());
});
expect(result).toBe('V');
});

it('should fail to use atob of a window that was created via document.open API to cross origin and then changed to same origin and leaked it via postMessage (onmessage)', async () => {
const result = await browser.executeAsync(function(done) {
const bypass = (wins) => done(wins.map(win => (win && win.atob ? win : top).atob('WA==')).join(','));
(function(){
onmessage = (a) => {
const x = a.source;
if (!x || !x.location) {
return bypass([top]); // give up
}
x.location.href = 'https://example.com/';
setTimeout(() => {
bypass([x]);
}, 1000);
};
document.open('https://lavamoat.github.io/snow/test/test-util.html', '', '');
}());
});
expect(result).toBe('V');
});

it('should fail to use atob of a window that was created via document.open API to cross origin and then changed to same origin and leaked it via postMessage (message)', async () => {
const result = await browser.executeAsync(function(done) {
const bypass = (wins) => done(wins.map(win => (win && win.atob ? win : top).atob('WA==')).join(','));
(function(){
addEventListener('message', a => {
const x = a.source;
if (!x || !x.location) {
return bypass([top]); // give up
}
x.location.href = 'https://example.com/';
setTimeout(() => {
bypass([x]);
}, 1000);
});
const x = {};
x.toString = () => 'https://lavamoat.github.io/snow/test/test-util.html';
document.open(x, '', '');
}());
});
expect(result).toBe('V');
});

it('should fail to use atob of a window that was created via document.open API to javascript: scheme, leaked to opener and then changed to cross origin and back to same origin', async () => {
const result = await browser.executeAsync(function(done) {
const bypass = (wins) => done(wins.map(win => (win && win.atob ? win : top).atob('WA==')).join(','));
(function(){
document.open('javAscRipt\:opener.win=window;location.href="data:1"', '', '');
setTimeout(() => {
if (!top.win) {
return bypass([top]); // give up
}
top.win.location.href = 'https://example.com';
setTimeout(() => {
bypass([top.win]);
}, 500);
}, 500);
}());
});
expect(result).toBe('V');
});
});

0 comments on commit 214573b

Please sign in to comment.