# MathJax requires unsafe "Content Security Policy" #256

Closed
opened this issue Jun 11, 2012 · 41 comments

Projects
None yet

### mikkorantalainen commented Jun 11, 2012

 The current MathJax implementation uses following features that are not considered safe in modern world and cannot be used with default Content-Security-Policy (http://www.w3.org/TR/CSP/) headers: JavaScript evaluation of strings (new Function() with a string or eval()) (1) Inline style attributes inserted via JavaScript (2) It's debatable if issue (2) should be fixed but at least (1) should be fixed because Content-Security-Policy does not have enough granularity to allow MathJax to execute as a trusted script and in the same time do not interpret every other JavaScript file as specially trusted. Currently, if one wants to use MathJax, he must allow eval() everywhere. The issue (1) also causes bug #130 (MathJax is incompatible with ECMAScript 5 strict mode). Currently the only way to make MathJax to work, even if one uses locally installed MathJax code, is to use following CSP HTTP headers (the deprecated "options" header is included for Firefox 13.0 and lesser): X-Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; options eval-script X-WebKit-CSP: default-src 'self'; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline' Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'  These headers will allow some CSP provided protection and still allow MathJax to work, if MathJax is distributed from the same origin as the page content.

### matthewrobertson commented Jul 9, 2012

 unsafe eval is a big issue for me as well. Very soon chrome will force all extensions to adopt a content security policy that bans the use of eval. We are currently trying to upgrade Readium to comply with this but we cannot use do so and use MathJax

 +1
Member

### pkra commented Jul 16, 2012

 Thanks guys. We'll look into it.
Member

### pkra commented Jul 17, 2012

 Just a preliminary update. It seems possible to fix some of the issues soon enough (hopefully enough for the Chrome store). However, we're not sure how the performance will suffer -- which, as you can guess, could be bad. We'll keep you updated when @dpvc can look at this in more detail and perhaps create some experimental branches. If you have additional comments, questions and suggestions about specific code, please let us know.

### matthewrobertson commented Jul 17, 2012

 I spent a bit of time looking into it myself. It seems like you guys need to stop with the premature optimization. Evaling a string is NOT faster than creating a closure.

### matthewrobertson commented Jul 17, 2012

 Also, you shouldn't be running eval() on every page that loads Mathjax just to check if you can run eval(). Basically, this needs to go.
Member

### dpvc commented Jul 18, 2012

 The new Function() calls are not for speed but for memory. The new Function() doesn't create a closure, and so doesn't hold onto the local scope. Since this is at the heart of the object-oriented programming model, and there are lots of objects in use, it could have an impact on memory usage. I haven't done any testing of that in recent browsers. As for eval usage, MathJax does use it to handle its in-line configuration blocks, and that could not be easily replaced at this point. So a "safe" version of MathJax would need to use external configuration files (which should not be a problem, and probably is more in line with the security policy anyway). The eval call you refer to is not to determine if eval can be run, but to determine if it runs in the global namespace (which isn't the case in all browsers). I'm aware that this would need to be removed for a version that would work with your security needs.

### matthewrobertson commented Jul 18, 2012

 That is not how closures work in javascript. You do not hold on to everything in local scope; you only capture things that your function uses. Your CONSTRUCTOR function uses nothing from the local scope there is no cost to creating the closure. This is premature optimization for a problem that never existed. As far as the eval thing is concerned my point is that you should not be running code on a page if you don't need to, especially if that code that uses unsafe eval(). You only use that EVAL function if Mathjax has been included with in-line configuration so, don't run the test for it until you need to. But really, why on earth does the configuration have to be executable code. It is really just a chunk of JSON that is passed to function. Why not just pass the JSON, parse it and have MathJAX call the function?
Member

### dpvc commented Jul 18, 2012

 That is not how closures work in javascript. You do not hold on to everything in local scope; you only capture things that your function uses. I don't think things are as clear cut as that. First, this was not the case back in 2008 when that part of the code was written. I have just run tests this morning that appear to confirm that the versions of Safari, Firefox, Opera, and IE in play at the time all worked the way I described (the complete scope chain was retained in a closure, regardless of the variables used). The site that is my reference for this seems to be down this morning (was up yesterday), so I can't check details, but my recollection is that this was part of the ECMAScript 262 specification. Current versions of Safari, Chrome, Firefox, and IE do appear to work as you describe, so somewhere since then things have changed. It looks like Safari 4, Firefox 3.6, and IE9 were where the change occurred; I don't have old versions of Chrome to test, so don't know the history there. IE8 has the older behavior, and Opera 12 still does. I have not checked mobile devices. Some of these browsers are on MathJax's support list, so it is still an issue that we have to consider for MathJax in general. Of course, I'm sure something can be worked out for your needs. As for JSON data, the configuration block may be more than just a MathJax.Hub.Config() call. For example, you can install event listeners, or add functions to the TeX input jax to implement additional commands, and so on. These can't be part of JSON data because they include executable code. This feature is not always used, but it certainly is being used by actual web sites. In addition, not all the target browsers have a JSON library built in, and so there would need to be additional libraries to do the parsing. (Certainly not insurmountable, but more code to download.)

Open

### ketch commented Sep 24, 2013

 +1 for changing this, so that (among other things) Github will allow MathJax in their wikis again.
Member

### pkra commented Sep 24, 2013

 @ketch do you have a reference for Github making a statement in this regard? I don't see how this issue touches Github Wiki security.

### ketch commented Sep 24, 2013

 @pkra I don't know for certain that this is the cause, but I believe it to be so. I was led to this by the comments on this page: http://stackoverflow.com/questions/16889421/how-to-insert-javascript-to-enable-mathjax-on-github-wiki-pages And see https://github.com/blog/1477-content-security-policy I believe MathJax support disappeared at the same time that they implemented the CSP feature.
Member

### pkra commented Sep 24, 2013

 Thanks, that's interesting. I'm not sure the two are related but who knows -- the github team never publicly discussed why they removed MathJax. It would be unfortunate if something that's actually a non-issue for their setup would have been the reason.

### tss commented Sep 25, 2013

 +1 for complying with CSP.

 +1

### matteius commented Oct 31, 2013

 I read this thread and found it very informational and fairly unbiased. I am going to stake my claim that they [github] would prevent something like exec, CSP on the matters of security and not allowing it. Besides being mystified by that code sample and your mythic computer lore of past versions, I find it very interesting none the less and take the position of that a feature should be made available for its continued use, though it shouldn't interfere with the happy path of using MathJAX in security concerned world.

### ketch commented Nov 29, 2013

 By the way, I e-mailed Github support about why they dropped MathJax. Here is the reply: CSP was one of the reasons. Other reasons included performance issues, and hard maintenance. We might consider adding it back if we eliminated the reasons that lead us to remove it, but I can't promise that.
Member

### pkra commented Nov 30, 2013

 Thanks @ketch , that's good to know.
Member

### pkra commented Dec 10, 2013

 @dpvc should we add this to the next milestone?

 👍
Member

### dpvc commented Dec 10, 2013

 @pkra, I was planning to add it. Just hadn't gotten this far down numerically in the list yet.
Member

### pkra commented Dec 10, 2013

 @dpvc right. I was mostly wondering if fixing this would require significant changes (especially wrt inline configurations), i.e., force a version jump.
Member

### dpvc commented Dec 10, 2013

 The changes we made to allow configuration via the MathJax variable should make it possible to include it without a jump. I'm pretty sure I can do it with backward compatibility and without having to make a separate "safe" version of MathJax.js. Of course, something could show up during the development that would throw a monkey wrench into the works; none of it is written or tested yet.

### salomons commented Dec 13, 2013

 +1 for making MathJax secure. Too bad not being able to use this nice library in production due to the security concerns.

Closed

### emichael commented Mar 17, 2014

 Any progress on this issue? I'm trying to programatically inject MathJax into pages with a Chrome extension, and I'm hitting if not a brick wall at least a decently solid wall. As described in emichael/texthings#4, my biggest problem now is with MathJax.js:265. I was able to eliminate the calls to new Function() pretty easily by turning them into closures as described above, but I have no clue how to get around using eval or an inline script. EDIT: I ended up giving the user an option to add unsafe-eval and unsafe-inline to the CSP, but a long-term fix to get MathJax to a safe CSP would be nice. 👍
Member

### dpvc commented Mar 18, 2014

 @emichael, we are planning to include the changes in the next release (planned for next month), but I haven't made them yet. One reason is that I haven't looked into how you actually test this (how to set up the environment that requires it). If you could give me a suggestion of where to look or what a minimal testing environment might be, that would help. Also, is the error about eval one that occurs at run time or at compile time? That is, does it occur if MathJax.js simply includes an eval call, even if it is never used, or does it happen only when eval actually is attempted? My reading of the spec suggests that it should be a run-time error, which would make things better for me, but I thought you might know the answer.

### emichael commented Mar 18, 2014

 If you have a test server, you can just set Content-Security-Policy in the response headers. Just make sure that script-src doesn't include 'unsafe-eval' or 'unsafe-inline' (GitHub itself is a good example). If you don't, you can use a very minimal Chrome extension to inject the headers yourself. It's a runtime error.
Member

### dpvc commented Mar 18, 2014

 Thanks. I'll see what I can do. The eval command is only used to process the in-line configuration blocks (and there is an initial one to test how global variables are handled in that case). The initial one can be put off until an inline configuration is used, and if you avoid using in-line configuration, then that should take care of it. In v2.3 we added a new way of doing in-line configuration without eval (in preparation for resolving this issue), so you can still include MathJax configuration within the HTML files without triggering the eval call.

Member

### dpvc commented Mar 18, 2014

 OK, I've made a patch that removes the new Function() and eval() calls. It is based off the latest development branch, but the changes listed in f220993 should be able to be made to the master copy of MathJax.js as well, if you need to do that. You do need to allow in-line styles (there is really no getting around that). There is also a font reference to about:blank so that MathJax can test the response to a missing font (without having to make a network access), so you might want to add about: to font-src as well. Once I changed those two, this copy of MathJax ran without a hitch.

### emichael commented Mar 19, 2014

 Nice! I can see why you definitely need 'unsafe-inline' for styles. As far as the script-src 'unsafe-inline' permission goes, if I understand you correctly, scripts are only ever in-lined when the user includes inline MathJax configuration to start with. This would be fine, since everything could still work without 'unsafe-inline' in script-src. It should be mentioned in the docs, though.
Member

### dpvc commented Mar 19, 2014

 Your understanding about inline scripts is correct. You do not need script-src 'unsafe-inline' unless you are using in-line configuration blocks, which you don't need to use. You can use either a local MathJax configuration file (added to the config=) or you can use a normal script file that sets the MathJax variable to an object that you would normally pass to MathJax.Hub.Config() and load that file before your script that loads MathJax.js. For example, put var MathJax = { tex2jax: { inlineMath: [['$','$'],['\$','\$']], procesEscapes: true } };  into a file called mathjax-config.js and then   I hope that that takes care of your requirements.

### emichael commented Mar 19, 2014

 It does indeed. Thanks for the quick fix!!
Member

### dpvc commented Mar 19, 2014

 There are some here who would say it was not all that fast (the issue has been open for two years!), but I did have it marked for the next release, and was just getting down to it anyway, so your comment came at the appropriate time.

Closed

### dpvc pushed a commit that referenced this issue Mar 20, 2014

 Merge remote-tracking branch 'dpvc/issue256' into develop. Issue #256. 
 6a93073 

Member

### dpvc commented Mar 20, 2014

 => Merged.

Closed

### silky commented Jun 6, 2014

 so has anyone asked github to allow mathjax yet? it's still not possible to write a dotjs file that lets me write tex in github issues so-as to render with mathjax... (the example here - http://stackoverflow.com/questions/16889421/how-to-insert-javascript-to-enable-mathjax-on-github-wiki-pages - fails.)

### bvancil referenced this issue in kubetz/mathjax-bookmarklet Jun 19, 2014

 Merge pull request #4 from pkra/patch-1 
update CDN address
 4c31b62 

### diego898 commented Sep 11, 2014

 Hello, I am currently hosting a jekyll site on github pages and following this article, and have added the following to my includes file:   Which is supposed to work with https or http. However, when loading my blog on a browser with https everywhere it looks messed up until you click to allow unsafe script. How can I fix this?
Member

### pkra commented Sep 13, 2014

 @silky nothing specific AFAWK. Client-side is unlikely, I think, but MathJax-node could provide a productive alternative. @diego898 General questions fit better at http://groups.google.com/forum/#!forum/mathjax-users; always include a link to a live page, browser and OS specifics etc. Thanks.

### diego898 commented Sep 13, 2014

 @pkra I understand I just wasnt sure if it was bug related to this issue, or a configuration issue on my part
Member

### pkra commented Sep 15, 2014

 @diego898 no problem. What you describe does not sound like it's related to this issue.

Closed

Closed

Closed

### kaushalmodi commented Apr 27, 2018

 I am still seeing this issue. See #1988.
Member

### dpvc commented Apr 27, 2018

 @kaushalmodi, see my comment above about how to avoid the problem, or my comment to the issue you link to. You have to change how you configure MathJax if you are using a CSP that restricts script execution.

Closed