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

Open 💬 0 comments Opened Jul 2, 2026 by ludishur

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 ↗