Skip to content

Commit

Permalink
fix(gatsby-plugin-mdx): don't allow JS frontmatter by default (#35830) (
Browse files Browse the repository at this point in the history
#35832)

Co-authored-by: Ty Hopp <hopp.ty.c@gmail.com>
Co-authored-by: Michal Piechowiak <misiek.piechowiak@gmail.com>
  • Loading branch information
3 people committed Jun 2, 2022
1 parent ab3131a commit e916cf8
Show file tree
Hide file tree
Showing 29 changed files with 354 additions and 24 deletions.
1 change: 1 addition & 0 deletions e2e-tests/mdx-less-babel/.gitignore
Expand Up @@ -9,3 +9,4 @@ yarn-error.log

# Cypress output
cypress/videos/
cypress/screenshots/
@@ -0,0 +1 @@
Nothing here, do not remove
29 changes: 29 additions & 0 deletions e2e-tests/mdx-less-babel/cypress/integration/js-frontmatter.js
@@ -0,0 +1,29 @@
describe(`webpack loader`, () => {
it(`---js frontmatter should not parse by default`, () => {
cy.visit(`/js-frontmatter`).waitForRouteChange()

// Check frontmatter not parsed in page context
cy.get(`[data-cy="js-frontmatter"]`).invoke(`text`).should(`eq`, `disabled`)
})

it(`---javascript frontmatter should not parse by default`, () => {
cy.visit(`/javascript-frontmatter`).waitForRouteChange()

// Check frontmatter not parsed in page context
cy.get(`[data-cy="js-frontmatter"]`).invoke(`text`).should(`eq`, `disabled`)
})
})

describe(`data layer`, () => {
it(`---js or ---javascript frontmatter should not parse by default`, () => {
cy.visit(`/mdx-query-js-frontmatter/`).waitForRouteChange()
cy.contains(`I should not be parsed`).should("not.exist")
})
})

it(`---js and ---javascript frontmatter should not allow remote code execution`, () => {
cy.readFile(`cypress/fixtures/file-to-attempt-rce-on.txt`).should(
`eq`,
`Nothing here, do not remove`
)
})
12 changes: 12 additions & 0 deletions e2e-tests/mdx-less-babel/gatsby-node.js
@@ -0,0 +1,12 @@
exports.createSchemaCustomization = ({ actions }) => {
const { createTypes } = actions

createTypes(`
type Mdx implements Node {
frontmatter: Frontmatter
}
type Frontmatter {
title: String
}
`)
}
15 changes: 8 additions & 7 deletions e2e-tests/mdx-less-babel/package.json
Expand Up @@ -6,9 +6,9 @@
"@mdx-js/mdx": "^1.6.6",
"@mdx-js/react": "^1.6.6",
"cypress": "^3.1.0",
"gatsby": "^2.0.118",
"gatsby-plugin-mdx": "^1.2.19",
"gatsby-source-filesystem": "^2.3.14",
"gatsby": "next",
"gatsby-plugin-mdx": "next",
"gatsby-source-filesystem": "next",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"theme-ui": "^0.3.1"
Expand All @@ -18,10 +18,11 @@
],
"license": "MIT",
"scripts": {
"build": "gatsby build",
"develop": "gatsby develop",
"clean": "gatsby clean",
"build": "cross-env CYPRESS_SUPPORT=y gatsby build",
"develop": "cross-env CYPRESS_SUPPORT=y gatsby develop",
"format": "prettier --write '**/*.js'",
"test": "cross-env CYPRESS_SUPPORT=y npm run build && npm run start-server-and-test",
"test": "npm run build && npm run start-server-and-test",
"start-server-and-test": "start-server-and-test serve http://localhost:9000 cy:run",
"serve": "gatsby serve",
"cy:open": "cypress open",
Expand All @@ -34,4 +35,4 @@
"prettier": "2.0.4",
"start-server-and-test": "^1.7.1"
}
}
}
16 changes: 16 additions & 0 deletions e2e-tests/mdx-less-babel/src/pages/javascript-frontmatter.mdx
@@ -0,0 +1,16 @@
---javascript
(() => {
require(`fs`).writeFileSync(`${process.cwd()}/cypress/fixtures/file-to-attempt-rce-on.txt`, (new Error('Helpful stack trace if this does execute. It should not execute.')).stack)
console.trace()
return {
title: `I should not be parsed`
}
})()

---

<h1>JS frontmatter engine is disabled by default</h1>

<span data-cy="js-frontmatter">
{props.pageContext.frontmatter?.title || `disabled`}
</span>
16 changes: 16 additions & 0 deletions e2e-tests/mdx-less-babel/src/pages/js-frontmatter.mdx
@@ -0,0 +1,16 @@
---js
(() => {
require(`fs`).writeFileSync(`${process.cwd()}/cypress/fixtures/file-to-attempt-rce-on.txt`, (new Error('Helpful stack trace if this does execute. It should not execute.')).stack)
console.trace()
return {
title: `I should not be parsed`
}
})()

---

<h1>JS frontmatter engine is disabled by default</h1>

<span data-cy="js-frontmatter">
{props.pageContext.frontmatter?.title || `disabled`}
</span>
30 changes: 30 additions & 0 deletions e2e-tests/mdx-less-babel/src/pages/mdx-query-js-frontmatter.js
@@ -0,0 +1,30 @@
import React from "react"
import { graphql } from "gatsby"

export default function PageRunningGraphqlResolversOnJSFrontmatterTestInputs({
data,
}) {
return <pre>{JSON.stringify(data.allMdx.nodes, null, 2)}</pre>
}

export const query = graphql`
{
allMdx(filter: { slug: { glob: "frontmatter-engine/*" } }) {
nodes {
frontmatter {
title
}
body
excerpt
tableOfContents
timeToRead
wordCount {
paragraphs
sentences
words
}
mdxAST
}
}
}
`
@@ -0,0 +1,16 @@
---javascript
(() => {
require(`fs`).writeFileSync(`${process.cwd()}/cypress/fixtures/file-to-attempt-rce-on.txt`, (new Error('Helpful stack trace if this does execute. It should not execute.')).stack)
console.trace()
return {
title: `I should not be parsed`
}
})()

---

<h1>JS frontmatter engine is disabled by default w</h1>

<span data-cy="js-frontmatter">
{props.pageContext.frontmatter?.title || `disabled`}
</span>
@@ -0,0 +1,16 @@
---js
(() => {
require(`fs`).writeFileSync(`${process.cwd()}/cypress/fixtures/file-to-attempt-rce-on.txt`, (new Error('Helpful stack trace if this does execute. It should not execute.')).stack)
console.trace()
return {
title: `I should not be parsed`
}
})()

---

<h1>JS frontmatter engine is disabled by default</h1>

<span data-cy="js-frontmatter">
{props.pageContext.frontmatter?.title || `disabled`}
</span>
1 change: 1 addition & 0 deletions e2e-tests/mdx/.gitignore
Expand Up @@ -9,3 +9,4 @@ yarn-error.log

# Cypress output
cypress/videos/
cypress/screenshots/
1 change: 1 addition & 0 deletions e2e-tests/mdx/cypress/fixtures/file-to-attempt-rce-on.txt
@@ -0,0 +1 @@
Nothing here, do not remove
29 changes: 29 additions & 0 deletions e2e-tests/mdx/cypress/integration/js-frontmatter.js
@@ -0,0 +1,29 @@
describe(`webpack loader`, () => {
it(`---js frontmatter should not parse by default`, () => {
cy.visit(`/js-frontmatter`).waitForRouteChange()

// Check frontmatter not parsed in page context
cy.get(`[data-cy="js-frontmatter"]`).invoke(`text`).should(`eq`, `disabled`)
})

it(`---javascript frontmatter should not parse by default`, () => {
cy.visit(`/javascript-frontmatter`).waitForRouteChange()

// Check frontmatter not parsed in page context
cy.get(`[data-cy="js-frontmatter"]`).invoke(`text`).should(`eq`, `disabled`)
})
})

describe(`data layer`, () => {
it(`---js or ---javascript frontmatter should not parse by default`, () => {
cy.visit(`/mdx-query-js-frontmatter/`).waitForRouteChange()
cy.contains(`I should not be parsed`).should("not.exist")
})
})

it(`---js and ---javascript frontmatter should not allow remote code execution`, () => {
cy.readFile(`cypress/fixtures/file-to-attempt-rce-on.txt`).should(
`eq`,
`Nothing here, do not remove`
)
})
2 changes: 1 addition & 1 deletion e2e-tests/mdx/gatsby-config.js
Expand Up @@ -37,7 +37,7 @@ module.exports = {
* See #26914 for more info.
*/
function remarkRequireFilePathPlugin() {
return function transformer(tree, file) {
return function transformer(_, file) {
if (!file.dirname) {
throw new Error("No directory name for this markdown file!")
}
Expand Down
13 changes: 13 additions & 0 deletions e2e-tests/mdx/gatsby-node.js
Expand Up @@ -16,3 +16,16 @@ exports.onPostBuild = async ({ graphql }) => {
{ spaces: 2 }
)
}

exports.createSchemaCustomization = ({ actions }) => {
const { createTypes } = actions

createTypes(`
type Mdx implements Node {
frontmatter: Frontmatter
}
type Frontmatter {
title: String
}
`)
}
7 changes: 4 additions & 3 deletions e2e-tests/mdx/package.json
Expand Up @@ -7,9 +7,9 @@
"@mdx-js/react": "^1.6.6",
"cypress": "^7.2.0",
"fs-extra": "^8.1.0",
"gatsby": "^3.0.0",
"gatsby-plugin-mdx": "^2.0.0",
"gatsby-source-filesystem": "^3.0.0",
"gatsby": "next",
"gatsby-plugin-mdx": "next",
"gatsby-source-filesystem": "next",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"theme-ui": "^0.3.1"
Expand All @@ -19,6 +19,7 @@
],
"license": "MIT",
"scripts": {
"clean": "gatsby clean",
"build": "cross-env CYPRESS_SUPPORT=y gatsby build",
"develop": "cross-env CYPRESS_SUPPORT=y gatsby develop",
"format": "prettier --write '**/*.js'",
Expand Down
16 changes: 16 additions & 0 deletions e2e-tests/mdx/src/pages/javascript-frontmatter.mdx
@@ -0,0 +1,16 @@
---javascript
(() => {
require(`fs`).writeFileSync(`${process.cwd()}/cypress/fixtures/file-to-attempt-rce-on.txt`, (new Error('Helpful stack trace if this does execute. It should not execute.')).stack)
console.trace()
return {
title: `I should not be parsed`
}
})()

---

<h1>JS frontmatter engine is disabled by default</h1>

<span data-cy="js-frontmatter">
{props.pageContext.frontmatter?.title || `disabled`}
</span>
16 changes: 16 additions & 0 deletions e2e-tests/mdx/src/pages/js-frontmatter.mdx
@@ -0,0 +1,16 @@
---js
(() => {
require(`fs`).writeFileSync(`${process.cwd()}/cypress/fixtures/file-to-attempt-rce-on.txt`, (new Error('Helpful stack trace if this does execute. It should not execute.')).stack)
console.trace()
return {
title: `I should not be parsed`
}
})()

---

<h1>JS frontmatter engine is disabled by default</h1>

<span data-cy="js-frontmatter">
{props.pageContext.frontmatter?.title || `disabled`}
</span>
30 changes: 30 additions & 0 deletions e2e-tests/mdx/src/pages/mdx-query-js-frontmatter.js
@@ -0,0 +1,30 @@
import React from "react"
import { graphql } from "gatsby"

export default function PageRunningGraphqlResolversOnJSFrontmatterTestInputs({
data,
}) {
return <pre>{JSON.stringify(data.allMdx.nodes, null, 2)}</pre>
}

export const query = graphql`
{
allMdx(filter: { slug: { glob: "frontmatter-engine/*" } }) {
nodes {
frontmatter {
title
}
body
excerpt
tableOfContents
timeToRead
wordCount {
paragraphs
sentences
words
}
mdxAST
}
}
}
`
@@ -0,0 +1,16 @@
---javascript
(() => {
require(`fs`).writeFileSync(`${process.cwd()}/cypress/fixtures/file-to-attempt-rce-on.txt`, (new Error('Helpful stack trace if this does execute. It should not execute.')).stack)
console.trace()
return {
title: `I should not be parsed`
}
})()

---

<h1>JS frontmatter engine is disabled by default w</h1>

<span data-cy="js-frontmatter">
{props.pageContext.frontmatter?.title || `disabled`}
</span>
16 changes: 16 additions & 0 deletions e2e-tests/mdx/src/posts/frontmatter-engine/js-frontmatter.mdx
@@ -0,0 +1,16 @@
---js
(() => {
require(`fs`).writeFileSync(`${process.cwd()}/cypress/fixtures/file-to-attempt-rce-on.txt`, (new Error('Helpful stack trace if this does execute. It should not execute.')).stack)
console.trace()
return {
title: `I should not be parsed`
}
})()

---

<h1>JS frontmatter engine is disabled by default</h1>

<span data-cy="js-frontmatter">
{props.pageContext.frontmatter?.title || `disabled`}
</span>
5 changes: 5 additions & 0 deletions packages/gatsby-plugin-mdx/README.md
Expand Up @@ -123,6 +123,7 @@ scope, and more.
| [`mediaTypes`](#media-types) | `["text/markdown", "text/x-markdown"]` | Determine which media types are processed by MDX |
| [`shouldBlockNodeFromTransformation`](#shouldblocknodefromtransformation) | `(node) => false` | Disable MDX transformation for nodes where this function returns true |
| [`commonmark`](#commonmark) | `false` | Use CommonMark |
| [`JSFrontmatterEngine`](#jsfrontmatterengine) | `false` | Add support for JavaScript frontmatter engine |

#### Extensions

Expand Down Expand Up @@ -466,6 +467,10 @@ module.exports = {

MDX will be parsed using CommonMark.

#### JSFrontmatterEngine

Adds support for JavaScript frontmatter engine. Use with caution - see https://github.com/gatsbyjs/gatsby/security/advisories/GHSA-mj46-r4gr-5x83

### Components

MDX and `gatsby-plugin-mdx` use components for different things like rendering
Expand Down

0 comments on commit e916cf8

Please sign in to comment.