Diff view gutter icons render as "tofu" (missing-glyph boxes) — webview CSP font-src is missing `data:`, blocking the embedded codicon font

Status Open
Reported on v2.1.198
Maintainer reply None cached
Activity 4 comments · opened Jul 2, 2026

Summary

In the VSCode extension, the chat webview's Content-Security-Policy font-src directive does not include data:. The extension embeds its codicon icon font as a data: URI @font-face, so the CSP blocks the font from loading. Every codicon rendered inside the webview then falls back to the "tofu" box (□ / ⊠).

The most visible symptom is the diff view: the insert/delete gutter signs on the left of every added/removed line show as broken boxes instead of + / .

Environment

  • OS: Ubuntu 26.04 LTS (Wayland)
  • VSCode: 1.126.0 (stable) and 1.127.0-insider — reproduces on both
  • Extension: anthropic.claude-code 2.1.198 (linux-x64)

Root cause (verified)

  1. webview/index.css embeds the codicon font as a data URI:

``css
@font-face{font-family:codicon;font-display:block;src:url(data:font/ttf;base64,AAEAAA...)}
`
The embedded font's charset covers
U+EA60–EC34 (+F101) and **does contain** the required glyphs. The diff icons are aliased to standard codicons in webview/index.js:
`js
sn("diff-insert", ue.add) // codicon-diff-insert -> add (+)
sn("diff-remove", ue.remove) // codicon-diff-remove -> remove (−)
``
So this is not a missing-glyph problem.

  1. The webview CSP assembled in extension.js is:

``
default-src 'none';
style-src ${cspSource} 'unsafe-inline';
font-src ${cspSource}; <-- no data:
img-src ${cspSource} data:; <-- has data:
script-src 'nonce-...';
worker-src ${cspSource};
`
img-src allows data: but font-src does not. Because the codicon @font-face uses a data:` URI, the browser blocks it under CSP → all webview codicons become tofu.

(Chrome DevTools on the webview shows a CSP violation:
Refused to load the font 'data:font/ttf;base64,...' because it violates the following Content Security Policy directive: "font-src <cspSource>".)

Fix

Add data: to the font-src directive, mirroring what img-src already does. In extension.js:

- font-src ${e.cspSource}
+ font-src ${e.cspSource} data:

Verification

Applying exactly that one change to extension.js and running Developer: Reload Window makes the diff insert/delete signs render correctly as + / . Confirmed on both the stable and Insiders installs.

Secondary note

There is a second, static CSP used by an HTML template ({{NONCE}} placeholder):

default-src 'none'; style-src 'unsafe-inline'; script-src 'nonce-{{NONCE}}'; img-src data:;

This one has no font-src at all, so under default-src 'none' any webview using this template would also fail to load a data: font. If any codicon-bearing webview uses it, it needs font-src data: too.

View original on GitHub ↗

4 Comments

silkfire · 1 month ago

I'm having the same issue and have had it since I started using the extension about 6 months ago. Strange that it hasn't been reported earlier.

Note the rectangles in the gutter.

<img width="1331" height="240" alt="Image" src="https://github.com/user-attachments/assets/97c75c79-444b-46cb-a251-9fe7423994e3" />

InChang-Youn · 1 month ago

Still reproduces on 2.1.220 (this issue and #51677 were filed against 2.1.116).

Environment: extension anthropic.claude-code 2.1.220 (win32-x64) · VS Code 1.130.0 · Windows 11 · claudeCode.preferredLocation: panel

Confirmed the CSP diagnosis against the shipped bundle:

  • webview/index.css embeds the font — @font-face { font-family: codicon; src: url(data:font/ttf;base64,…) }
  • and it does apply it — font: 16px/1 codicon is present (worth noting, since it's easy to miss: the rule uses the font: shorthand, not font-family:, so grepping for font-family:codicon gives a false negative and makes it look like the rule is missing)
  • but extension.js emits font-src ${cspSource} with no data:, so the embedded font is blocked before it can load

So the stylesheet is fine; only the font-src directive needs data: added.

Symptom detail that may help triage: the tofu box appears on changed lines only — context lines are clean, which is consistent with it being the Monaco codicon-diff-insert / codicon-diff-remove gutter indicators specifically:

⊠   "diffEditor.codeLens": true,      <- added line, box present
⊠   "editor.fontFamily": "Consolas…   <- added line, box present
    }                                  <- unchanged line, no box

Ruled out (in case others land here from a search): diffEditor.renderIndicators has no effect — it only governs VS Code's own diff editors, not the Monaco instance embedded in the webview. Likewise editor.fontFamily fallbacks, Developer: Reload Window, third-party extensions, and file encoding / invisible characters in the diffed files. There is no user-side workaround short of patching the extension.

MtkN1 · 1 month ago

Since #51677 was automatically closed as stale, I believe this issue should now serve as the active tracker for this bug.

donyxu · 5 days ago

Still reproduces on 2.1.246 (darwin-arm64) · VSCode 1.134.0 · macOS ·
claudeCode.preferredLocation: panel.

Patched locally as a workaround — adding data: to font-src in
extension.js:

q = font-src ${$.cspSource} data:

Reload Window → diff gutter icons render correctly. Confirms the diagnosis
still holds on the latest version and the one-line CSP fix is sufficient.