PIXI requires unsafe CSP
See original GitHub issueExpected Behavior
PIXI.js works with a strict CSP (e.g. script-src 'self'
) by default.
Current Behavior
PIXI.js requires an external module that patches it in order to work with strict CSP (@pixi/unsafe-eval
). Not being safe by default opens a number of attack vectors on the application of the developer:
- Opens the door to XSS due to PIXI itself. Even if today your use of
new Function
is safe (has anyone conducted a security audit recently?), as code evolves, there is a significant risk that an XSS vulnerability will be introduced by accident. - A relaxed CSP allowing unsafe eval can’t be applied just to PIXI (as far as I know, let me know otherwise), so because of PIXI, the unsafe eval behavior has to be allowed on the entire app. While PIXI engineers can, to some extent, be confident in the security of the PIXI library, you can’t be confident about any other code landing on the final application of the developer.
The whole point of CSP is to deal with situations in which you can’t reliably ensure the quality of all the sources being pulled into your final application.
Possible Solution
Make @pixi/unsafe-eval
the default behavior of PIXI.js, and instead create an external module to make PIXI faster for those devs who need the extra speed and know what they are doing. Most likely, the majority of developers won’t need the extra speed, but their end users will appreciate the extra security.
Steps to Reproduce
Add a strict CSP meta tag to your HTML (or a header):
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
Run a PIXI-based application.
Environment
pixi.js
version: 5.3.8- Browser & Version: Chrome 89
- OS & Version: Ubuntu 20.04.2
- Running Example: n/a
Related: #5509
Issue Analytics
- State:
- Created 2 years ago
- Reactions:2
- Comments:13 (7 by maintainers)
Top GitHub Comments
I just ran into this issue as well while upgrading the security of our CDN. One thing I’d like to add to this is that even with the
@pixi/unsafe-eval
package the try/catch detection causes a CSP violation. This is hidden from the console logs but if you use any of the reporting directives, like report-to, report-uri, or the Content-Security-Policy-Report-Only header this violation will get logged. In essence this means you’ll get a violation report from every user loading the app.I am confident that PIXI’s use of
new Function
is pretty much safe but I don’t really like that in order to enable that you will basically have to allow unsafe eval for all scripts on your site.One other option for the future might be the strict-dynamic directive. That should allow trusted scripts to run arbitrary generated code. The documentation shows an example of the script add a new
<script>
tag dynamically. I’m not 100% sure if that applies toeval
andnew Function
as well. However this is not supported in some common browsers yet (like Safari) so I guess we’ll have to wait and see how it goes.Also while testing this with the require-trusted-types-for header I found out that Chrome’s trusted Function implementation has a bug which causes even more headache for PIXI’s
new Function
usage - in essence it won’t work without that workaround even with the@pixi/unsafe-eval
package.I think @SukantPal’s idea for a long term solutions sounds good - I was thinking of something similar before landing on this issue. This would really make all of this discussion irrelevant since it all boils down to the runtime usage of
new Function
:And while I agree in principle with @ivanpopelyshev’s comment about using the language features I have to point out that some language features turn out to be mistakes later on and will get deprecated (or blocked by security features):
All that said, we will be sticking with the allow
unsafe-eval
CSP directive for now as the world doesn’t seem ready for a more secure configuration with PIXI yet. As a fix for the CSP violation reporting spam it would probably make sense to add a “force” parameter to the unsafe-eval install function so the detection can be skipped in scenarios where you know it won’t be allowed.Don’t get me wrong. I love PIXI. I’ve been writing raw WebGL pretty much since it came out 10 years ago, and PIXI changed completely the way I write games and especially level editors, allowing me to focus on the app logic rather than fighting the GL state machine. It’s comparable to what OpenSceneGraph did to my code back in the 90s, when I could stop writing raw OpenGL for C++. Thanks a lot for your work!
I understand that there is a trade-off between performance and security. My argument is that by default any web library, including PIXI, should favor security by default, especially when the developer has explicitly enabled CSP because they care, and fall back to performance upon conscious choice by the developer.
Right now, whenever a user has a strict CSP, PIXI just doesn’t work. The developer gets a helpful message in the console, but all of the sudden, they are forced to choose between installing an extra module that will make their app slower, or relaxing their CSP. Guess what, most junior developers when faced with that dilemma, blindly choose performance, because they are unable to gauge whether the performance degradation matters at all to their app/game, and loosing frames seems like a much more tangible risk than having an XSS bug in their “perfect” app/game code.
Here is another alternative:
You already do feature detection in order to show that use @pixi/unsafe-eval message. What if instead of failing with that message, you automatically enable safe+slow mode when you detect a disabled eval (maybe with a console warning about performance implications) and run in unsafe+fast mode whenever eval is allowed?
That way, PIXI would always work regardless of the CSP setting, and people without performance issues wouldn’t need to worry about it at all. Does that sound like a reasonable trade-off?