@@ -306,55 +306,86 @@ function HtmlRunner() {
306306 if ( ! externalLink ) {
307307 const indexPage = parse ( focussedComponent ( previewFile ) . content ) ;
308308 const body = indexPage . querySelector ( "body" ) || indexPage ;
309+ const htmlRoot = indexPage . querySelector ( "html" ) ?? indexPage ;
309310
310- // insert script to disable access to specific localStorage keys
311- // localstorage.getItem() is a potential security risk when executing untrusted code
312311 const disableLocalStorageScript = `
313- <script>
314- (function() {
315- const originalGetItem = window.localStorage.getItem.bind(window.localStorage);
316- const originalSetItem = window.localStorage.setItem.bind(window.localStorage);
317- const originalRemoveItem = window.localStorage.removeItem.bind(window.localStorage);
318- const originalClear = window.localStorage.clear.bind(window.localStorage);
319-
320- const isDisallowedKey = (key) => key === 'authKey' || key.startsWith('oidc.');
321-
322- Object.defineProperty(window, 'localStorage', {
323- value: {
324- getItem: function(key) {
325- if (isDisallowedKey(key)) {
326- console.log(\`localStorage.getItem for "\${key}" is disabled\`);
327- return null;
328- }
329- return originalGetItem(key);
312+ <script>
313+ (function () {
314+ "use strict";
315+ const isBlocked = (key) =>
316+ typeof key === "string" && (key === "authKey" || key.startsWith("oidc."));
317+ const wrapLocal = (storage) =>
318+ storage && {
319+ getItem(key) {
320+ return isBlocked(key) ? null : storage.getItem(key);
321+ },
322+ setItem(key, value) {
323+ if (!isBlocked(key)) storage.setItem(key, value);
324+ },
325+ removeItem(key) {
326+ if (!isBlocked(key)) storage.removeItem(key);
327+ },
328+ clear() {},
329+ key(index) {
330+ const name = storage.key(index);
331+ return isBlocked(name) ? null : name;
332+ },
333+ get length() {
334+ return storage?.length ?? 0;
335+ },
336+ };
337+ const apply = (host) => {
338+ if (!host) return;
339+ try {
340+ const guarded = wrapLocal(host.localStorage);
341+ if (!guarded) return;
342+ Object.defineProperty(host, "localStorage", {
343+ configurable: false,
344+ enumerable: false,
345+ get: () => guarded,
346+ set: () => undefined,
347+ });
348+ } catch (_) {}
349+ };
350+ [window, window.parent, window.top, document.defaultView].forEach(apply);
351+ })();
352+ </script>
353+ ` ;
354+
355+ const disableSessionStorageScript = `
356+ <script>
357+ (function () {
358+ "use strict";
359+ const stub = {
360+ getItem: () => null,
361+ setItem: () => undefined,
362+ removeItem: () => undefined,
363+ clear: () => undefined,
364+ key: () => null,
365+ get length() {
366+ return 0;
330367 },
331- setItem: function(key, value) {
332- if (isDisallowedKey(key)) {
333- console.log(\`localStorage.setItem for "\${key}" is disabled\`);
334- return;
335- }
336- return originalSetItem(key, value);
337- },
338- removeItem: function(key) {
339- if (isDisallowedKey(key)) {
340- console.log(\`localStorage.removeItem for "\${key}" is disabled\`);
341- return;
342- }
343- return originalRemoveItem(key);
344- },
345- clear: function() {
346- console.log('localStorage.clear is disabled');
347- return;
348- }
349- },
350- writable: false,
351- configurable: false
352- });
353- })();
354- </script>
355- ` ;
356-
357- body . insertAdjacentHTML ( "afterbegin" , disableLocalStorageScript ) ;
368+ };
369+ const apply = (host) => {
370+ if (!host) return;
371+ try {
372+ Object.defineProperty(host, "sessionStorage", {
373+ configurable: false,
374+ enumerable: false,
375+ get: () => stub,
376+ set: () => undefined,
377+ });
378+ } catch (_) {}
379+ };
380+ [window, window.parent, window.top, document.defaultView].forEach(apply);
381+ })();
382+ </script>
383+ ` ;
384+
385+ // insert scripts to disable access to specific localStorage keys and sessionStorage
386+ // entirely, they are both potential security risks when executing untrusted code
387+ htmlRoot . insertAdjacentHTML ( "afterbegin" , disableLocalStorageScript ) ;
388+ htmlRoot . insertAdjacentHTML ( "afterbegin" , disableSessionStorageScript ) ;
358389
359390 replaceHrefNodes ( indexPage , projectCode ) ;
360391 replaceSrcNodes ( indexPage , projectMedia , projectCode ) ;
0 commit comments