diff --git a/packages/gatsby-transformer-remark/README.md b/packages/gatsby-transformer-remark/README.md
index 6c012fe738ebe..e780d4a802f37 100644
--- a/packages/gatsby-transformer-remark/README.md
+++ b/packages/gatsby-transformer-remark/README.md
@@ -4,25 +4,46 @@ Parses Markdown files using [remark](http://remark.js.org/).
 
 ## Install
 
-`npm install gatsby-transformer-remark`
-
-## How to use
-
-```javascript
-// In your gatsby-config.js
-plugins: [
-  {
-    resolve: `gatsby-transformer-remark`,
-    options: {
-      // Footnotes mode (default: true)
-      footnotes: true,
-      // GitHub Flavored Markdown mode (default: true)
-      gfm: true,
-      // Plugins configs
-      plugins: [],
+Install the plugin to your site:
+
+```shell
+npm install gatsby-transformer-remark
+```
+
+Add it to your `gatsby-config`:
+
+```js:title=gatsby-config.js
+module.exports = {
+  plugins: [
+    {
+      resolve: `gatsby-transformer-remark`,
+      options: {},
     },
-  },
-],
+  ],
+}
+```
+
+## Options
+
+```js:title=gatsby-config.js
+module.exports = {
+  plugins: [
+    {
+      resolve: `gatsby-transformer-remark`,
+      options: {
+        // Footnotes mode (default: true)
+        footnotes: true,
+        // GitHub Flavored Markdown mode (default: true)
+        gfm: true,
+        // Add your gatsby-remark-* plugins here
+        plugins: [],
+        // Enable JS for https://github.com/jonschlinkert/gray-matter#optionsengines (default: false)
+        // It's not advised to set this to "true" and this option will likely be removed in the future
+        jsFrontmatterEngine: false,
+      },
+    },
+  ],
+}
 ```
 
 The following parts of `options` enable the `remark-footnotes` and `remark-gfm`
@@ -31,10 +52,30 @@ plugins:
 - `options.footnotes`
 - `options.gfm`
 
-A full explanation of how to use markdown in Gatsby can be found here:
-[Adding Markdown Pages](https://www.gatsbyjs.com/docs/how-to/routing/adding-markdown-pages/)
+A full explanation of how to use markdown in Gatsby can be found here: [Adding Markdown Pages](https://www.gatsbyjs.com/docs/how-to/routing/adding-markdown-pages/)
+
+There are many `gatsby-remark-*` plugins which you can install to customize how Markdown is processed. Check out the [source code for using-remark](https://github.com/gatsbyjs/gatsby/tree/master/examples/using-remark) as an example.
+
+### `gray-matter` options
+
+`gatsby-transformer-remark` uses [gray-matter](https://github.com/jonschlinkert/gray-matter) to parse Markdown frontmatter, so you can specify any of the options mentioned [in its README](https://github.com/jonschlinkert/gray-matter#options) in the `options` key of the plugin.
 
-There are many Gatsby Remark plugins which you can install to customize how Markdown is processed. Many of them are demoed at https://using-remark.gatsbyjs.org/. See also the [source code for using-remark](https://github.com/gatsbyjs/gatsby/tree/master/examples/using-remark).
+**Example: Excerpts**
+
+If you don't want to use `pruneLength` for excerpts but a custom separator, you can specify an `excerpt_separator`:
+
+```js:title=gatsby-config.js
+module.exports = {
+  plugins: [
+    {
+      resolve: `gatsby-transformer-remark`,
+      options: {
+        excerpt_separator: `<!-- end -->`
+      }
+    },
+  ],
+}
+```
 
 ## Parsing algorithm
 
@@ -120,19 +161,20 @@ By default, `absolute` is set to `false`, generating a relative path. If you'd l
 
 To pass default options to the plugin generating the `tableOfContents`, configure it in `gatsby-config.js` as shown below. The options shown below are the defaults used by the plugin.
 
-```javascript
-// In your gatsby-config.js
-plugins: [
-  {
-    resolve: `gatsby-transformer-remark`,
-    options: {
-      tableOfContents: {
-        heading: null,
-        maxDepth: 6,
+```js:title=gatsby-config.js
+module.exports = {
+  plugins: [
+    {
+      resolve: `gatsby-transformer-remark`,
+      options: {
+        tableOfContents: {
+          heading: null,
+          maxDepth: 6,
+        },
       },
     },
-  },
-]
+  ],
+}
 ```
 
 ### Excerpts
@@ -198,23 +240,6 @@ You can also get excerpts in Markdown format.
 }
 ```
 
-## `gray-matter` options
-
-`gatsby-transformer-remark` uses [gray-matter](https://github.com/jonschlinkert/gray-matter) to parse Markdown frontmatter, so you can specify any of the options mentioned [here](https://github.com/jonschlinkert/gray-matter#options) in the `gatsby-config.js` file.
-
-### Example: Excerpts
-
-If you don't want to use `pruneLength` for excerpts but a custom separator, you can specify an `excerpt_separator` in the `gatsby-config.js` file:
-
-```javascript
-{
-  "resolve": `gatsby-transformer-remark`,
-  "options": {
-    "excerpt_separator": `<!-- end -->`
-  }
-}
-```
-
 Any file that does not have the given `excerpt_separator` will fall back to the default pruning method.
 
 ## Troubleshooting
@@ -237,14 +262,18 @@ If that is the case, you can set `truncate` option on `excerpt` field, like:
 
 If your Markdown file contains HTML, `excerpt` will not return a value.
 
-In that case, you can set an `excerpt_separator` in the `gatsby-config.js` file:
+In that case, you can set an `excerpt_separator` in the `gatsby-config`:
 
-```javascript
-{
-  "resolve": `gatsby-transformer-remark`,
-  "options": {
-    "excerpt_separator": `<!-- endexcerpt -->`
-  }
+```js:title=gatsby-config.js
+module.exports = {
+  plugins: [
+    {
+      resolve: `gatsby-transformer-remark`,
+      options: {
+        excerpt_separator: `<!-- endexcerpt -->`
+      },
+    },
+  ],
 }
 ```
 
diff --git a/packages/gatsby-transformer-remark/src/__tests__/gatsby-node.js b/packages/gatsby-transformer-remark/src/__tests__/gatsby-node.js
index d288f29ab165a..4e7de171b5b49 100644
--- a/packages/gatsby-transformer-remark/src/__tests__/gatsby-node.js
+++ b/packages/gatsby-transformer-remark/src/__tests__/gatsby-node.js
@@ -7,32 +7,43 @@ describe(`gatsby-node.js`, () => {
       `"footnotes" must be a boolean`,
       `"gfm" must be a boolean`,
       `"plugins" must be an array`,
+      `"jsFrontmatterEngine" must be a boolean`,
     ]
 
-    const { errors } = await testPluginOptionsSchema(pluginOptionsSchema, {
-      footnotes: `this should be a boolean`,
-      gfm: `this should be a boolean`,
-      plugins: `this should be an array`,
-    })
+    const { errors, isValid } = await testPluginOptionsSchema(
+      pluginOptionsSchema,
+      {
+        footnotes: `this should be a boolean`,
+        gfm: `this should be a boolean`,
+        plugins: `this should be an array`,
+        jsFrontmatterEngine: `this should be a boolean`,
+      }
+    )
 
+    expect(isValid).toBe(false)
     expect(errors).toEqual(expectedErrors)
   })
 
   it(`should validate the schema`, async () => {
-    const { isValid } = await testPluginOptionsSchema(pluginOptionsSchema, {
-      footnotes: false,
-      gfm: false,
-      plugins: [
-        `gatsby-remark-copy-linked-files`,
-        {
-          resolve: `gatsby-remark-images`,
-          options: {
-            maxWidth: 756,
+    const { isValid, errors } = await testPluginOptionsSchema(
+      pluginOptionsSchema,
+      {
+        footnotes: false,
+        gfm: false,
+        plugins: [
+          `gatsby-remark-copy-linked-files`,
+          {
+            resolve: `gatsby-remark-images`,
+            options: {
+              maxWidth: 756,
+            },
           },
-        },
-      ],
-    })
+        ],
+        jsFrontmatterEngine: true,
+      }
+    )
 
     expect(isValid).toBe(true)
+    expect(errors).toEqual([])
   })
 })
diff --git a/packages/gatsby-transformer-remark/src/gatsby-node.js b/packages/gatsby-transformer-remark/src/gatsby-node.js
index 9c1ef41caee4b..e403ab9961a99 100644
--- a/packages/gatsby-transformer-remark/src/gatsby-node.js
+++ b/packages/gatsby-transformer-remark/src/gatsby-node.js
@@ -7,6 +7,9 @@ exports.unstable_shouldOnCreateNode = unstable_shouldOnCreateNode
 exports.createSchemaCustomization = require(`./create-schema-customization`)
 exports.setFieldsOnGraphQLNodeType = require(`./extend-node-type`)
 
+// Dedupe warning
+let warnedAboutJSFrontmatterEngine = false
+
 exports.pluginOptionsSchema = function ({ Joi }) {
   return Joi.object({
     footnotes: Joi.boolean().description(
@@ -21,5 +24,43 @@ exports.pluginOptionsSchema = function ({ Joi }) {
     plugins: Joi.subPlugins().description(
       `A list of remark plugins. See also: https://github.com/gatsbyjs/gatsby/tree/master/examples/using-remark for examples`
     ),
+    // TODO(v6): Remove and disallow any custom engines (including JS)
+    jsFrontmatterEngine: Joi.boolean()
+      .default(false)
+      .description(
+        `Enable JS for https://github.com/jonschlinkert/gray-matter#optionsengines`
+      ),
+  }).custom(value => {
+    const { jsFrontmatterEngine, engines = {} } = value || {}
+
+    if (jsFrontmatterEngine) {
+      // show this warning only once in main process
+      if (!process.env.GATSBY_WORKER_ID) {
+        console.warn(
+          `JS frontmatter engine is enabled in gatsby-transformer-remark (via jsFrontmatterEngine: true). This can cause a security risk, see https://github.com/gatsbyjs/gatsby/security/advisories/GHSA-7ch4-rr99-cqcw. If you are not relying on this feature we strongly suggest disabling it via the "jsFrontmatterEngine: false" plugin option. If you rely on this feature make sure to properly secure or sanitize your content source.`
+        )
+      }
+      return value
+    }
+
+    const js = () => {
+      if (!warnedAboutJSFrontmatterEngine) {
+        console.warn(
+          `You have frontmatter declared with "---js" or "---javascript" that is not parsed by default to mitigate a security risk (see https://github.com/gatsbyjs/gatsby/security/advisories/GHSA-7ch4-rr99-cqcw). If you require this feature it can be enabled by setting "jsFrontmatterEngine: true" in the plugin options of gatsby-transformer-remark.`
+        )
+        warnedAboutJSFrontmatterEngine = true
+      }
+      // we still have to return a frontmatter, so we just stub it with empty object
+      return {}
+    }
+
+    return {
+      ...value,
+      engines: {
+        ...engines,
+        js,
+        javascript: js,
+      },
+    }
   })
 }