| 
 | 1 | +# GraphQL Playground HTML XSS Reflection Attack Example  | 
 | 2 | + | 
 | 3 | +This shows the simplest possible example for how one might re-create the XSS Reflection Vulnerability reported by Cure53.  | 
 | 4 | + | 
 | 5 | +Notice we force the resolution to `graphql-playground-html@1.6.20`, which is the last version susceptible. All prior versions are susceptible to the attack.  | 
 | 6 | + | 
 | 7 | +Dynamic, unsanitized input that resembles some of the configuration you see is a simple example - if url parameters, query parameters, unsanitized database text strings, etc are passed to `expressPlayground()`, `renderPlaygroundPage()` or equivalent middleware functions such as `koaPlayground()`, they are all vulnerable to this attack.  | 
 | 8 | + | 
 | 9 | +## Reccomendations  | 
 | 10 | + | 
 | 11 | +Here we use `xss` because it was easy to provide for node.js, however [DOMPurify](https://github.com/cure53/DOMPurify) is also an excellent choice for sanitizing strings for unwanted html. By default it requires the browser DOM, but you can load it with JSDOM for server side purposes as well.  | 
 | 12 | + | 
 | 13 | +here are a few more tips to prevent other XSS vulnerabilities that might exist in your own applications:  | 
 | 14 | + | 
 | 15 | +- `DOMPurify.sanitize` url values with user input to be used for rendering `<a href=` or `<script src=`, `<img src=` etc. whether using react or not!  | 
 | 16 | +- in react,`dangerouslySetInnerHtml={{ __html: { DOMPurify.sanitize(userInputString) }}` always!  | 
 | 17 | +- when doing direct dom manipulation, avoid `domElement.innerHTML = string` at all costs, but at least `DOMPurify.sanitize(string)` first if you must  | 
 | 18 | +- when generating an entire html file, sanitize *all* user input values (this was our mistake)  | 
 | 19 | + | 
 | 20 | +## Setup  | 
 | 21 | + | 
 | 22 | +```sh  | 
 | 23 | +$ yarn  | 
 | 24 | +$ yarn start  | 
 | 25 | +```  | 
 | 26 | + | 
 | 27 | +## Examples  | 
 | 28 | + | 
 | 29 | +Now that you've set up the example, you can view the examples:  | 
 | 30 | + | 
 | 31 | +### Example 1 - Query params  | 
 | 32 | + | 
 | 33 | +this one uses query parameters  | 
 | 34 | + | 
 | 35 | +http://localhost:4000/example-1?id=%3C/script%3E%3Cscript%3Ealert('I%20%3C3%20GraphQL.%20Hack%20the%20Planet!!')%3C/script%3E%3Cscript%3E  | 
 | 36 | + | 
 | 37 | +### Example 2 - DB Example  | 
 | 38 | + | 
 | 39 | +this one uses a mock database, to demonstrate more ways in which the function is susceptible  | 
 | 40 | + | 
 | 41 | +http://localhost:4000/example-2  | 
 | 42 | + | 
 | 43 | +### Example 3 - Upgrade workaround example  | 
 | 44 | + | 
 | 45 | +this one uses query like number 1, but shows how to use [`xss`](https://npmjs.com/xss) module to workaround the issue if you aren't able to upgrade  | 
 | 46 | + | 
 | 47 | +http://localhost:4000/example-3?id=%3C/script%3E%3Cscript%3Ealert('I%20%3C3%20GraphQL.%20Hack%20the%20Planet!!')%3C/script%3E%3Cscript%3E  | 
 | 48 | + | 
 | 49 | +### Example 4 - Always Safe example  | 
 | 50 | + | 
 | 51 | +this one uses static values, so it's safe without any workarounds! (try removing the ?darkMode parameter)  | 
 | 52 | + | 
 | 53 | +http://localhost:4000/example-4?darkMode=%3C/script%3E%3Cscript%3Ealert('I%20%3C3%20GraphQL.%20Hack%20the%20Planet!!')%3C/script%3E%3Cscript%3E  | 
 | 54 | + | 
 | 55 | +[XSS Safe using static configuration strings]("http://localhost:4000/example-3?darkMode")  | 
 | 56 | + | 
 | 57 | +## More Details  | 
 | 58 | + | 
 | 59 | +See more details in [SECURITY.md](../../../../SECURITY.md)  | 
0 commit comments