CVE-2020-4038: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79)
value: GraphQL Playground (graphql-playground-html NPM package) before version 1.6.22 have a severe XSS Reflection attack vulnerability. All unsanitized user input passed into renderPlaygroundPage() method could trigger this vulnerability. This has been patched in graphql-playground-html version 1.6.22. Note that some of the associated dependent middleware packages are also affected including but not limited to graphql-playground-middleware-express before version 1.7.16, graphql-playground-middleware-koa before version 1.6.15, graphql-playground-middleware-lambda before version 1.7.17, and graphql-playground-middleware-hapi before 1.6.13.
CWE description: The product does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.
CVSS v3 base score: 7.4
Published: 2020-06-08T21:15Z
Repository: https://github.com/prisma-labs/graphql-playground
Language: Markdown
Files changed: README.md, SECURITY.md, packages/graphql-playground-html/README.md, packages/graphql-playground-html/package.json, packages/graphql-playground-html/src/render-playground-page.ts, packages/graphql-playground-middleware-express/README.md, packages/graphql-playground-middleware-express/examples/basic/index.js, packages/graphql-playground-middleware-hapi/README.md, packages/graphql-playground-middleware-koa/README.md, packages/graphql-playground-middleware-lambda/README.md, packages/graphql-playground-middleware-lambda/examples/basic/README.md, packages/graphql-playground-react/README.md, scripts/build.sh, yarn.lock
Commit date: 2020-06-06 21:17:58 -0400
Commit message: Merge pull request from GHSA-4852-vrh7-28rf

* fix: security vulnerability allowing XSS reflection with user input

* fix: update docs, replace santize-html and sanitizeUrl with xss module
Diff: diff --git a/README.md b/README.md
index 49d098e..3dd18e5 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,10 @@
+> **SECURITY WARNING:** This `graphql-playground-html` and [all of it's middleware dependents](#impacted-packages) in this repository **had a severe XSS Reflection attack vulnerability to unsanitized user input** until version `graphql-playground-html@1.6.20`. Impacted are any and all **user-defined** input to `renderPlaygroundPage()`, `koaPlayground()`,`expressPlayground()`, `koaPlayground()`, or `lambdaPlayground()`. If you used static values, such as `graphql-playground-electron` does in [it's webpack config](https://github.com/prisma-labs/graphql-playground/blob/master/packages/graphql-playground-electron/webpack.config.build.js#L16), you were not vulnerable to the attack. [More Details](./SECURITY.md)
+
 <p align="center"><img src="https://imgur.com/5fzMbyV.png" width="269"></p>
 
-[![npm version](https://badge.fury.io/js/graphql-playground-react.svg)](https://badge.fury.io/js/graphql-playground-react) 
+[![npm version](https://badge.fury.io/js/graphql-playground-react.svg)](https://badge.fury.io/js/graphql-playground-react)
 [![prisma-labs](https://circleci.com/gh/prisma-labs/graphql-playground.svg?style=shield)](https://circleci.com/gh/prisma-labs/graphql-playground)
 
 **Future of this repository**: see [the announcement issue](https://github.com/prisma-labs/graphql-playground/issues/1143) for details.
 
 ---
@@ -23,10 +25,36 @@ $ brew cask install graphql-playground
 - 📚 Interactive, multi-column docs (keyboard support)
 - ⚡️ Supports real-time GraphQL Subscriptions
 - ⚙ GraphQL Config support with multiple Projects & Endpoints
 - 🚥 Apollo Tracing support
 
+## Security Details
+
+**NOTE: only _unsanitized user input_ to the functions in these packages is vulnerable** to the recently reported XSS Reflection attack.
+
+### Impact
+
+The only reason this vulnerability exists is because we are using template strings in `renderPlaygroundPage()` with potentially user defined variables. This allows an attacker to inject html and javascript into a page on execution.
+
+Common examples may be user-defined path parameters, query string, unsanitized UI provided values in database, etc that are used to build template strings or passed directly to a `renderPlaygroundPage()` or the matching middleware function equivalent.
+
+### Impacted Packages
+
+**All versions of these packages are impacted until the ones specified below**, which are now safe for user defined input:
+
+- `graphql-playground-html`: **☔ safe** @ `1.6.20`
+- `graphql-playground-express` **☔ safe** @ `1.7.15`
+- `graphql-playground-koa` **☔ safe** @ `1.6.14`
+- `graphql-playground-hapi` **☔ safe** @ `1.6.12`
+- `graphql-playground-lambda` **☔ safe** @ `1.7.16`
+- `graphql-playground-electron` has always been **☔ safe** from XSS attacks! This is because configuration is statically defined [it's webpack config](https://github.com/prisma-labs/graphql-playground/blob/master/packages/graphql-playground-electron/webpack.config.build.js#L16)
+- `graphql-playground-react` is safe because it does not use `renderPlaygroundPage()` anywhere, and thus is not susceptible to template string XSS reflection attacks.
+
+### More Information
+
+See the [security docs](./SECURITY.md) for more details on how your implementation might be impacted by this vulnerability. It contains safe examples, unsafe examples, workarounds, and more details.
+
 ## FAQ
 
 ### How is this different from [GraphiQL](https://github.com/graphql/graphiql)?
 
 GraphQL Playground uses components of GraphiQL under the hood but is meant as a more powerful GraphQL IDE enabling better (local) development workflows. Compared to GraphiQL, the GraphQL Playground ships with the following additional features:
@@ -120,16 +148,16 @@ interface ISettings {
 - `schema` [`IntrospectionResult`](optional) - The result of an introspection query (an object of this form: `{__schema: {...}}`) The playground automatically fetches the schema from the endpoint. This is only needed when you want to override the schema.
 - `tabs` [`Tab[]`](optional) - An array of tabs to inject. **Note: When using this feature, tabs will be resetted each time the page is reloaded**
 
 ```ts
 interface Tab {
-	endpoint: string
-	query: string
-	name?: string
-	variables?: string
-	responses?: string[]
-	headers?: { [key: string]: string }
+  endpoint: string
+  query: string
+  name?: string
+  variables?: string
+  responses?: string[]
+  headers?: { [key: string]: string }
 }
 ```
 
 In addition to this, the React app provides some more properties:
 
@@ -167,12 +195,12 @@ The GraphQL Playground requires **React 16**.
 
 Including Fonts (`1.`)
 
 ```html
 <link
-	href="https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700|Source+Code+Pro:400,700"
-	rel="stylesheet"
+  href="https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700|Source+Code+Pro:400,700"
+  rel="stylesheet"
 />
 ```
 
 Including stylesheet and the component (`2., 3.`)
 
@@ -181,14 +209,14 @@ import React from 'react'
 import ReactDOM from 'react-dom'
 import { Provider } from 'react-redux'
 import { Playground, store } from 'graphql-playground-react'
 
 ReactDOM.render(
-	<Provider store={store}>
-		<Playground endpoint="https://api.graph.cool/simple/v1/swapi" />
-	</Provider>,
-	document.body,
+  <Provider store={store}>
+    <Playground endpoint='https://api.graph.cool/simple/v1/swapi' />
+  </Provider>,
+  document.body,
 )
 ```
 
 ### As Server Middleware
 
@@ -230,22 +258,22 @@ yarn add graphql-playground-middleware-lambda
 import lambdaPlayground from 'graphql-playground-middleware-lambda'
 // or using require()
 // const lambdaPlayground = require('graphql-playground-middleware-lambda').default
 
 exports.graphqlHandler = function graphqlHandler(event, context, callback) {
-	function callbackFilter(error, output) {
-		// eslint-disable-next-line no-param-reassign
-		output.headers['Access-Control-Allow-Origin'] = '*'
-		callback(error, output)
-	}
-
-	const handler = graphqlLambda({ schema: myGraphQLSchema })
-	return handler(event, context, callbackFilter)
+  function callbackFilter(error, output) {
+    // eslint-disable-next-line no-param-reassign
+    output.headers['Access-Control-Allow-Origin'] = '*'
+    callback(error, output)
+  }
+
+  const handler = graphqlLambda({ schema: myGraphQLSchema })
+  return handler(event, context, callbackFilter)
 }
 
 exports.playgroundHandler = lambdaPlayground({
-	endpoint: '/dev/graphql',
+  endpoint: '/dev/graphql',
 })
 ```
 
 `serverless.yml`
 
@@ -265,10 +293,14 @@ functions:
           path: playground
           method: get
           cors: true
 ```
 
+#### Security Issue
+
+There is an [XSS Reflection Vulnerability](./SECURITY.md) when using these middlewares with unsanitized user input before
+
 ## Development
 
 ```sh
 $ cd packages/graphql-playground-react
 $ yarn
@@ -283,31 +315,31 @@ Open
 From `graphql-playground-react@1.7.0` on you can provide a `codeTheme` property to the React Component to customize your color theme.
 These are the available options:
 
 ```ts
 export interface EditorColours {
-	property: string
-	comment: string
-	punctuation: string
-	keyword: string
-	def: string
-	qualifier: string
-	attribute: string
-	number: string
-	string: string
-	builtin: string
-	string2: string
-	variable: string
-	meta: string
-	atom: string
-	ws: string
-	selection: string
-	cursorColor: string
-	editorBackground: string
-	resultBackground: string
-	leftDrawerBackground: string
-	rightDrawerBackground: string
+  property: string
+  comment: string
+  punctuation: string
+  keyword: string
+  def: string
+  qualifier: string
+  attribute: string
+  number: string
+  string: string
+  builtin: string
+  string2: string
+  variable: string
+  meta: string
+  atom: string
+  ws: string
+  selection: string
+  cursorColor: string
+  editorBackground: string
+  resultBackground: string
+  leftDrawerBackground: string
+  rightDrawerBackground: string
 }
 ```
 
 ### Versions
 
diff --git a/SECURITY.md b/SECURITY.md
new file mode 100644
index 0000000..381633e
--- /dev/null
+++ b/SECURITY.md
@@ -0,0 +1,132 @@
+# Known Vulnerabilities
+
+## XSS Reflection Vulnerability
+
+the origin of the vulnerability is in `renderPlaygroundPage`, found in `graphql-playground-html`
+
+### Impact
+
+When using
+
+- `renderPlaygroundPage()`,
+- `koaPlayground()`
+- `expressPlayground()`
+- `koaPlayground()`
+- `lambdaPlayground()`
+- any downstream dependents that use these functions
+
+without sanitization of user input, your application is vulnerable to an XSS Reflecton Attack. This is a serious vulnerability that could allow for exfiltration of data or user credentials, or to disrupt systems.
+
+### Impacted Packages
+
+**All versions of these packages are impacted until those specified below**, which are now safe for user defined input:
+
+- `graphql-playground-html`: **☔ safe** @ `1.6.20`
+- `graphql-playground-express` **☔ safe** @ `1.7.15`
+- `graphql-playground-koa` **☔ safe** @ `1.6.14`
+- `graphql-playground-hapi` **☔ safe** @ `1.6.12`
+- `graphql-playground-lambda` **☔ safe** @ `1.7.16`
+
+### Static input was always safe
+
+These examples are safe for _all versions_ **because input is static**
+
+with `express` and `renderPlaygroundPage`:
+
+```js
+app.get('/playground', (req) => {
+  res.html(
+    renderPlaygroundPage({
+      endpoint: `/our/graphql`,
+    }),
+  )
+  next()
+})
+```
+
+with `expressPlayground`:
+
+```js
+// params
+app.get('/playground', (req) =>
+  expressPlayground({
+    endpoint: `/our/graphql`,
+    settings: { 'editor.theme': req.query.darkMode ? 'dark' : 'light' },
+  }),
+)
+```
+
+with `koaPlayground`:
+
+```js
+const koa = require('koa')
+const koaRouter = require('koa-router')
+const koaPlayground = require('graphql-playground-middleware-koa')
+
+const app = new koa()
+const router = new koaRouter()
+
+router.all('/playground', koaPlayground({ endpoint: '/graphql' }))
+```
+
+### Vulnerable Examples
+
+Here are some examples where the vulnerability would be present before the patch, because of unfiltered user input
+
+```js
+const express = require('express')
+const expressPlayground = require('graphql-playground-middleware-express')
+  .default
+
+const app = express()
+
+app.use(express.json())
+
+// params
+app.get('/playground/:id', (req) =>
+  expressPlayground({
+    endpoint: `/our/graphql/${req.params.id}`,
+  }),
+)
+
+// params
+app.get('/playground', (req) =>
+  expressPlayground({
+    endpoint: `/our/graphql`,
+    // any settings that are unsanitized user input, not just `endpoint`
+    settings: { 'editor.fontFamily': req.query.font },
+  }),
+)
+```
+
+### Workaround
+
+To fix this issue without the update, you can sanitize however you want.
+
+We suggest using [`xss`](https://www.npmjs.com/package/xss) (what we use for our own fix)
+
+For example, with `graphql-playground-middleware-express`:
+
+```js
+const express = require('express')
+const { filterXSS } = require('xss')
+const expressPlayground = require('graphql-playground-middleware-express')
+  .default
+
+
+const app = express()
+
+const filter = (val) => filterXSS(val, {
+  whitelist: [],
+  stripIgnoreTag: true,
+  stripIgnoreTagBody: ['script']
+})
+
+// simple example
+app.get('/playground/:id', (req) =>
+  expressPlayground({ endpoint: `/graphql/${filter(req.params.id)}` })
+
+// advanced params
+app.get('/playground', (req) =>
+  expressPlayground(JSON.parse(filter(JSON.stringify(req.query))))
+```
diff --git a/packages/graphql-playground-html/README.md b/packages/graphql-playground-html/README.md
index 66d3d35..bd27fdd 100644
--- a/packages/graphql-playground-html/README.md
+++ b/packages/graphql-playground-html/README.md
@@ -1,6 +1,8 @@
 # graphql-playground-html
 
+> **SECURITY WARNING:** This package and all of it's dependendents had a severe XSS Reflection attack vulnerability until version `1.6.20` of this package. You must sanitize any and all user input values to `renderPlaygroundPage()` values. If you used static values in your middlewares, including ours, you were not vulnerable to the attack.
+
 This package is being used by the GraphQL Playground middlewares.
 
 For local development, you can `yarn link` this package, then use `yarn link graphql-playground-html` in the
 middleware you want to develop.
diff --git a/packages/graphql-playground-html/package.json b/packages/graphql-playground-html/package.json
index 4aae26c..0818d94 100644
--- a/packages/graphql-playground-html/package.json
+++ b/packages/graphql-playground-html/package.json
@@ -31,7 +31,9 @@
   },
   "typings": "dist/index.d.ts",
   "typescript": {
     "definition": "dist/index.d.ts"
   },
-  "dependencies": {}
+  "dependencies": {
+    "xss": "^1.0.6"
+  }
 }
diff --git a/packages/graphql-playground-html/src/render-playground-page.ts b/packages/graphql-playground-html/src/render-playground-page.ts
index db066ea..4137073 100644
--- a/packages/graphql-playground-html/src/render-playground-page.ts
+++ b/packages/graphql-playground-html/src/render-playground-page.ts
@@ -1,5 +1,7 @@
+import { filterXSS } from 'xss';
+
 import getLoadingMarkup from './get-loading-markup'
 
 export interface MiddlewareOptions {
   endpoint?: string
   subscriptionEndpoint?: string
@@ -70,56 +72,77 @@ export interface Tab {
   variables?: string
   responses?: string[]
   headers?: { [key: string]: string }
 }
 
+const filter = (val) => {
+  return filterXSS(val, {
+    // @ts-ignore
+    whiteList: [],
+    stripIgnoreTag: true,
+    stripIgnoreTagBody: ["script"]
+  })
+}
+
+
 const loading = getLoadingMarkup()
 
-const getCdnMarkup = ({ version, cdnUrl = '//cdn.jsdelivr.net/npm', faviconUrl }) => `
-    <link rel="stylesheet" href="${cdnUrl}/graphql-playground-react${
-  version ? `@${version}` : ''
-}/build/static/css/index.css" />
-    ${typeof faviconUrl === 'string' ? `<link rel="shortcut icon" href="${faviconUrl}" />` : ''}
-    ${faviconUrl === undefined ? `<link rel="shortcut icon" href="${cdnUrl}/graphql-playground-react${
-      version ? `@${version}` : ''
-    }/build/favicon.png" />` : ''}
-    <script src="${cdnUrl}/graphql-playground-react${
-  version ? `@${version}` : ''
-}/build/static/js/middleware.js"></script>
-`
+const getCdnMarkup = ({ version, cdnUrl = '//cdn.jsdelivr.net/npm', faviconUrl }) => {
+  const buildCDNUrl = (packageName: string, suffix: string) => filter(`${cdnUrl}/${packageName}/${version ? `@${version}/` : ''}${suffix}` || '')
+  return `
+    <link 
+      rel="stylesheet" 
+      href="${buildCDNUrl('graphql-playground-react', 'build/static/css/index.css')}"
+    />
+    ${typeof faviconUrl === 'string' ? `<link rel="shortcut icon" href="${filter(faviconUrl || '')}" />` : ''}
+    ${faviconUrl === undefined ? `<link rel="shortcut icon" href="${buildCDNUrl('graphql-playground-react', 'build/favicon.png')}" />` : ''}
+    <script 
+      src="${buildCDNUrl('graphql-playground-react', 'build/static/js/middleware.js')}"
+    ></script>
+`}
+
+
+const renderConfig = (config) => {
+  return filterXSS(`<div id="config">${JSON.stringify(config)}</div>`, {
+    whiteList: { div: ['id'] },
+  })
+}
 
 export function renderPlaygroundPage(options: RenderPageOptions) {
   const extendedOptions: any = {
     ...options,
     canSaveConfig: false,
   }
   // for compatibility
   if ((options as any).subscriptionsEndpoint) {
-    extendedOptions.subscriptionEndpoint = (options as any).subscriptionsEndpoint
+    extendedOptions.subscriptionEndpoint = filter((options as any).subscriptionsEndpoint || '')
   }
   if (options.config) {
     extendedOptions.configString = JSON.stringify(options.config, null, 2)
   }
   if (!extendedOptions.endpoint && !extendedOptions.configString) {
     /* tslint:disable-next-line */
     console.warn(
       `WARNING: You didn't provide an endpoint and don't have a .graphqlconfig. Make sure you have at least one of them.`,
     )
   }
+  else if (extendedOptions.endpoint) {
+    extendedOptions.endpoint = filter(extendedOptions.endpoint || '')
+  }
 
   return `
   <!DOCTYPE html>
   <html>
   <head>
     <meta charset=utf-8 />
     <meta name="viewport" content="user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, minimal-ui">
     <link href="https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700|Source+Code+Pro:400,700" rel="stylesheet">
     <title>${extendedOptions.title || 'GraphQL Playground'}</title>
     ${
-      extendedOptions.env === 'react' || extendedOptions.env === 'electron'
-        ? ''
-        : getCdnMarkup(extendedOptions)
+    extendedOptions.env === 'react' || extendedOptions.env === 'electron'
+      ? ''
+      : getCdnMarkup(extendedOptions)
     }
   </head>
   <body>
     <style type="text/css">
       html {
@@ -166,23 +189,27 @@ export function renderPlaygroundPage(options: RenderPageOptions) {
           transform: translateY(0);
         }
       }
     </style>
     ${loading.container}
+    ${renderConfig(extendedOptions)}
     <div id="root" />
     <script type="text/javascript">
       window.addEventListener('load', function (event) {
         ${loading.script}
   
         const root = document.getElementById('root');
         root.classList.add('playgroundIn');
-  
-        GraphQLPlayground.init(root, ${JSON.stringify(
-          extendedOptions,
-          null,
-          2,
-        )})
+        const configText = document.getElementById('config').innerText
+        if(configText && configText.length) {
+          try {
+            GraphQLPlayground.init(root, JSON.parse(configText))
+          }
+          catch(err) {
+            console.error("could not find config")
+          }
+        }
       })
     </script>
   </body>
   </html>
 `
diff --git a/packages/graphql-playground-middleware-express/README.md b/packages/graphql-playground-middleware-express/README.md
index bd6cbba..addc069 100644
--- a/packages/graphql-playground-middleware-express/README.md
+++ b/packages/graphql-playground-middleware-express/README.md
@@ -1,8 +1,9 @@
 # graphql-playground-middleware-express
 
 > Express middleware to expose an endpoint for the GraphQL Playground IDE
+> **SECURITY NOTE**: All versions of `graphql-playground-express` until `1.7.15` or later have a security vulnerability when unsanitized user input is used while invoking `expressPlayground()`. [Read more below](#security-notes)
 
 ## Installation
 
 Using yarn:
 
@@ -27,5 +28,19 @@ const expressPlayground = require('graphql-playground-middleware-express')
 
 const app = express()
 
 app.get('/playground', expressPlayground({ endpoint: '/graphql' }))
 ```
+
+## Security Notes
+
+All versions before `1.7.15` were vulnerable to user-defined input to `expressPlayground()`. Read more in [the security notes](https://github.com/prisma/graphql-playground/tree/master/SECURITY.md)
+
+### Security Upgrade Steps
+
+To fix the issue, you can upgrade to `1.6.12` or later. If you aren't able to upgrade, see the security notes for a workaround.
+
+**yarn:**
+`yarn add graphql-playground-express@^1.7.15`
+
+**npm:**
+`npm install --save graphql-playground-express@^1.7.15`
diff --git a/packages/graphql-playground-middleware-express/examples/basic/index.js b/packages/graphql-playground-middleware-express/examples/basic/index.js
index c39209e..ac3c89d 100644
--- a/packages/graphql-playground-middleware-express/examples/basic/index.js
+++ b/packages/graphql-playground-middleware-express/examples/basic/index.js
@@ -1,30 +1,35 @@
-const express = require("express");
-const { ApolloServer, gql } = require("apollo-server-express");
-const expressPlayground = require("../../dist/index").default;
+const express = require('express')
+const { ApolloServer, gql } = require('apollo-server-express')
+const expressPlayground = require('../../dist/index').default
 
 const typeDefs = gql`
   type Query {
     hello: String!
   }
   schema {
     query: Query
   }
-`;
+`
 const resolvers = {
   Query: {
-    hello: () => "world"
-  }
-};
+    hello: () => 'world',
+  },
+}
 
-const PORT = 4000;
+const PORT = 4000
 
-const server = new ApolloServer({ typeDefs, resolvers });
-const app = express();
-server.applyMiddleware({ app });
+const server = new ApolloServer({ typeDefs, resolvers })
+const app = express()
+server.applyMiddleware({ app })
 
-app.get("/playground", expressPlayground({ endpoint: "/graphql" }));
-app.listen(PORT);
+app.get(
+  '/playground',
+  expressPlayground({
+    endpoint: '/graphql/</script><script>alert(1)</script><script>',
+  }),
+)
+app.listen(PORT)
 
 console.log(
-  `Serving the GraphQL Playground on http://localhost:${PORT}/playground`
-);
+  `Serving the GraphQL Playground on http://localhost:${PORT}/playground`,
+)
diff --git a/packages/graphql-playground-middleware-hapi/README.md b/packages/graphql-playground-middleware-hapi/README.md
new file mode 100644
index 0000000..328b439
--- /dev/null
+++ b/packages/graphql-playground-middleware-hapi/README.md
@@ -0,0 +1,57 @@
+# graphql-playground-middleware-hapi
+
+> Koa middleware to expose an endpoint for the GraphQL Playground IDE
+> **SECURITY NOTE**: All versions of `graphql-playground-middleware-hapi` until `1.6.12` or later have a security vulnerability when unsanitized user input is used while invoking `hapiPlayground()`. [Read more below](#security-notes)
+
+## Installation
+
+Using yarn:
+
+```console
+yarn add graphql-playground-middleware-hapi
+```
+
+Or npm:
+
+```console
+npm install graphql-playground-middleware-hapi --save
+```
+
+## Usage
+
+See full example in [examples/basic](https://github.com/prisma/graphql-playground/tree/master/packages/graphql-playground-middleware-hapi/examples/basic).
+
+minimal example:
+
+```js
+const hapiPlayground = require('graphql-playground-middleware-hapi').default
+
+const playground = {
+  plugin: hapiPlayground,
+  options: {
+    path: '/playground',
+    endpoint: '/graphql',
+  },
+}
+
+const app = new Hapi.server({
+  port: 3000,
+})
+
+app.register(playground)
+;(async () => await app.start())()
+```
+
+## Security Notes
+
+All versions before `1.6.12` were vulnerable to user-defined input to `hapiPlayground()`. Read more in [the security notes](https://github.com/prisma/graphql-playground/tree/master/SECURITY.md)
+
+### Security Upgrade Steps
+
+To fix the issue, you can upgrade to `1.6.12` or later. If you aren't able to upgrade, see the security notes for a workaround.
+
+**yarn:**
+`yarn add graphql-playground-middleware-hapi@^1.6.12`
+
+**npm:**
+`npm install --save graphql-playground-middleware-hapi@^1.6.12`
diff --git a/packages/graphql-playground-middleware-koa/README.md b/packages/graphql-playground-middleware-koa/README.md
index bd43dcb..236d7fa 100644
--- a/packages/graphql-playground-middleware-koa/README.md
+++ b/packages/graphql-playground-middleware-koa/README.md
@@ -1,7 +1,9 @@
 # graphql-playground-middleware-koa
+
 > Koa middleware to expose an endpoint for the GraphQL Playground IDE
+> **SECURITY NOTE**: All versions of `graphql-playground-koa` until `1.6.14` or later have a security vulnerability when unsanitized user input is used while invoking `koaPlayground()`. [Read more below](#security-notes)
 
 ## Installation
 
 Using yarn:
 
@@ -27,5 +29,19 @@ const koaPlayground = require('graphql-playground-middleware-koa')
 const app = new koa()
 const router = new koaRouter()
 
 router.all('/playground', koaPlayground({ endpoint: '/graphql' }))
 ```
+
+## Security Notes
+
+All versions before `1.6.14` were vulnerable to user-defined input to `koaPlayground()`. Read more in [the security notes](https://github.com/prisma/graphql-playground/tree/master/SECURITY.md)
+
+### Security Upgrade Steps
+
+To fix the issue, you can upgrade to `1.6.14` or later. If you aren't able to upgrade, see the security notes for a workaround.
+
+**yarn:**
+`yarn add graphql-playground-koa@^1.6.14`
+
+**npm:**
+`npm install --save graphql-playground-koa@^1.6.14`
diff --git a/packages/graphql-playground-middleware-lambda/README.md b/packages/graphql-playground-middleware-lambda/README.md
new file mode 100644
index 0000000..b4f24a1
--- /dev/null
+++ b/packages/graphql-playground-middleware-lambda/README.md
@@ -0,0 +1,46 @@
+# graphql-playground-middleware-lambda
+
+> Koa middleware to expose an endpoint for the GraphQL Playground IDE
+> **SECURITY NOTE**: All versions of `graphql-playground-middleware-lambda` until `1.7.16` or later have a security vulnerability when unsanitized user input is used while invoking `lambdaPlayground()`. [Read more below](#security-notes)
+
+## Installation
+
+Using yarn:
+
+```console
+yarn add graphql-playground-middleware-lambda
+```
+
+Or npm:
+
+```console
+npm install graphql-playground-middleware-lambda --save
+```
+
+## Usage
+
+See full example in [examples/basic](https://github.com/prisma/graphql-playground/tree/master/packages/graphql-playground-middleware-lambda/examples/basic).
+
+minimal example:
+
+```js
+const lambdaPlayground = require('graphql-playground-middleware-lambda').default
+
+exports.handler = lambdaPlayground({
+  endpoint: '/dev',
+})
+```
+
+## Security Notes
+
+All versions before `1.7.16` were vulnerable to user-defined input to `lambdaPlayground()`. Read more in [the security notes](https://github.com/prisma/graphql-playground/tree/SECURITY.md)
+
+### Security Upgrade Steps
+
+To fix the issue, you can upgrade to `1.7.16`. If you aren't able to upgrade, see the security notes for a workaround.
+
+**yarn:**
+`yarn add graphql-playground-middleware-lambda@^1.7.16`
+
+**npm:**
+`npm install --save graphql-playground-middleware-lambda@^1.7.16`
diff --git a/packages/graphql-playground-middleware-lambda/examples/basic/README.md b/packages/graphql-playground-middleware-lambda/examples/basic/README.md
index 0457bba..eeca0f3 100644
--- a/packages/graphql-playground-middleware-lambda/examples/basic/README.md
+++ b/packages/graphql-playground-middleware-lambda/examples/basic/README.md
@@ -1,11 +1,16 @@
 # graphql playground serverless example
 
 ## Deploy
+
 ```
 $ sls deploy
 ```
 
 ## Hosted Example
+
 This example is also hosted here:
 https://1rp2h4rth8.execute-api.us-east-1.amazonaws.com/dev/playground
 
+exports.playgroundHandler = lambdaPlayground({
+endpoint: '/dev',
+})
diff --git a/packages/graphql-playground-react/README.md b/packages/graphql-playground-react/README.md
index 1b5781f..12d6cf9 100644
--- a/packages/graphql-playground-react/README.md
+++ b/packages/graphql-playground-react/README.md
@@ -71,22 +71,25 @@ There are **3 dependencies** needed in order to run the `graphql-playground` Rea
 The GraphQL Playground requires **React 16**.
 
 Including Fonts (`1.`)
 
 ```html
-<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700|Source+Code+Pro:400,700" rel="stylesheet">
+<link
+  href="https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700|Source+Code+Pro:400,700"
+  rel="stylesheet"
+/>
 ```
 
 Including stylesheet and the component (`2., 3.`)
 
 ```js
 import React from 'react'
 import ReactDOM from 'react-dom'
 import Playground from 'graphql-playground'
 
 ReactDOM.render(
-  <Playground endpoint="https://api.graph.cool/simple/v1/swapi" />,
+  <Playground endpoint='https://api.graph.cool/simple/v1/swapi' />,
   document.body,
 )
 ```
 
 ### As Server Middleware
@@ -151,21 +154,21 @@ exports.playgroundHandler = lambdaPlayground({
 ```yaml
 functions:
   graphql:
     handler: handler.graphqlHandler
     events:
-    - http:
-        path: graphql
-        method: post
-        cors: true
+      - http:
+          path: graphql
+          method: post
+          cors: true
   playground:
     handler: handler.playgroundHandler
     events:
-    - http:
-        path: playground
-        method: get
-        cors: true
+      - http:
+          path: playground
+          method: get
+          cors: true
 ```
 
 ## Development [![npm version](https://badge.fury.io/js/graphql-playground-react.svg)](https://badge.fury.io/js/graphql-playground-react)
 
 This is a mono-repo setup containing packages for the `graphql-playground` and `graphql-playground-electron`.
diff --git a/scripts/build.sh b/scripts/build.sh
index 3ac6621..2d2c773 100755
--- a/scripts/build.sh
+++ b/scripts/build.sh
@@ -3,12 +3,12 @@
 set -e
 
 cd packages
 
 packages=(
-  graphql-playground-react
   graphql-playground-html
+  graphql-playground-react
   # graphql-playground-electron
   graphql-playground-middleware-express
   graphql-playground-middleware-hapi
   graphql-playground-middleware-koa
   graphql-playground-middleware-lambda
diff --git a/yarn.lock b/yarn.lock
index 25a5b1f..e511ec9 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -4599,10 +4599,15 @@ css-what@2.1:
 cssesc@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
   integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==
 
+cssfilter@0.0.10:
+  version "0.0.10"
+  resolved "https://registry.yarnpkg.com/cssfilter/-/cssfilter-0.0.10.tgz#c6d2672632a2e5c83e013e6864a42ce8defd20ae"
+  integrity sha1-xtJnJjKi5cg+AT5oZKQs6N79IK4=
+
 cssnano@^3.10.0:
   version "3.10.0"
   resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-3.10.0.tgz#4f38f6cea2b9b17fa01490f23f1dc68ea65c1c38"
   integrity sha1-Tzj2zqK5sX+gFJDyPx3GjqZcHDg=
   dependencies:
@@ -15126,10 +15131,18 @@ xmldom@0.1.x:
 xregexp@4.0.0:
   version "4.0.0"
   resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-4.0.0.tgz#e698189de49dd2a18cc5687b05e17c8e43943020"
   integrity sha512-PHyM+sQouu7xspQQwELlGwwd05mXUFqwFYfqPO0cC7x4fxyHnnuetmQr6CjJiafIDoH4MogHb9dOoJzR/Y4rFg==
 
+xss@^1.0.6:
+  version "1.0.6"
+  resolved "https://registry.yarnpkg.com/xss/-/xss-1.0.6.tgz#eaf11e9fc476e3ae289944a1009efddd8a124b51"
+  integrity sha512-6Q9TPBeNyoTRxgZFk5Ggaepk/4vUOYdOsIUYvLehcsIZTFjaavbVnsuAkLA5lIFuug5hw8zxcB9tm01gsjph2A==
+  dependencies:
+    commander "^2.9.0"
+    cssfilter "0.0.10"
+
 xtend@^4.0.0, xtend@~4.0.1:
   version "4.0.2"
   resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
   integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
 

Vulnerable code: [![npm version](https://badge.fury.io/js/graphql-playground-react.svg)](https://badge.fury.io/js/graphql-playground-react) 
	endpoint: string
	query: string
	name?: string
	variables?: string
	responses?: string[]
	headers?: { [key: string]: string }
	href="https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700|Source+Code+Pro:400,700"
	rel="stylesheet"
	<Provider store={store}>
		<Playground endpoint="https://api.graph.cool/simple/v1/swapi" />
	</Provider>,
	document.body,
	function callbackFilter(error, output) {
		// eslint-disable-next-line no-param-reassign
		output.headers['Access-Control-Allow-Origin'] = '*'
		callback(error, output)
	}

	const handler = graphqlLambda({ schema: myGraphQLSchema })
	return handler(event, context, callbackFilter)
	endpoint: '/dev/graphql',
	property: string
	comment: string
	punctuation: string
	keyword: string
	def: string
	qualifier: string
	attribute: string
	number: string
	string: string
	builtin: string
	string2: string
	variable: string
	meta: string
	atom: string
	ws: string
	selection: string
	cursorColor: string
	editorBackground: string
	resultBackground: string
	leftDrawerBackground: string
	rightDrawerBackground: string
  "dependencies": {}
const getCdnMarkup = ({ version, cdnUrl = '//cdn.jsdelivr.net/npm', faviconUrl }) => `
    <link rel="stylesheet" href="${cdnUrl}/graphql-playground-react${
  version ? `@${version}` : ''
}/build/static/css/index.css" />
    ${typeof faviconUrl === 'string' ? `<link rel="shortcut icon" href="${faviconUrl}" />` : ''}
    ${faviconUrl === undefined ? `<link rel="shortcut icon" href="${cdnUrl}/graphql-playground-react${
      version ? `@${version}` : ''
    }/build/favicon.png" />` : ''}
    <script src="${cdnUrl}/graphql-playground-react${
  version ? `@${version}` : ''
}/build/static/js/middleware.js"></script>
`
    extendedOptions.subscriptionEndpoint = (options as any).subscriptionsEndpoint
      extendedOptions.env === 'react' || extendedOptions.env === 'electron'
        ? ''
        : getCdnMarkup(extendedOptions)
  
        GraphQLPlayground.init(root, ${JSON.stringify(
          extendedOptions,
          null,
          2,
        )})
const express = require("express");
const { ApolloServer, gql } = require("apollo-server-express");
const expressPlayground = require("../../dist/index").default;
`;
    hello: () => "world"
  }
};
const PORT = 4000;
const server = new ApolloServer({ typeDefs, resolvers });
const app = express();
server.applyMiddleware({ app });
app.get("/playground", expressPlayground({ endpoint: "/graphql" }));
app.listen(PORT);
  `Serving the GraphQL Playground on http://localhost:${PORT}/playground`
);
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700|Source+Code+Pro:400,700" rel="stylesheet">
  <Playground endpoint="https://api.graph.cool/simple/v1/swapi" />,
    - http:
        path: graphql
        method: post
        cors: true
    - http:
        path: playground
        method: get
        cors: true
  graphql-playground-react
Fixed code: > **SECURITY WARNING:** This `graphql-playground-html` and [all of it's middleware dependents](#impacted-packages) in this repository **had a severe XSS Reflection attack vulnerability to unsanitized user input** until version `graphql-playground-html@1.6.20`. Impacted are any and all **user-defined** input to `renderPlaygroundPage()`, `koaPlayground()`,`expressPlayground()`, `koaPlayground()`, or `lambdaPlayground()`. If you used static values, such as `graphql-playground-electron` does in [it's webpack config](https://github.com/prisma-labs/graphql-playground/blob/master/packages/graphql-playground-electron/webpack.config.build.js#L16), you were not vulnerable to the attack. [More Details](./SECURITY.md)

[![npm version](https://badge.fury.io/js/graphql-playground-react.svg)](https://badge.fury.io/js/graphql-playground-react)
## Security Details

**NOTE: only _unsanitized user input_ to the functions in these packages is vulnerable** to the recently reported XSS Reflection attack.

### Impact

The only reason this vulnerability exists is because we are using template strings in `renderPlaygroundPage()` with potentially user defined variables. This allows an attacker to inject html and javascript into a page on execution.

Common examples may be user-defined path parameters, query string, unsanitized UI provided values in database, etc that are used to build template strings or passed directly to a `renderPlaygroundPage()` or the matching middleware function equivalent.

### Impacted Packages

**All versions of these packages are impacted until the ones specified below**, which are now safe for user defined input:

- `graphql-playground-html`: **☔ safe** @ `1.6.20`
- `graphql-playground-express` **☔ safe** @ `1.7.15`
- `graphql-playground-koa` **☔ safe** @ `1.6.14`
- `graphql-playground-hapi` **☔ safe** @ `1.6.12`
- `graphql-playground-lambda` **☔ safe** @ `1.7.16`
- `graphql-playground-electron` has always been **☔ safe** from XSS attacks! This is because configuration is statically defined [it's webpack config](https://github.com/prisma-labs/graphql-playground/blob/master/packages/graphql-playground-electron/webpack.config.build.js#L16)
- `graphql-playground-react` is safe because it does not use `renderPlaygroundPage()` anywhere, and thus is not susceptible to template string XSS reflection attacks.

### More Information

See the [security docs](./SECURITY.md) for more details on how your implementation might be impacted by this vulnerability. It contains safe examples, unsafe examples, workarounds, and more details.

  endpoint: string
  query: string
  name?: string
  variables?: string
  responses?: string[]
  headers?: { [key: string]: string }
  href="https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700|Source+Code+Pro:400,700"
  rel="stylesheet"
  <Provider store={store}>
    <Playground endpoint='https://api.graph.cool/simple/v1/swapi' />
  </Provider>,
  document.body,
  function callbackFilter(error, output) {
    // eslint-disable-next-line no-param-reassign
    output.headers['Access-Control-Allow-Origin'] = '*'
    callback(error, output)
  }

  const handler = graphqlLambda({ schema: myGraphQLSchema })
  return handler(event, context, callbackFilter)
  endpoint: '/dev/graphql',
#### Security Issue

There is an [XSS Reflection Vulnerability](./SECURITY.md) when using these middlewares with unsanitized user input before

  property: string
  comment: string
  punctuation: string
  keyword: string
  def: string
  qualifier: string
  attribute: string
  number: string
  string: string
  builtin: string
  string2: string
  variable: string
  meta: string
  atom: string
  ws: string
  selection: string
  cursorColor: string
  editorBackground: string
  resultBackground: string
  leftDrawerBackground: string
  rightDrawerBackground: string
# Known Vulnerabilities

## XSS Reflection Vulnerability

the origin of the vulnerability is in `renderPlaygroundPage`, found in `graphql-playground-html`

### Impact

When using

- `renderPlaygroundPage()`,
- `koaPlayground()`
- `expressPlayground()`
- `koaPlayground()`
- `lambdaPlayground()`
- any downstream dependents that use these functions

without sanitization of user input, your application is vulnerable to an XSS Reflecton Attack. This is a serious vulnerability that could allow for exfiltration of data or user credentials, or to disrupt systems.

### Impacted Packages

**All versions of these packages are impacted until those specified below**, which are now safe for user defined input:

- `graphql-playground-html`: **☔ safe** @ `1.6.20`
- `graphql-playground-express` **☔ safe** @ `1.7.15`
- `graphql-playground-koa` **☔ safe** @ `1.6.14`
- `graphql-playground-hapi` **☔ safe** @ `1.6.12`
- `graphql-playground-lambda` **☔ safe** @ `1.7.16`

### Static input was always safe

These examples are safe for _all versions_ **because input is static**

with `express` and `renderPlaygroundPage`:

```js
app.get('/playground', (req) => {
  res.html(
    renderPlaygroundPage({
      endpoint: `/our/graphql`,
    }),
  )
  next()
})
```

with `expressPlayground`:

```js
// params
app.get('/playground', (req) =>
  expressPlayground({
    endpoint: `/our/graphql`,
    settings: { 'editor.theme': req.query.darkMode ? 'dark' : 'light' },
  }),
)
```

with `koaPlayground`:

```js
const koa = require('koa')
const koaRouter = require('koa-router')
const koaPlayground = require('graphql-playground-middleware-koa')

const app = new koa()
const router = new koaRouter()

router.all('/playground', koaPlayground({ endpoint: '/graphql' }))
```

### Vulnerable Examples

Here are some examples where the vulnerability would be present before the patch, because of unfiltered user input

```js
const express = require('express')
const expressPlayground = require('graphql-playground-middleware-express')
  .default

const app = express()

app.use(express.json())

// params
app.get('/playground/:id', (req) =>
  expressPlayground({
    endpoint: `/our/graphql/${req.params.id}`,
  }),
)

// params
app.get('/playground', (req) =>
  expressPlayground({
    endpoint: `/our/graphql`,
    // any settings that are unsanitized user input, not just `endpoint`
    settings: { 'editor.fontFamily': req.query.font },
  }),
)
```

### Workaround

To fix this issue without the update, you can sanitize however you want.

We suggest using [`xss`](https://www.npmjs.com/package/xss) (what we use for our own fix)

For example, with `graphql-playground-middleware-express`:

```js
const express = require('express')
const { filterXSS } = require('xss')
const expressPlayground = require('graphql-playground-middleware-express')
  .default


const app = express()

const filter = (val) => filterXSS(val, {
  whitelist: [],
  stripIgnoreTag: true,
  stripIgnoreTagBody: ['script']
})

// simple example
app.get('/playground/:id', (req) =>
  expressPlayground({ endpoint: `/graphql/${filter(req.params.id)}` })

// advanced params
app.get('/playground', (req) =>
  expressPlayground(JSON.parse(filter(JSON.stringify(req.query))))
```
> **SECURITY WARNING:** This package and all of it's dependendents had a severe XSS Reflection attack vulnerability until version `1.6.20` of this package. You must sanitize any and all user input values to `renderPlaygroundPage()` values. If you used static values in your middlewares, including ours, you were not vulnerable to the attack.

  "dependencies": {
    "xss": "^1.0.6"
  }
import { filterXSS } from 'xss';

const filter = (val) => {
  return filterXSS(val, {
    // @ts-ignore
    whiteList: [],
    stripIgnoreTag: true,
    stripIgnoreTagBody: ["script"]
  })
}


const getCdnMarkup = ({ version, cdnUrl = '//cdn.jsdelivr.net/npm', faviconUrl }) => {
  const buildCDNUrl = (packageName: string, suffix: string) => filter(`${cdnUrl}/${packageName}/${version ? `@${version}/` : ''}${suffix}` || '')
  return `
    <link 
      rel="stylesheet" 
      href="${buildCDNUrl('graphql-playground-react', 'build/static/css/index.css')}"
    />
    ${typeof faviconUrl === 'string' ? `<link rel="shortcut icon" href="${filter(faviconUrl || '')}" />` : ''}
    ${faviconUrl === undefined ? `<link rel="shortcut icon" href="${buildCDNUrl('graphql-playground-react', 'build/favicon.png')}" />` : ''}
    <script 
      src="${buildCDNUrl('graphql-playground-react', 'build/static/js/middleware.js')}"
    ></script>
`}


const renderConfig = (config) => {
  return filterXSS(`<div id="config">${JSON.stringify(config)}</div>`, {
    whiteList: { div: ['id'] },
  })
}
    extendedOptions.subscriptionEndpoint = filter((options as any).subscriptionsEndpoint || '')
  else if (extendedOptions.endpoint) {
    extendedOptions.endpoint = filter(extendedOptions.endpoint || '')
  }
    extendedOptions.env === 'react' || extendedOptions.env === 'electron'
      ? ''
      : getCdnMarkup(extendedOptions)
    ${renderConfig(extendedOptions)}
        const configText = document.getElementById('config').innerText
        if(configText && configText.length) {
          try {
            GraphQLPlayground.init(root, JSON.parse(configText))
          }
          catch(err) {
            console.error("could not find config")
          }
        }
> **SECURITY NOTE**: All versions of `graphql-playground-express` until `1.7.15` or later have a security vulnerability when unsanitized user input is used while invoking `expressPlayground()`. [Read more below](#security-notes)

## Security Notes

All versions before `1.7.15` were vulnerable to user-defined input to `expressPlayground()`. Read more in [the security notes](https://github.com/prisma/graphql-playground/tree/master/SECURITY.md)

### Security Upgrade Steps

To fix the issue, you can upgrade to `1.6.12` or later. If you aren't able to upgrade, see the security notes for a workaround.

**yarn:**
`yarn add graphql-playground-express@^1.7.15`

**npm:**
`npm install --save graphql-playground-express@^1.7.15`
const express = require('express')
const { ApolloServer, gql } = require('apollo-server-express')
const expressPlayground = require('../../dist/index').default
`
    hello: () => 'world',
  },
}
const PORT = 4000
const server = new ApolloServer({ typeDefs, resolvers })
const app = express()
server.applyMiddleware({ app })
app.get(
  '/playground',
  expressPlayground({
    endpoint: '/graphql/</script><script>alert(1)</script><script>',
  }),
)
app.listen(PORT)
  `Serving the GraphQL Playground on http://localhost:${PORT}/playground`,
)
# graphql-playground-middleware-hapi

> Koa middleware to expose an endpoint for the GraphQL Playground IDE
> **SECURITY NOTE**: All versions of `graphql-playground-middleware-hapi` until `1.6.12` or later have a security vulnerability when unsanitized user input is used while invoking `hapiPlayground()`. [Read more below](#security-notes)

## Installation

Using yarn:

```console
yarn add graphql-playground-middleware-hapi
```

Or npm:

```console
npm install graphql-playground-middleware-hapi --save
```

## Usage

See full example in [examples/basic](https://github.com/prisma/graphql-playground/tree/master/packages/graphql-playground-middleware-hapi/examples/basic).

minimal example:

```js
const hapiPlayground = require('graphql-playground-middleware-hapi').default

const playground = {
  plugin: hapiPlayground,
  options: {
    path: '/playground',
    endpoint: '/graphql',
  },
}

const app = new Hapi.server({
  port: 3000,
})

app.register(playground)
;(async () => await app.start())()
```

## Security Notes

All versions before `1.6.12` were vulnerable to user-defined input to `hapiPlayground()`. Read more in [the security notes](https://github.com/prisma/graphql-playground/tree/master/SECURITY.md)

### Security Upgrade Steps

To fix the issue, you can upgrade to `1.6.12` or later. If you aren't able to upgrade, see the security notes for a workaround.

**yarn:**
`yarn add graphql-playground-middleware-hapi@^1.6.12`

**npm:**
`npm install --save graphql-playground-middleware-hapi@^1.6.12`

> **SECURITY NOTE**: All versions of `graphql-playground-koa` until `1.6.14` or later have a security vulnerability when unsanitized user input is used while invoking `koaPlayground()`. [Read more below](#security-notes)

## Security Notes

All versions before `1.6.14` were vulnerable to user-defined input to `koaPlayground()`. Read more in [the security notes](https://github.com/prisma/graphql-playground/tree/master/SECURITY.md)

### Security Upgrade Steps

To fix the issue, you can upgrade to `1.6.14` or later. If you aren't able to upgrade, see the security notes for a workaround.

**yarn:**
`yarn add graphql-playground-koa@^1.6.14`

**npm:**
`npm install --save graphql-playground-koa@^1.6.14`
# graphql-playground-middleware-lambda

> Koa middleware to expose an endpoint for the GraphQL Playground IDE
> **SECURITY NOTE**: All versions of `graphql-playground-middleware-lambda` until `1.7.16` or later have a security vulnerability when unsanitized user input is used while invoking `lambdaPlayground()`. [Read more below](#security-notes)

## Installation

Using yarn:

```console
yarn add graphql-playground-middleware-lambda
```

Or npm:

```console
npm install graphql-playground-middleware-lambda --save
```

## Usage

See full example in [examples/basic](https://github.com/prisma/graphql-playground/tree/master/packages/graphql-playground-middleware-lambda/examples/basic).

minimal example:

```js
const lambdaPlayground = require('graphql-playground-middleware-lambda').default

exports.handler = lambdaPlayground({
  endpoint: '/dev',
})
```

## Security Notes

All versions before `1.7.16` were vulnerable to user-defined input to `lambdaPlayground()`. Read more in [the security notes](https://github.com/prisma/graphql-playground/tree/SECURITY.md)

### Security Upgrade Steps

To fix the issue, you can upgrade to `1.7.16`. If you aren't able to upgrade, see the security notes for a workaround.

**yarn:**
`yarn add graphql-playground-middleware-lambda@^1.7.16`

**npm:**
`npm install --save graphql-playground-middleware-lambda@^1.7.16`


exports.playgroundHandler = lambdaPlayground({
endpoint: '/dev',
})
<link
  href="https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700|Source+Code+Pro:400,700"
  rel="stylesheet"
/>
  <Playground endpoint='https://api.graph.cool/simple/v1/swapi' />,
      - http:
          path: graphql
          method: post
          cors: true
      - http:
          path: playground
          method: get
          cors: true
  graphql-playground-react
cssfilter@0.0.10:
  version "0.0.10"
  resolved "https://registry.yarnpkg.com/cssfilter/-/cssfilter-0.0.10.tgz#c6d2672632a2e5c83e013e6864a42ce8defd20ae"
  integrity sha1-xtJnJjKi5cg+AT5oZKQs6N79IK4=

xss@^1.0.6:
  version "1.0.6"
  resolved "https://registry.yarnpkg.com/xss/-/xss-1.0.6.tgz#eaf11e9fc476e3ae289944a1009efddd8a124b51"
  integrity sha512-6Q9TPBeNyoTRxgZFk5Ggaepk/4vUOYdOsIUYvLehcsIZTFjaavbVnsuAkLA5lIFuug5hw8zxcB9tm01gsjph2A==
  dependencies:
    commander "^2.9.0"
    cssfilter "0.0.10"