Skip to content

Commit e916cf8

Browse files
gatsbybottyhopppieh
authored
fix(gatsby-plugin-mdx): don't allow JS frontmatter by default (#35830) (#35832)
Co-authored-by: Ty Hopp <[email protected]> Co-authored-by: Michal Piechowiak <[email protected]>
1 parent ab3131a commit e916cf8

29 files changed

+354
-24
lines changed

e2e-tests/mdx-less-babel/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ yarn-error.log
99

1010
# Cypress output
1111
cypress/videos/
12+
cypress/screenshots/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Nothing here, do not remove
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
describe(`webpack loader`, () => {
2+
it(`---js frontmatter should not parse by default`, () => {
3+
cy.visit(`/js-frontmatter`).waitForRouteChange()
4+
5+
// Check frontmatter not parsed in page context
6+
cy.get(`[data-cy="js-frontmatter"]`).invoke(`text`).should(`eq`, `disabled`)
7+
})
8+
9+
it(`---javascript frontmatter should not parse by default`, () => {
10+
cy.visit(`/javascript-frontmatter`).waitForRouteChange()
11+
12+
// Check frontmatter not parsed in page context
13+
cy.get(`[data-cy="js-frontmatter"]`).invoke(`text`).should(`eq`, `disabled`)
14+
})
15+
})
16+
17+
describe(`data layer`, () => {
18+
it(`---js or ---javascript frontmatter should not parse by default`, () => {
19+
cy.visit(`/mdx-query-js-frontmatter/`).waitForRouteChange()
20+
cy.contains(`I should not be parsed`).should("not.exist")
21+
})
22+
})
23+
24+
it(`---js and ---javascript frontmatter should not allow remote code execution`, () => {
25+
cy.readFile(`cypress/fixtures/file-to-attempt-rce-on.txt`).should(
26+
`eq`,
27+
`Nothing here, do not remove`
28+
)
29+
})
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
exports.createSchemaCustomization = ({ actions }) => {
2+
const { createTypes } = actions
3+
4+
createTypes(`
5+
type Mdx implements Node {
6+
frontmatter: Frontmatter
7+
}
8+
type Frontmatter {
9+
title: String
10+
}
11+
`)
12+
}

e2e-tests/mdx-less-babel/package.json

+8-7
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
"@mdx-js/mdx": "^1.6.6",
77
"@mdx-js/react": "^1.6.6",
88
"cypress": "^3.1.0",
9-
"gatsby": "^2.0.118",
10-
"gatsby-plugin-mdx": "^1.2.19",
11-
"gatsby-source-filesystem": "^2.3.14",
9+
"gatsby": "next",
10+
"gatsby-plugin-mdx": "next",
11+
"gatsby-source-filesystem": "next",
1212
"react": "^17.0.2",
1313
"react-dom": "^17.0.2",
1414
"theme-ui": "^0.3.1"
@@ -18,10 +18,11 @@
1818
],
1919
"license": "MIT",
2020
"scripts": {
21-
"build": "gatsby build",
22-
"develop": "gatsby develop",
21+
"clean": "gatsby clean",
22+
"build": "cross-env CYPRESS_SUPPORT=y gatsby build",
23+
"develop": "cross-env CYPRESS_SUPPORT=y gatsby develop",
2324
"format": "prettier --write '**/*.js'",
24-
"test": "cross-env CYPRESS_SUPPORT=y npm run build && npm run start-server-and-test",
25+
"test": "npm run build && npm run start-server-and-test",
2526
"start-server-and-test": "start-server-and-test serve http://localhost:9000 cy:run",
2627
"serve": "gatsby serve",
2728
"cy:open": "cypress open",
@@ -34,4 +35,4 @@
3435
"prettier": "2.0.4",
3536
"start-server-and-test": "^1.7.1"
3637
}
37-
}
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---javascript
2+
(() => {
3+
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)
4+
console.trace()
5+
return {
6+
title: `I should not be parsed`
7+
}
8+
})()
9+
10+
---
11+
12+
<h1>JS frontmatter engine is disabled by default</h1>
13+
14+
<span data-cy="js-frontmatter">
15+
{props.pageContext.frontmatter?.title || `disabled`}
16+
</span>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---js
2+
(() => {
3+
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)
4+
console.trace()
5+
return {
6+
title: `I should not be parsed`
7+
}
8+
})()
9+
10+
---
11+
12+
<h1>JS frontmatter engine is disabled by default</h1>
13+
14+
<span data-cy="js-frontmatter">
15+
{props.pageContext.frontmatter?.title || `disabled`}
16+
</span>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import React from "react"
2+
import { graphql } from "gatsby"
3+
4+
export default function PageRunningGraphqlResolversOnJSFrontmatterTestInputs({
5+
data,
6+
}) {
7+
return <pre>{JSON.stringify(data.allMdx.nodes, null, 2)}</pre>
8+
}
9+
10+
export const query = graphql`
11+
{
12+
allMdx(filter: { slug: { glob: "frontmatter-engine/*" } }) {
13+
nodes {
14+
frontmatter {
15+
title
16+
}
17+
body
18+
excerpt
19+
tableOfContents
20+
timeToRead
21+
wordCount {
22+
paragraphs
23+
sentences
24+
words
25+
}
26+
mdxAST
27+
}
28+
}
29+
}
30+
`
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---javascript
2+
(() => {
3+
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)
4+
console.trace()
5+
return {
6+
title: `I should not be parsed`
7+
}
8+
})()
9+
10+
---
11+
12+
<h1>JS frontmatter engine is disabled by default w</h1>
13+
14+
<span data-cy="js-frontmatter">
15+
{props.pageContext.frontmatter?.title || `disabled`}
16+
</span>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---js
2+
(() => {
3+
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)
4+
console.trace()
5+
return {
6+
title: `I should not be parsed`
7+
}
8+
})()
9+
10+
---
11+
12+
<h1>JS frontmatter engine is disabled by default</h1>
13+
14+
<span data-cy="js-frontmatter">
15+
{props.pageContext.frontmatter?.title || `disabled`}
16+
</span>

e2e-tests/mdx/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ yarn-error.log
99

1010
# Cypress output
1111
cypress/videos/
12+
cypress/screenshots/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Nothing here, do not remove
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
describe(`webpack loader`, () => {
2+
it(`---js frontmatter should not parse by default`, () => {
3+
cy.visit(`/js-frontmatter`).waitForRouteChange()
4+
5+
// Check frontmatter not parsed in page context
6+
cy.get(`[data-cy="js-frontmatter"]`).invoke(`text`).should(`eq`, `disabled`)
7+
})
8+
9+
it(`---javascript frontmatter should not parse by default`, () => {
10+
cy.visit(`/javascript-frontmatter`).waitForRouteChange()
11+
12+
// Check frontmatter not parsed in page context
13+
cy.get(`[data-cy="js-frontmatter"]`).invoke(`text`).should(`eq`, `disabled`)
14+
})
15+
})
16+
17+
describe(`data layer`, () => {
18+
it(`---js or ---javascript frontmatter should not parse by default`, () => {
19+
cy.visit(`/mdx-query-js-frontmatter/`).waitForRouteChange()
20+
cy.contains(`I should not be parsed`).should("not.exist")
21+
})
22+
})
23+
24+
it(`---js and ---javascript frontmatter should not allow remote code execution`, () => {
25+
cy.readFile(`cypress/fixtures/file-to-attempt-rce-on.txt`).should(
26+
`eq`,
27+
`Nothing here, do not remove`
28+
)
29+
})

e2e-tests/mdx/gatsby-config.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ module.exports = {
3737
* See #26914 for more info.
3838
*/
3939
function remarkRequireFilePathPlugin() {
40-
return function transformer(tree, file) {
40+
return function transformer(_, file) {
4141
if (!file.dirname) {
4242
throw new Error("No directory name for this markdown file!")
4343
}

e2e-tests/mdx/gatsby-node.js

+13
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,16 @@ exports.onPostBuild = async ({ graphql }) => {
1616
{ spaces: 2 }
1717
)
1818
}
19+
20+
exports.createSchemaCustomization = ({ actions }) => {
21+
const { createTypes } = actions
22+
23+
createTypes(`
24+
type Mdx implements Node {
25+
frontmatter: Frontmatter
26+
}
27+
type Frontmatter {
28+
title: String
29+
}
30+
`)
31+
}

e2e-tests/mdx/package.json

+4-3
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
"@mdx-js/react": "^1.6.6",
88
"cypress": "^7.2.0",
99
"fs-extra": "^8.1.0",
10-
"gatsby": "^3.0.0",
11-
"gatsby-plugin-mdx": "^2.0.0",
12-
"gatsby-source-filesystem": "^3.0.0",
10+
"gatsby": "next",
11+
"gatsby-plugin-mdx": "next",
12+
"gatsby-source-filesystem": "next",
1313
"react": "^17.0.2",
1414
"react-dom": "^17.0.2",
1515
"theme-ui": "^0.3.1"
@@ -19,6 +19,7 @@
1919
],
2020
"license": "MIT",
2121
"scripts": {
22+
"clean": "gatsby clean",
2223
"build": "cross-env CYPRESS_SUPPORT=y gatsby build",
2324
"develop": "cross-env CYPRESS_SUPPORT=y gatsby develop",
2425
"format": "prettier --write '**/*.js'",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---javascript
2+
(() => {
3+
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)
4+
console.trace()
5+
return {
6+
title: `I should not be parsed`
7+
}
8+
})()
9+
10+
---
11+
12+
<h1>JS frontmatter engine is disabled by default</h1>
13+
14+
<span data-cy="js-frontmatter">
15+
{props.pageContext.frontmatter?.title || `disabled`}
16+
</span>
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---js
2+
(() => {
3+
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)
4+
console.trace()
5+
return {
6+
title: `I should not be parsed`
7+
}
8+
})()
9+
10+
---
11+
12+
<h1>JS frontmatter engine is disabled by default</h1>
13+
14+
<span data-cy="js-frontmatter">
15+
{props.pageContext.frontmatter?.title || `disabled`}
16+
</span>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import React from "react"
2+
import { graphql } from "gatsby"
3+
4+
export default function PageRunningGraphqlResolversOnJSFrontmatterTestInputs({
5+
data,
6+
}) {
7+
return <pre>{JSON.stringify(data.allMdx.nodes, null, 2)}</pre>
8+
}
9+
10+
export const query = graphql`
11+
{
12+
allMdx(filter: { slug: { glob: "frontmatter-engine/*" } }) {
13+
nodes {
14+
frontmatter {
15+
title
16+
}
17+
body
18+
excerpt
19+
tableOfContents
20+
timeToRead
21+
wordCount {
22+
paragraphs
23+
sentences
24+
words
25+
}
26+
mdxAST
27+
}
28+
}
29+
}
30+
`
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---javascript
2+
(() => {
3+
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)
4+
console.trace()
5+
return {
6+
title: `I should not be parsed`
7+
}
8+
})()
9+
10+
---
11+
12+
<h1>JS frontmatter engine is disabled by default w</h1>
13+
14+
<span data-cy="js-frontmatter">
15+
{props.pageContext.frontmatter?.title || `disabled`}
16+
</span>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---js
2+
(() => {
3+
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)
4+
console.trace()
5+
return {
6+
title: `I should not be parsed`
7+
}
8+
})()
9+
10+
---
11+
12+
<h1>JS frontmatter engine is disabled by default</h1>
13+
14+
<span data-cy="js-frontmatter">
15+
{props.pageContext.frontmatter?.title || `disabled`}
16+
</span>

packages/gatsby-plugin-mdx/README.md

+5
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ scope, and more.
123123
| [`mediaTypes`](#media-types) | `["text/markdown", "text/x-markdown"]` | Determine which media types are processed by MDX |
124124
| [`shouldBlockNodeFromTransformation`](#shouldblocknodefromtransformation) | `(node) => false` | Disable MDX transformation for nodes where this function returns true |
125125
| [`commonmark`](#commonmark) | `false` | Use CommonMark |
126+
| [`JSFrontmatterEngine`](#jsfrontmatterengine) | `false` | Add support for JavaScript frontmatter engine |
126127

127128
#### Extensions
128129

@@ -466,6 +467,10 @@ module.exports = {
466467

467468
MDX will be parsed using CommonMark.
468469

470+
#### JSFrontmatterEngine
471+
472+
Adds support for JavaScript frontmatter engine. Use with caution - see https://github.com/gatsbyjs/gatsby/security/advisories/GHSA-mj46-r4gr-5x83
473+
469474
### Components
470475

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

0 commit comments

Comments
 (0)