 Hi everyone, good morning. So I'm very happy to give the first talk, open the session. This is the second time I think I'm doing it in JSFOO. And it's always a good experience to open the talk because most developers, programmers usually work through the nights. So the first talk, it's a bit of a responsibility because like myself, I sleep at around 4. So I'm a little sleepy myself. I'm assuming it's similar to you as well. So I would try and make the first talk as engaging as possible. OK. So the talk itself is on a very important topic. How many of you here have heard about a recent attack group or hacker group called as magecott or attacks called as magecott attacks? Anybody? Is anybody here from the time? I'm sure most of you are young developers. But is anybody here from the time before when front end was taken seriously? JavaScript was taken seriously as a language. So there is this saying, which is you know you've made it when people start attacking you. So it's kind of similar here as well because till now all the major security attacks, they were on the back end. They were targeting back end applications and black technology stack and so on. So magecott is an attack which primarily focuses on the front end. So if the attack happens on the front end and the impact is on the front end and the data loss is also on the front end. So I think in an ironical sort of way, I should say congratulations to front end folks because now you guys have finally made it because you have attackers targeting your stack. OK. So through this talk, we'll try to understand the attacks of this nature and we'll see how these can be detected and then eventually stopped using a technology called as content security policy. So that's the background. A little bit about myself. I'm the founder of Iron Wars for security. It's a pure play product, security product based startup. We develop several products on continuous application security. We do content security policy automation. Some of the technologies we develop there is what I'm going to present in the talk. And this is the outline for the talk itself, which is we'll talk about data exfiltration attacks. We'll understand what they are, how they work. And we'll discuss how they can be detected using content security policy. And we'll see how this can be implemented. So I'll give you a set of steps or a guideline, if you will, of how you can deploy or how you can put a mechanism to detect this. And what are the limitations for an approach like this and how you can possibly try and overcome those limitations? OK, so let's start with understanding data exfiltration. Now, so there are these three companies. Now, obviously, as you can see, these are big names. New Egg, for example, is one of the top retailers in the US. They handle several millions of transactions in a day. And all these three companies were affected by hackers back in 2018. And this is the kind of impact they had. New Egg had lost more than 45 million credit card information of their customers. And British Airways and Ticketmaster, they were hit equally as well, loss of several thousands of credit card information. Now, anybody would say that this is a serious attack, because there's a lot of credit card data being lost. But what is more interesting here is not just the impact, but this, which is the duration for which the attack actually took place. So if you see in all of these cases, the attacks went on for what we can say is a significant period of time. Like even the shortest case, which is British Airways, where they lost about half a million credit card information, the attack went on for over two weeks. And this is unacceptable for any big organization to be under active attack, losing their customer's data for such a long duration. It simply doesn't happen in normal circumstances. So the reason why it happened with British Airways and all of these companies, now these are big companies, they have a lot of security practices and a lot of security tools and other mechanisms in place. But still the attacks went on undetected for a long time, in fact, a ticket master went on for more than eight months. You can even have a baby in that much time. That's how long the attack actually went on. So we'll try and see why this actually happened. The reason is because you have all of these security monitoring and processes and everything, usually on the server side, right? But there's nothing on the client side. So let's say if this is a very poor and simplified representation of your infrastructure, then you have your monitoring systems covering your server. So if there's going to be a data leakage on the server side, then it gets picked up by any of these monitoring systems. It can be in your data center, it can be in your cloud. You have these monitoring systems in place. But let's say if a person connects to your website through their browser and from the user's browser. So your JavaScript is loaded in the user's browser and due to some reason, this JavaScript is now sending the user's credit card information to somebody else. So this is data leakage on the client side. And this usually goes undetected because you do not have any mechanisms in place to look for egress data from the browser itself, right? Which your site might be sending outside. So this is why the attack could go undetected on all of these companies for such a long time irrespective of them having good security measures in place. Now, how does a data leakage like this happen? So we can talk about this. So this is a brief representation of that which is attackers try and look for sites where they can inject their JavaScript into your website. How they can do it, we'll just talk about it briefly. So they find some way to inject their JavaScript into your site. Once they do that, they just wait for customer data to hit their servers. And then every time a user goes to your website and then they are interacting with it, they're putting a data inside it. The attackers JavaScript which is running inside it will take this information and it'll send it to their server. It's a very simple process. Now, in terms of how the attackers JavaScript can enter into your website, there are four ways in which this can happen. One is cross-aid scripting. How many of you have heard about cross-aid scripting? Most of you. And I'm sure you've taken counter measures to prevent that it does not happen. In fact, most of the modern frameworks, React and Vue.js and so on, they automatically escape whatever data you try to show on the DOM. So there are a lot of things which they try and do to prevent that, to automatically protect you from, or you can say they are secure by default, unless you actually go and do something wrong or you do a lot of direct DOM API calls, you are mostly secure from doing cross-aid scripting. But then again, you might be using a lot of libraries, you might be using external widgets and so on, and they might actually have problems in them. So cross-aid scripting is one easy way in which anybody can inject JavaScript code into your websites. And the other one is compromise of external CDNs. It's a little far-fished, but it does happen where you're loading in code from external servers, and if those servers get compromised through whatever means, then your site will get affected as well. And the other one is compromised ad networks. A lot of websites include advertising code inside them. They use analytics code and similar types of external code. You might have chat widgets and so on. And if they were to have a problem, then also you might get affected. And then finally, you have compromised web servers where your server gets compromised, so an attacker is able to go and modify the JavaScript code. So there is a vulnerability on your server. The attacker is able to compromise it. And instead of doing anything, any damage to your backend or trying to steal data from your backend, what the attacker instead does is he goes and modifies the JavaScript files on your server. In fact, there's a very recent example of this where about 13,000 odd websites were infected by the same mage card attack group. And the way it was affected was they were looking for AWS buckets, which were misconfigured. So when a bucket is misconfigured, what can happen is anybody who has a valid AWS credential, instead of just being able to read your buckets, they can also write to the bucket. So what these guys did was they scanned for these misconfigured buckets and there were quite a lot of them and they looked for JavaScript files inside them and wherever they found JavaScript files, they went and they modified those JavaScript files. And all the websites which were loading JavaScript files from these buckets, all of them were infected and the number was roughly around 13,000. So it's a big number. Okay, so this is an example of an actual attack which took place on British Airways. What the attackers did was British Airways was loading this library called Modernizer, right? Attackers found a way to compromise the server and what they did was they modified the content of the Modernizer.js. What they did was they added about eight or nine lines of JavaScript code to the end of this Modernizer JavaScript, right? So which means that wherever British Airways was loading this JS code into their site, all of those pages were also under the control of the attacker. Okay, now once an attacker is able to get their JavaScript code into your site, how can they send this information out? So there are two steps to this attack. One is I inject the JavaScript into your site and then after that I get your user's information and then I'll have to send it outside. So how can you actually send it? One is you can try and load resources from an external site. We'll see how that can be used to send out data outside. You can navigate the user to an external site, connects to external sites where DOM APIs, you know, DOM has a lot of communication APIs like, you know, Ajax, I'm sorry, XML HTTP request and fetch and so on. So these can be used to send data outside. In case of British Airways, this is what the attackers were doing. The eight or nine lines of JavaScript code which was injected into modernizer.js, this is the, you know, de-minified or beautified version of the code. And it's actually pretty simple. What they're doing is they're just collecting the contents of the payment form and they make a post request to a website, a domain called baways.com. A baways.com was registered by these attackers and it looks similar to British Airways, but it doesn't actually belong to British Airways, it belongs to these attackers and they're sending a regular post request to send this data outside, right? And this little piece of code is what stole 500,000 credit card details of British Airways customers. Right, so one thing an attacker could do is they can try and load an, you know, resource from an external site, which is they can say script source and they can give a URL or they can say image source. They can give any, they can try to load any resource and they can actually put the data to be stolen as part of the URL, right? So which means this is one way by which you can make a request to an attacker's site and you can send data. The other way is, like I said, using a DOM API, you can actually make a normal Ajax request and you can put the data inside it. So it's important to know how you can send data so that you can actually try and prevent those exact means of sending data outside. So now we'll discuss about how you can actually detect if your site is leaking data to an external, you know, entity. So you can do it in two ways. The first way is at the JavaScript level and since all of you are JavaScript developers, this would probably be the more, you know, natural way to handle this. So the way you will do it in JavaScript level is you will first, you know, write some JavaScript code to do some monkey patching of the DOM APIs, you know, essentially create an abstraction layer and once you do that, every call to the native API, you will actually monitor it and you will see if this call is happening to somebody which is, you know, not trusted. For example, this is how it will look. Normally you have your native, you have your applications JavaScript code which is directly calling the native APIs and what you would instead do is you would write some code which will essentially hook your native APIs. You can think of it like a New Relic, you know, monitoring type of code and what this will do is every time your application tries to call, say, the DOM API, then the call will first come to your code. Your code can, you know, look at the call. It can determine if this has to be sent to the, you know, native DOM API. So you can have a whitelist of domain names, for example, and you can say, hey, these are the domains I normally communicate with and if the JavaScript code is trying to communicate to a domain which is not in the whitelist, then you can send an alert to your server, right? So you have full control over who your site actually talks to. And you can do the same for DOM manipulations as well. So for example, if there's a DOM manipulation and there's a new image SRC tag being added, you can monitor that and you can see if it's for a resource that you trust. Now the JavaScript approach is again, like I said, as JavaScript developers, it looks like the most obvious thing to do, but it has some downsides as well. The first thing is it's a complicated approach. You know, you'll have to do monkey patching for JavaScript and it's not a very straightforward process and it requires a lot of coding as well as maintenance effort, you know, because you'll have to again test all scenarios in your code to make sure that whatever you're doing is not breaking the site's functionality, not just the functionality that you've written as well as, you know, third-party code that you are importing inside. You don't want to make sure that it's not breaking any of that and you also want to make sure it does not have any performance impact because what you're doing is you're adding one extra layer of abstraction between the application's code and the native code. So that can put on a performance overhead and, you know, that is something you want to be careful about. So these are some problems with the JavaScript approach, although it's something which you might think is a more, you know, easier approach to take given your familiarity with the language. So I would propose an alternative approach which is through content security policy. How many of you know content security policy? Okay, that's good. How many of you have, or how many of your websites actually do use content security policy? Right, okay, good. I think almost half of the folks who know are using it and the other half I presume you bravely tried to venture into using content security policy and it was too complicated and you probably, you know, gave up somewhere. But anyway, the content security policy is a, it's a client-side technology. I'll discuss it briefly. But using this approach has several benefits. The first thing is it can be done either by the developers or it can be done by the network or infrastructure team. You know, it doesn't have a lot of coding effort. So you don't have to, if you don't code anything, then you don't have to maintain it as well. It's a much simpler approach and it will not break your site, at least if you put the CSP in the monitoring mode instead of blocking mode, your site will not break and it has no performance impact because it's a built-in functionality in the browser. You're not writing any code of your own. So, you know, performance-wise, it's really good. Right, so let's try and understand what is content security policy. I would like to call content security policy as, you know, like a firewall for the browser. You would never put your website out without any kind of, you know, firewall or a filtering mechanism for your application. But it's very ironical that for the client-side, you know, we put it out without any kind of a filtering system and CSP is like a filtering system for the client-side. So it's, you know, it's highly, you know, advisable to use CSP on your website. And CSP is essentially a single HTTP header. It's a HTTP response header. You know, that's all it essentially comes down to. You set one header and then you tell the browser how the browser has to behave based on that header. And you can put it again, like I said, in blocking mode as well as non-blocking mode. And when you put it in non-blocking mode, you get alerts about what the browser is doing. So it can act like a form of analytics system as well, if you want to use it that way. Right, so this is how a typical CSP header would look. We have two headers here. One is a normal CSP header. The other one is a CSP header in the report-only mode. So this is the blocking mode header and this is the monitoring mode header. And the header will have something called as a directive. I'll explain what a directive is a little later. So it'll have a directive and then that will be followed by something called as a report URI. Right, so if there are any violations, this is where the violations are essentially sent. Now CSP directives are essentially guidelines. So when I said CSP is like a firewall for your browser, the firewall will normally have rules, right? So the directives are the rules of this CSP type of firewall. This will essentially tell how a certain aspect of your browser should behave, okay? So for example, you have CSP directives which control loading of JavaScript code. You have CSP directives which control loading of CSS, CSP directives which control loading of iframes and so on. So each of those directives will, you know, control those individual behaviors. So for the task at hand, which is preventing data exfiltration attack or detecting data exfiltration attack, these are the kind of CSP directives that we would be interested in. So these are part of the slides. You can start with these. I'll explain them briefly, you know, a little down the line. Now each directive has a value. The value defines how the, you know, particular directive must be interpreted by the browser. So for most of the directives, the values would be either none, self, or it would be a single site name or a bunch of site names, you know, like a group of site names. And what these values specify is, let's say I have a directive called script src. Script src defines, you know, JavaScript loading behavior of your browser. So you can essentially tell your browser if it should load JavaScript code and if it should load JavaScript code, then where it should load the JavaScript code from. And for script src, if I put the directive as directive value as none, then essentially you're telling your browser, do not load any JavaScript code, you know, even though the HTML might try to load JavaScript code, you're telling the browser through the header, do not load and execute any JavaScript code. So even if your HTML is trying to refer a script from somewhere, your browser will not evaluate it. And if you set it to self, then it means that you're telling the browser to load JavaScript code from the same site, which is, if your site is hasgeek.com, then any JavaScript code loaded from hasgeek.com will be allowed by the browser, it will evaluate it. But if you're loading JavaScript code from an external domain, that will be blocked. And the third is you can specify an explicit domain name. You can say, hey, I want to load JavaScript code from this domain name, and you can make it as specific as you would like, which is you can give the exact domain name, you can give the protocol, which is HTTP or HTTPS, you can also give the path and file name, right? So you can be as specific as you would want to be in terms of which places you would like to load resources from, and you can also give multiple values, which is you can give a comma separated list of multiple domain names. So if you're loading JavaScript code from five or six different CDNs, you can give all of them in a comma separated value list. So this is typically how it would look. You can give the directive name, you know, followed by the corresponding value. So here we have a none for Connect S R C, Connect S R C defines your DOM communication API. So this would mean that if your site sets this as the CSP header, CSP policy, then from the browser, there would be no Ajax calls, you know, Ajax calls and some other DOM communication APIs will be turned off. Now when script S R C is self, this controls the JavaScript loading. So this would mean that JavaScript files only from the same domain will be loaded by the browser. And for style SRC, if you set it to this domain, then the browser will only note CSS files from this specific domain name. It will not even load it from the same domain, right? Okay, so now that we have looked at the list of CSPs, we look at them in a little detail, each of them. So script S R C, like I said, it'll control the loading of JavaScript, you know, resources in your browser. So if you give a script S R C, and then if you give a specific domain name, then only JavaScript files loaded from that domain will be loaded. If you load JS file from another domain, it'll be rejected by the browser. Style SRC is for your CSS files, similar behavior. Image SRC is for loading images. Connect S R C is for, like I said, communication APIs. And this would include your, you know, HNF Pings, Fetch, XML HTTP request, WebSocket and even source. Font SRC is for loading fonts through your CSS. Object SRC is for, you know, embedding videos and so on. I'm sorry, object SRC is for, you know, embedding, you know, objects into your application and media SRC is for videos and audio. Frame SRC is for external life frames. Worker SRC is when you want to start a web worker, it'll determine which URLs you can actually use. I'm sorry, the web worker JavaScript URL, where it can be allowed from. Form action is when you have an HTML form and then you submit the form, this will determine where this form can actually be submitted to, right? So you can control where your form contents get sent. Manifest SRC is for your manifest files, right? So this essentially covers all the different CSP directives which can essentially be used by an attacker to leak data to an external entity. And if you're going to use CSP to kind of control data leakage, then these are the only directives you'll have to be concerned about. CSP has several other directives as well. They are meant for different purposes. But for purposes of data leakage, these are the only directives you'll have to look at. Okay, so now that we know what does the CSP directive, what are its possible values and what CSP directives we'll have to use, you know, the directives of interest. Now, when you write a CSP policy, you will have to whitelist the domains which can actually load resources, right? Now in a typical application, there are a lot of external parties from where you're loading different, different kinds of resources. You might be loading images from somewhere, you might be loading font from somewhere, you might be loading CSS from another place. Now for you to write a policy which defines your browser's, your application's behavior, you'll have to do a lot of study about your application, right? So which is a very time intensive task. So what you can actually do is you can actually let the browser itself tell you where it's loading, you know, resources from. So it's a little trick you can use. So what you can do is you can make use of CSP violations. Now CSP violations are essentially in your policy, you can say report URI, and you can give a specific URL. And anytime there's a violation with the policy. So the resource that your browser is trying to load is different from the policy that has been defined from you. That would be considered as a violation. And your browser will send a report for that violation to this report URI. And if you look at this reports, then you will get to know, you know, which, what kind of places your, your application is actually loading resources from. This is what a typical report actually looks like. So you can see the document URI is a URL from where this, URL at which this violation actually took place. Blog URI is the resource which the browser was trying to load, which caused the violation. So in this case, it's trying to load, you know, CSS, style.css from example.com. And violated directive is the exact CSS directive, which was violated because of that particular resource. So CSS directive here says style.css.cdn.example.com. It says CSS files can only be loaded from cdn.example.com. But the pay, but this particular page was trying to load CSS from example.com. So which is a mismatch. So this particular violation was generated and this report was sent. It's a, it's a little JSON, you know, format data, which is sent. This contains all of this information. If you look at these reports, you will get to know from where you are, what all places your site is loading, you know, resources from and what kind of resources. Okay, so what you can do is, you can actually start with a very simple CSS policy. You know, you don't have to know a lot about your website. You start with a simple startup policy and then you look at the violations which are generated as your users are using, browsing your website, right? And using, once you look at the violations, you can then go back and you can update the policy. Like for example, you start with a policy like this, let's say, stylusrccdn.example.com and then you start getting violations for this. So now you know that your site is also loading data from CSS from example.com. So what you then do is you go and update the CSS policy to include cdn.example as well as comma example.com, right? So which means that this violation will now go away. So now if you do this as a cycle, then you know, you will reach, you can say like a sort of equilibrium in a few days or a few weeks depending on how frequently you are looking at your violation reports and you're updating your CSS policy. And once you hit equilibrium, then it means that you have created a baseline for your website's behavior, right? And once you create this baseline, any violations which come after that are usually, activities done by attackers or by external scripts or something which are undesirable. So once you have this equilibrium, then any further violations will essentially let you detect your egress traffic from the browser because now if the attacker, you know, if you go back to the earlier case of British Airways, right? So you have defined return a CSV policies which defines your connected source directive which says which sites you can make DOM communication API calls to and you know, that is well defined. And if an attacker is able to now compromise your site and if he is making an Ajax call to baves.com, then because that's different from the CSV policy, you will get a CSV alert, right? And if it is affecting several users, you will start getting several thousands of CSV violations, right? And then you can look into it and again, the CSV violation tells you in which URL it happens and it can also in some cases tell you at which line of code a violation is taking place, which is if there's an Ajax call being made, then it'll also tell you in which line of code this, you know, Ajax call, which is violating the CSV directive is being made. And if you get enough reports, violation reports, then you can actually go investigate and find out if it's a code change which has legitimate and you actually want to communicate with this third party or if it is because of an attacker, you know, who has modified your site's, you know, code and he is stealing data, right? So to get started, this is, this can be used as an initial starting point. It's a very simple policy where I have mentioned all of those, you know, directives of interest and for all of them you can start with self, which is essentially you are saying you can load all of these resources from the same domain, which is a very likely scenario. And if you start with this, the number of violations you will get at the beginning will not be massive. You can start with none, which means you're just saying, I don't want to load any resource at all. So which means every resource loaded will throw a violation but then you will be hit with a ton of violations. So you can start with self, which is good enough and you can then look at the reports and you can slowly, you know, work yourself up from there. Now, this is how you can use CSP to, you know, possibly detect data frustration attacks. I hope this was straightforward. Any questions, you know, on this before we get into the limitations? No, or if you would like want me to, yeah. Yeah, that's a very good question. If it's possible to block the attacks in real time, to block the attacks in real time, you'll actually have to have the policy in, you know, blocking mode, not in the reporting mode. But the problem is once you put a policy in the blocking mode, you have to be very careful because if there's a new code change, right? And because of a legitimate code change, you're going to load data from somewhere, then because of the blocking mode, it'll just prevent that functionality from working, right? So that's a common problem with CSP, which is in a very dynamically changing environment, you have to also constantly keep updating your CSP policy, right? So if you can do that, or if your site doesn't change all that much in terms of where you load data from, then once you have hit a equilibrium, once you have, you know, in a monitoring mode, once you've got a good enough policy, you see that there are no violations coming, then you can actually change the policy into the blocking mode state of CSP, right? In that case, if, you know, there's an attack, if there's a new resource being loaded from somewhere else, then it'll get blocked by CSP, and you'll also get a violation report for that. So it'll also block the attack, and it'll also tell you that, hey, I blocked this from happening. And if it's a legitimate thing, then it'll like break functionality, but seeing the alerts, you can go and, you know, you can update your CSP policy. But yes, it is possible to do that, but it has a little caveat and you have to be careful about it. Yeah. There's a mic there. Do we get any callback when it is violated so that we can block the UI or show the error message? Yeah, of course. So this violation report is the callback that you get, right? So the policy, the CSP policy will have a property called report URI. So where you can, you know, define an endpoint. And this endpoint will receive JSON information like this, right? So every time there's a violation, it'll have all of this data for you. Oh yeah, you have, there is an event, window event you can actually listen to. So you can get the same violation report from within JavaScript as well. So that is also possible. Yes, you have both the options, right? So that's a social engineering attack, right? Where it's the user who's being tricked into, you know, doing something. I mean, like the moment you take some JavaScript code and you put it into your console, at that point, you cannot really protect the users from themselves, right? So that is like, there are different ways in which you can convince a user to take a data and put it somewhere else. So we are not really trying to prevent that. We are more looking at cases where there is JavaScript code, attackers JavaScript code running into your site and that is automatically trying to send data away. That's what we're trying to block with this. So if you make a Ajax call from the console and if it violates the CSP directive, oh right, right, yes. You're saying that there'll be a new browser tab open and the URL will have the attackers data, yeah. So that's a good point. In fact, that is currently not covered under CSP. I'll be talking about it in the limitations of CSP, right? So that could still work. So my question is, which browsers support CSP and what if my client forces us to use a legacy browser where the CSP is not supported? Then what measures should we take to make the content secure? Okay, so this question, I'll talk about the limitations and then I can answer this, right? So the question is about which browser supports it and what do you do if a legacy browser is being used by your user, right? Okay, so I think I'll now go to the limitations part and then I'll answer this question. Okay, so CSP, although the approach, like I explained, it can help you with this kind of an attack but then it has its limitations as well. The limitations are CSP was not designed for this purpose. It was designed to prevent cross-site scripting attacks. That was the original intent of CSP. So anytime you take a technology designed for one purpose and then you use it in a different way, it's essentially a hack, which means there would be limitations to the approach. So there are known bypasses. One is something called DNS prefetching, a setting location or register of navigation where I'll probably just explain them one by one. There's an approach called DNS prefetch where the attacker instead of trying to load a resource from an external domain, he can actually try to prefetch a resource and the data to be stolen, he can actually put it as a subdomain name. So which means there will be a DNS lookup which will be made. So the lookup will go to the attacker's DNS server and from the DNS server, he can get the data that he wants to steal. So or he can try to navigate the user to a different domain by setting the location or register of property or he can have a hatch of link. You click on the link, it navigates the user to a different page to the attacker's site and it can have the stolen data. This is the scenario that he was actually talking about. So this will not get picked up by CSP and he can also do a window.open and he can open a new tab with whatever URL he wants to. So these are known limitations with this approach but should you still use CSP? I would say yes, because it makes the attack still relatively harder for an attacker to perform. Like in the case of British Airways, if you see they were just using a regular Ajax call to make that, you know, steal the data. So by using this, you are actually making it harder for the attacker. The other thing is CSP version three is having fixes for some of the bypasses I discussed about. I'll speak about those fixes briefly. So if you invest in CSP now and if you have started the process, once CSP version three is supported by the browsers, then these bypasses will also get fixed automatically. So it's not like these will remain open for eternity. So if you start the process now, then it'll eventually catch up with you. So for prefetch, you have a new directive called prefetch.src. So this will prevent the resource prefetch queries from being made. For navigation, there is navigate too. So this will block the scenario that you are referring to. It'll block all kinds of navigation. Link, window.open, location.href. And there is one other thing you can do with CSP, which is you can actually, from time to time, script src as none. So once you set it as none, you will get a list of all JavaScript code which is loaded by your site. And you can make a list of that and you can reset it back to the normal value. And every once in a while, you can set it back to none again, get the list again, and you can keep comparing this list and you can see if there are any changes there. And if there's any change, any new JavaScript file which is being loaded, then you can review and make sure if it's actually a legitimate JavaScript file or if it's an attacker-controlled JavaScript file. So this is again something you can do through CSP to try and cover some of the limitations there. Okay, so now I think I'll answer this question about the browser support itself. CSP version two is supported on all major browsers. And Chrome is by far the most popular browser and it has the best support for CSP, Mozilla as well. And Edge is now eventually going to get a Chromium, you know, WebKit internally. So that'll have first-class support as well. And in terms of legacy browsers, if some people are using legacy browsers, that's not so much a problem for us because that could be a problem if you're trying to block an attack. What we are trying to do here is we are trying to detect data leakage, right? So let's say you have 1000 users and even 200 of them are on Chrome, latest version of Chrome, right? And if your site is infected by an attacker's code and it is leaking data, then you will get violations from these 200 users. So you as a site owner, you're getting alerts, you get to know that there is something wrong in your site and you can go and investigate and you can go and fix it, right? You don't have to get alerts from all 1000 users, even the ones on the legacy browser. So that's not really necessary, right? So even though it is not supported in IE and older versions of IE, that's still not a problem because you get alert from even a certain section of your users, you get to know there's an attack and you can go fix it.