If you use Aragon icons and your CSP is even slightly off, the breakage is usually annoying, subtle, and easy to misdiagnose. You see missing icons, blank squares, CSP console noise, or everything works locally but fails in production.
I’ve hit this enough times to have strong opinions about it: most CSP problems around icon libraries come from guessing which directive applies. People tweak default-src, maybe throw in img-src data:, and hope for the best. That’s not how CSP works.
Aragon icons can show up in a few different ways depending on your setup:
- inline SVG components
- external SVG files
- icon fonts
- CSS background images
- data URLs generated by a bundler
Each one is governed by different CSP directives. If you don’t map the delivery mechanism to the right directive, you end up fixing the wrong policy.
The first mistake: assuming all icons are covered by img-src
This is the classic one.
If your icons are rendered as inline SVG components in React or another framework, img-src may not matter at all. Inline SVG in the DOM is markup, not an external image fetch. If your icons come from CSS background-image, then img-src does matter. If they come from a font, font-src matters. If the icon package injects styles, style-src matters.
I see people start from a broad policy like this real-world example from headertest.com:
content-security-policy:
default-src 'self' https://www.googletagmanager.com https://*.cookiebot.com https://*.google-analytics.com;
script-src 'self' 'nonce-YzIxNGI2MjMtOWFkNS00NjZkLWIyOTctMWE4NDE1Y2E3NzZl' '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'
That looks decent overall, but for icons the detail that matters is this:
img-src 'self' data: https:;
font-src 'self';
style-src 'self' 'unsafe-inline' ...
If your Aragon icons are loaded from a CDN as SVG files, img-src 'self' is not enough. If they are served as fonts from another origin, font-src 'self' blocks them.
Fix
Figure out how the icons are actually delivered.
Examples:
Case 1: external SVG sprite or files from your own origin
Content-Security-Policy:
default-src 'self';
img-src 'self';
style-src 'self';
script-src 'self';
object-src 'none';
base-uri 'self';
Case 2: icons are fetched from a dedicated asset host
Content-Security-Policy:
default-src 'self';
img-src 'self' https://assets.example.com;
style-src 'self';
script-src 'self';
object-src 'none';
base-uri 'self';
Case 3: icon font hosted on a CDN
Content-Security-Policy:
default-src 'self';
style-src 'self';
font-src 'self' https://cdn.example.com;
object-src 'none';
base-uri 'self';
Don’t widen directives you don’t need. If the problem is fonts, fix font-src, not default-src.
For directive behavior and fallback rules, the official docs are worth checking: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
The second mistake: forgetting style-src when icons depend on CSS
A lot of teams think “icons are images” and stop there. But many icon systems rely on CSS classes, pseudo-elements, masks, or background images. Aragon-related UI packages can also bring styling assumptions with them depending on how you bundle components.
If your icons render through CSS and your CSP blocks the stylesheet, the icon never had a chance.
This gets uglier when a library injects styles at runtime. Then you’ll see CSP errors for inline styles even though you never wrote any inline CSS yourself.
Broken setup
Content-Security-Policy:
default-src 'self';
style-src 'self';
img-src 'self';
font-src 'self';
If your app injects a <style> tag during runtime for icon-related CSS, this may fail.
Common bad “fix”
style-src 'self' 'unsafe-inline';
Yes, this often makes the problem go away. No, I don’t recommend it unless you’ve consciously accepted the tradeoff. unsafe-inline is one of those shortcuts that sticks around for years because nobody comes back to remove it.
Better fix
Use nonces or hashes for inline styles if your stack supports them.
Content-Security-Policy:
default-src 'self';
style-src 'self' 'nonce-rAnd0m123';
img-src 'self' data:;
font-src 'self';
And in your HTML:
<style nonce="rAnd0m123">
.icon-mask {
mask-image: url('/icons/check.svg');
-webkit-mask-image: url('/icons/check.svg');
}
</style>
If the styles are static, hashes are even cleaner. Official reference: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/style-src
If you want a practical CSP breakdown by directive, https://csp-guide.com is useful.
The third mistake: blocking data: when your bundler inlines icons
Modern bundlers love inlining small assets. That includes SVGs. So your nice simple Aragon icon import can turn into a data: URL behind the scenes.
Example:
import warningIcon from './warning.svg'
document.querySelector('#status').innerHTML = `
<img src="${warningIcon}" alt="Warning">
`
In development, warningIcon may be a file path. In production, it may become something like:
data:image/svg+xml;base64,PHN2ZyB4bWxucz0i...
If your CSP says:
img-src 'self';
those icons break.
Fix
Allow data: for images if your build pipeline actually needs it.
Content-Security-Policy:
default-src 'self';
img-src 'self' data:;
This is one of the rare cases where broadening policy is often justified because the source is still controlled by your own build process.
That said, don’t cargo-cult data: into every directive. img-src data: can be reasonable. script-src data: is a terrible idea.
The fourth mistake: using icon fonts but only testing with cached assets
Icon fonts fail in a way that wastes time. If your browser cached the font before CSP tightened, everything looks fine until another user, browser profile, or deploy environment loads it fresh.
I’ve seen teams swear the CSP is correct because “it works for me,” while font-src is silently blocking in a clean session.
Broken setup
Content-Security-Policy:
default-src 'self';
style-src 'self' https://cdn.example.com;
font-src 'self';
If the CSS comes from your CDN and references woff2 files on the same CDN, those font requests are blocked.
Fix
Match the actual font origin.
Content-Security-Policy:
default-src 'self';
style-src 'self' https://cdn.example.com;
font-src 'self' https://cdn.example.com;
If the stylesheet and fonts live on different subdomains, list both. Don’t assume one allowlist entry magically covers every related request.
The fifth mistake: relying on default-src fallback and forgetting explicit directives
Yes, CSP has fallback behavior. No, you should not lean on it for something as visible as icons.
This policy:
Content-Security-Policy:
default-src 'self';
might technically cover some icon requests through fallback rules, but it becomes fragile the moment you add explicit directives elsewhere. Once you define img-src, font-src, or style-src, those take over for their resource types.
That means a policy can get stricter over time in surprising ways:
Content-Security-Policy:
default-src 'self';
img-src 'self' data:;
style-src 'self';
font-src 'self';
Now if Aragon icons switch from inline SVGs to a font-backed implementation during a package upgrade, they break immediately unless font-src is ready for that source.
Fix
Be explicit for the resource types your icon system uses today.
A solid starting point for self-hosted Aragon icons looks like this:
Content-Security-Policy:
default-src 'self';
script-src 'self';
style-src 'self';
img-src 'self' data:;
font-src 'self';
connect-src 'self';
object-src 'none';
base-uri 'self';
frame-ancestors 'none';
Then add origins only where they’re actually needed.
The sixth mistake: ignoring console errors because “only icons are broken”
That console error is the whole case file. Read it carefully.
Examples you might see:
Refused to load the image 'data:image/svg+xml;base64,...' because it violates the following Content Security Policy directive: "img-src 'self'".
or:
Refused to load the font 'https://cdn.example.com/icons.woff2' because it violates the following Content Security Policy directive: "font-src 'self'".
or:
Refused to apply inline style because it violates the following Content Security Policy directive: "style-src 'self'".
The browser usually tells you exactly which directive blocked the resource. Don’t guess. Don’t loosen three directives at once. Fix the one named in the error.
A practical policy for Aragon icons
If you self-host Aragon icons, avoid runtime style injection, and allow bundler-inlined SVGs, this is a sane baseline:
Content-Security-Policy:
default-src 'self';
script-src 'self';
style-src 'self';
img-src 'self' data:;
font-src 'self';
connect-src 'self';
object-src 'none';
base-uri 'self';
form-action 'self';
frame-ancestors 'none';
If you need a nonce-based script policy like the headertest.com example, keep that separate from icon troubleshooting. Icon rendering usually comes down to img-src, font-src, and style-src, not script-src.
What I’d check first
When Aragon icons fail under CSP, I go through this list:
- Are they inline SVG, external SVG, CSS background images, or fonts?
- Does the browser console name
img-src,font-src, orstyle-src? - Is the asset self-hosted, CDN-hosted, or inlined as
data:? - Is my bundler changing asset behavior between dev and prod?
- Am I “fixing” the issue with
unsafe-inlinewhen a nonce or hash would be better?
That usually gets to the answer fast.
If you want the official CSP reference, use the MDN docs: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
And if you want a directive-by-directive explanation with examples, https://csp-guide.com is handy.
The big takeaway: Aragon icons aren’t special. CSP still follows the same boring rules. The hard part is knowing whether your “icon” is actually an image, a font, a stylesheet side effect, or a data: URL in disguise. Once you identify that, the fix is usually one line.