Boxicons looks simple from the frontend side: drop in a stylesheet, use a class like bx bx-home, and move on. Then CSP shows up and your icons quietly disappear.
I’ve seen this happen a lot because Boxicons sits in an awkward spot for CSP. It’s “just icons,” but depending on how you load it, you may need to allow a stylesheet, font files, maybe images, and sometimes a CDN you forgot you were using. If your policy is tight — which it should be — Boxicons is exactly the kind of third-party asset that gets blocked first.
Here are the mistakes I see most often, and the fixes that actually work.
Mistake #1: Allowing the stylesheet but forgetting the font files
This is the classic one.
A lot of developers add Boxicons from a CDN like this:
<link
rel="stylesheet"
href="https://unpkg.com/[email protected]/css/boxicons.min.css"
/>
Then they update CSP:
Content-Security-Policy: default-src 'self'; style-src 'self' https://unpkg.com
The CSS loads, but the icons still don’t render.
Why? Because Boxicons uses font files referenced from inside that CSS. Your browser fetches the stylesheet first, then tries to load .woff, .woff2, or similar assets from the same CDN. If font-src doesn’t allow that origin, the icons fail.
Fix
Allow the CDN in both style-src and font-src:
Content-Security-Policy:
default-src 'self';
style-src 'self' https://unpkg.com;
font-src 'self' https://unpkg.com;
If you’re using jsDelivr instead:
Content-Security-Policy:
default-src 'self';
style-src 'self' https://cdn.jsdelivr.net;
font-src 'self' https://cdn.jsdelivr.net;
If you want to understand why different directives matter here, csp-guide.com is a good reference for directive behavior.
Mistake #2: Relying on default-src to cover fonts and styles
This one trips people up because default-src is a fallback, not a magic catch-all once you start defining specific directives.
You might write:
Content-Security-Policy:
default-src 'self' https://unpkg.com;
style-src 'self';
That does not mean styles can also come from unpkg.com. Since style-src is explicitly set, it overrides the fallback for styles. Same idea for font-src.
Fix
Be explicit for every resource type Boxicons needs:
Content-Security-Policy:
default-src 'self';
style-src 'self' https://unpkg.com;
font-src 'self' https://unpkg.com;
If you’re debugging this kind of issue, I usually check the actual response headers first with a tool like HeaderTest. It’s faster than guessing whether the browser is seeing the CSP you think you deployed.
Mistake #3: Using 'unsafe-inline' because the icons “need CSS”
They usually don’t.
I’ve seen teams loosen CSP like this after Boxicons breaks:
Content-Security-Policy:
default-src 'self';
style-src 'self' 'unsafe-inline' https://unpkg.com;
font-src 'self' https://unpkg.com;
That often “works,” but for the wrong reason. Boxicons from a CDN is usually just an external stylesheet plus external font files. You generally do not need 'unsafe-inline' for that.
'unsafe-inline' in style-src allows inline <style> blocks and style="" attributes, which expands your attack surface. If Boxicons is the reason you added it, you probably added too much.
Fix
Start with the narrow policy:
Content-Security-Policy:
default-src 'self';
style-src 'self' https://unpkg.com;
font-src 'self' https://unpkg.com;
Only add 'unsafe-inline' if your app genuinely uses inline styles and you can’t replace them with nonces, hashes, or external CSS.
For comparison, here’s a real CSP header from headertest.com:
content-security-policy: default-src 'self' https://www.googletagmanager.com https://*.cookiebot.com https://*.google-analytics.com; script-src 'self' 'nonce-OWJiMDU0M2YtNjk5OS00NWE1LWFmZmEtZWYwY2UxMjY3MzBh' 'strict-dynamic' https://www.googletagmanager.com https://*.cookiebot.com https://*.google-analytics.com; style-src 'self' 'unsafe-inline' https://www.googletagmanager.com https://*.cookiebot.com https://consent.cookiebot.com; img-src 'self' data: https:; font-src 'self'; connect-src 'self' https://api.headertest.com https://tallycdn.com https://or.headertest.com wss://or.headertest.com https://*.google-analytics.com https://*.googletagmanager.com https://*.cookiebot.com; frame-src 'self' https://consentcdn.cookiebot.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self'; object-src 'none'
Notice the pattern: resource types are separated intentionally. If Boxicons were added from a CDN, font-src would need to include that CDN too.
Mistake #4: Allowing the wrong Boxicons host
“Boxicons” is the library name, not the CSP source expression.
Your app might load Boxicons from:
unpkg.comcdn.jsdelivr.net- your own domain
- a framework asset pipeline
- a copied local file under
/assets
I’ve seen people write policies for boxicons.com even though nothing is loaded from there.
Fix
Open DevTools, reload the page, and inspect the actual request URLs.
If your HTML is:
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/[email protected]/css/boxicons.min.css"
/>
Then your CSP should match cdn.jsdelivr.net, not some guessed domain:
Content-Security-Policy:
default-src 'self';
style-src 'self' https://cdn.jsdelivr.net;
font-src 'self' https://cdn.jsdelivr.net;
CSP is literal. Close enough doesn’t count.
Mistake #5: Self-hosting the CSS but not the font files
This is the second most common Boxicons breakage I see.
You download boxicons.min.css, serve it from your own app, and feel good because now style-src 'self' should be enough. But the CSS still contains url(...) references pointing to wherever the package expected the fonts to live.
Example:
@font-face {
font-family: boxicons;
src: url("../fonts/boxicons.woff2") format("woff2");
}
If you copied only the CSS file and not the fonts/ directory, or changed the path structure, the browser gets a 404. CSP isn’t even the real problem at that point — the asset path is broken.
Fix
Self-host the whole asset set and verify the paths:
Content-Security-Policy:
default-src 'self';
style-src 'self';
font-src 'self';
Directory structure:
/public
/css
boxicons.min.css
/fonts
boxicons.woff2
boxicons.woff
If needed, update the URLs inside the CSS:
@font-face {
font-family: boxicons;
src: url("/fonts/boxicons.woff2") format("woff2"),
url("/fonts/boxicons.woff") format("woff");
}
Honestly, self-hosting is usually the cleanest Boxicons+CSP setup. Fewer third-party origins, fewer surprises.
Mistake #6: Forgetting data: if your icon setup includes embedded assets
This one is less common for Boxicons itself, but it shows up in real projects where icon systems get mixed together.
Your app may use Boxicons for fonts and also include SVGs or CSS assets with embedded data: URLs. If those are blocked, developers sometimes blame Boxicons because “icons are broken.”
Fix
Only if you actually need it, allow data: for the relevant directive. Commonly that’s img-src, not font-src:
Content-Security-Policy:
default-src 'self';
style-src 'self' https://unpkg.com;
font-src 'self' https://unpkg.com;
img-src 'self' data:;
Don’t add data: everywhere out of habit. Keep it scoped.
Mistake #7: Copying a CSP from another app without mapping dependencies
A production CSP is usually a living list of real dependencies, not a generic template.
For example, this real policy from headertest.com includes sources for Google Tag Manager, Cookiebot, analytics, API calls, and websockets. That makes sense for that app. It would make no sense to cargo-cult that whole header into a Boxicons-only site.
Fix
Map Boxicons to the smallest set of directives it needs.
For CDN-hosted Boxicons, that’s often enough:
Content-Security-Policy:
default-src 'self';
style-src 'self' https://unpkg.com;
font-src 'self' https://unpkg.com;
object-src 'none';
base-uri 'self';
frame-ancestors 'none';
For self-hosted Boxicons:
Content-Security-Policy:
default-src 'self';
style-src 'self';
font-src 'self';
object-src 'none';
base-uri 'self';
frame-ancestors 'none';
That’s much better than bloating the policy with unrelated third-party domains.
A practical Boxicons CSP checklist
If Boxicons is broken under CSP, I go through this list:
-
Check the exact stylesheet URL
unpkg.com?cdn.jsdelivr.net?- local file?
-
Check the font file requests in DevTools
- Are they blocked by CSP?
- Are they 404ing?
- Are they coming from the same origin as the CSS?
-
Make sure
style-srcallows the stylesheet origin -
Make sure
font-srcallows the font origin -
Remove
'unsafe-inline'unless something else actually needs it -
Prefer self-hosting if you want the simplest CSP
Good baseline policies
Boxicons from unpkg
Content-Security-Policy:
default-src 'self';
style-src 'self' https://unpkg.com;
font-src 'self' https://unpkg.com;
object-src 'none';
base-uri 'self';
frame-ancestors 'none';
Boxicons from jsDelivr
Content-Security-Policy:
default-src 'self';
style-src 'self' https://cdn.jsdelivr.net;
font-src 'self' https://cdn.jsdelivr.net;
object-src 'none';
base-uri 'self';
frame-ancestors 'none';
Self-hosted Boxicons
Content-Security-Policy:
default-src 'self';
style-src 'self';
font-src 'self';
object-src 'none';
base-uri 'self';
frame-ancestors 'none';
That’s really the whole game with Boxicons: know where the CSS comes from, know where the fonts come from, and whitelist exactly those origins. Most CSP problems here come from treating icon fonts like a single asset when they’re actually a small dependency chain. Once you account for that, Boxicons becomes boring again — which is exactly what you want from your security headers.