~/posts/cesium-under-a-strict-csp

Cesium under a strict CSP: Viewer vs CesiumWidget

The satellite flight on this site said "3D rendering unavailable" in production only. Two CSP rules were the reason, and neither was about WebGL.

· 1 min read · written in English

In production, the satellite flight on this site showed "3D rendering unavailable on this device". Locally it worked. Production has a strict Content-Security-Policy:

text
script-src 'self'

That one line broke two separate things.

1. WebAssembly needs its own permission

Cesium decodes parts of its data with WebAssembly. Under script-src 'self', Chrome refuses to compile WASM. The fix is narrow and does not allow eval for JavaScript:

text
script-src 'self' 'wasm-unsafe-eval'

2. Viewer brings Knockout, and Knockout brings new Function

Cesium.Viewer is the batteries-included widget: timeline, animation dial, base-layer picker. Its UI binds through Knockout, which compiles bindings with new Function(). That is exactly what script-src 'self' exists to block, and I did not want to add unsafe-eval to the whole site for a few buttons I did not use.

CesiumWidget is the same globe without the Knockout widgets. In current Cesium it also has entities, so markers and ellipses still work:

ts
import { CesiumWidget, EllipsoidTerrainProvider } from 'cesium';

const viewer = new CesiumWidget(stage, {
  baseLayer: false,
  terrainProvider: new EllipsoidTerrainProvider(),
  requestRenderMode: true,
});

Lessons