Skip to content

feat: use calculated integrity hashes for local vendor plugins#947

Closed
pivaldi wants to merge 0 commit into
next-theme:masterfrom
pivaldi:master
Closed

feat: use calculated integrity hashes for local vendor plugins#947
pivaldi wants to merge 0 commit into
next-theme:masterfrom
pivaldi:master

Conversation

@pivaldi

@pivaldi pivaldi commented Feb 12, 2026

Copy link
Copy Markdown
Contributor
  • The changes have been tested (for bug fixes / features).
  • Docs in NexT website have been added / updated (for features).

PR Type

  • Bugfix.
  • Feature.
  • Improvement.
  • Code style update (e.g. formatting, linting).
  • Refactoring (no changes to functionality and APIs).
  • Documentation.
  • Translation.
  • Other... Please describe:

When vendors.plugins is set to local, integrity hashes are now computed from the actual local files via @next-theme/plugins getLocalIntegrity() rather than using the hardcoded CDN hashes from _vendors.yml.

This fixes SRI (Subresource Integrity) validation failures that caused browsers to block all vendor assets when self-hosting, resulting in blank pages.

CDN mode is unaffected: hardcoded hashes from _vendors.yml are still used when plugins is not local.

Depends on: next-theme/plugins#347

@CLAassistant

CLAassistant commented Feb 12, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@github-actions

Copy link
Copy Markdown

This pull request contains changes to the configuration file. Please make sure the documentation in NexT website is changed or added.
Please edit relevant source files here: https://github.com/next-theme/theme-next-docs/tree/master/source/docs and create a pull request with the changes here: https://github.com/next-theme/theme-next-docs/pulls

@stevenjoezhang

Copy link
Copy Markdown
Member

@pivaldi
Thanks for the PR. I am a bit confused about the problem this patch is intended to solve.

I checked all dependencies from @next-theme/plugins against the integrity hashes recorded in hexo-theme-next/_vendors.yml, and could not find any SRI mismatch when the theme and plugin versions are aligned (all checked local files match the existing hashes).

Could you clarify in which scenario the current hardcoded integrity values fail for vendors.plugins: local? Is this meant to handle cases where users mix different versions of hexo-theme-next and @next-theme/plugins, or where the plugin dependencies are updated before _vendors.yml is regenerated?

@pivaldi

pivaldi commented Jun 24, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for taking a look, @stevenjoezhang — and you're right to push on this.

the hardcoded hash actually fail only when the vendor files served in plugins: local mode differ byte-for-byte from the CDN versions that _vendors.yml's hashes were computed against. With a clean install where the theme and @next-theme/plugins are on matching releases, the bytes are identical and SRI passes — which is exactly what you observed.

The mismatch shows up once the bundled vendor versions diverge from the pinned hashes. In my case that happens because I let Renovate update the libraries inside @next-theme/plugins ahead of the theme (newer @fancyapps/ui, katex, mathjax, etc.). The local files are then newer than the CDN versions the hashes were cut from, the browser's SRI check fails, every vendor asset is blocked, and the page renders blank. So it's not "always broken" — it breaks whenever the locally bundled vendor version no longer matches the theme's pinned hash.

There is a simpler fix than this PR…
SRI is really there to protect against a compromised third-party CDN but for self-hosted, same-origin assets it provides little security benefit and is precisely what breaks here.
So the minimal change would be to drop the integrity (and crossorigin) attributes when plugins: local, instead of computing and threading hashes through the plugin and templates.
That removes the whole failure class with a few lines in the theme and no plugin change at all (dropping the dependency on next-theme/plugins#347).

If you'd rather keep SRI even for local assets, the computed-hash approach in this PR (#347 exposing getLocalIntegrity() / the next_vendor_integrity helper) is the fallback because it derives the hash from the bytes actually served, so it can never mismatch regardless of version skew.

My preference would be to "drop integrity for local" route since it's smaller and needs no plugin release.
Which would you prefer?

One more thing: we can split the lazy-CSS optimization out into its own PR so it can be reviewed independently of the SRI discussion.

@stevenjoezhang

Copy link
Copy Markdown
Member

@pivaldi Thanks for clarifying. I agree that dropping integrity and crossorigin for vendors.plugins: local is the better fix. For same-origin self-hosted assets, SRI does not add much value.

So I would prefer:

  1. When vendors.plugins === 'local', do not emit integrity or crossorigin for plugin vendor assets.
  2. Split the lazy-CSS changes into a separate PR.

Thanks!

@pivaldi

pivaldi commented Jun 28, 2026

Copy link
Copy Markdown
Contributor Author

Closing this in favor of two focused PRs that address @stevenjoezhang's feedback.

As discussed above, hardcoded SRI hashes only break when self-hosted vendor
files diverge byte-for-byte from the CDN builds the hashes were computed for
(e.g. when bundled vendor versions are updated independently). Since SRI adds
no real value for same-origin self-hosted assets, the agreed fix is simply to
drop integrity/crossorigin for vendors.plugins: local rather than
compute hashes — so this needs no plugin change, and the dependency on
next-theme/plugins#347 is dropped.

Splitting the original change into:

Thanks for the review!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants