Pin the scripts and stylesheets WordPress prints to the bytes they should contain, so the browser refuses a file that has changed. The plugin hashes the site's own files from disk and adds integrity and crossorigin to their tags.
Turn pinning on
-
Find the assets
Under Integrity, choose Check home page. WordPress loads its own home page once and records what it prints. Assets are also recorded as pages are served while pinning is on.
-
Pin the site’s own files
Switch on Pin this site’s own files and choose Save. The header badge changes to Pinning on.
-
Decide about remote files
Optionally switch on Pin remote files too. CDN files are fetched in the background and pinned only when their host allows cross-origin checks.
-
Check the table
Each asset shows Pinned, or why it is not. Fix or exclude anything you do not want pinned.
How assets are hashed
| This site's files | Remote files | |
|---|---|---|
| Source of the bytes | The file on disk | A background fetch, about 30 seconds after the file is first seen |
| Algorithm | SHA-384 | SHA-384 |
| Re-hashed | Whenever the file's modification time changes, on the next page that prints it | With Hash again |
| Limits | .js, .mjs and .css files up to 5 MB | Up to 5 MB, three redirects |
| Pinned when | Pinning is on | Pin remote files too is on and the host sends Access-Control-Allow-Origin of * or the site's own origin |
A URL counts as this site's when it is under the content, plugins, includes, site or home URL and resolves to a file inside the matching directory. Paths that climb out of those directories with .. are refused. The consepo_csp_scanner_asset_bases filter changes the list; see Hooks and constants.
The plugin adds integrity and, when the tag has none, crossorigin="anonymous". It leaves tags that already carry an integrity attribute alone.
<link crossorigin="anonymous" integrity="sha384-FX5lt8LPJCa0tSh1GD8ii7WfZhgsC5PQpikPwaycOPT9mZCpeCvz5MCyle101LiZ" rel='stylesheet' id='dashicons-css' href='http://localhost:9400/wp-includes/css/dashicons.min.css?ver=7.1.4' media='all' />
Statuses
| Status | Means | What to do |
|---|---|---|
| Pinned | Hashed, and pinned on the page | Nothing |
| hashed | Hashed but not pinned: pinning is off, the handle is excluded, or it is remote and remote pinning is off | Turn pinning on, or leave it |
| pending | Waiting for the background fetch | Wait, or reload the table |
| skipped: volatile | The host changes its code behind the same URL, so a pinned hash would break the page | Allow the host in the policy instead |
| skipped: no-cors | The host sends no CORS header, so the browser could not check a hash and would block the file | Leave it unpinned |
| skipped: too-large | Larger than 5 MB | Leave it unpinned |
| error | fetch-failed, http- and a status code, missing-file or unreadable | Check the URL, then Hash again |
Hovering a status shows the reason in words. Hosts treated as volatile include Google Tag Manager and Analytics, DoubleClick, Facebook, Hotjar, Segment, Intercom, Microsoft Clarity, LinkedIn, TikTok, HubSpot, Optimizely, Calendly and Stripe (js.stripe.com), matched with their subdomains.
Row actions
- Hash again hashes the selected files from disk at once, and queues remote ones for the next background run.
- Copy integrity copies the
sha384-…value. - Never pin and Allow pinning exclude a handle from pinning, or include it again.
The inventory keeps up to 300 assets and drops the least recently seen beyond that.