Log 20
Open in GitHub

Where Did My Textures Go? Loading GLBs on the Web

Why embedded GLB textures can be blocked by connect-src, and the CSP change that lets them load.

The model renders correctly in a glTF inspector, but its textures are missing in the app, even though the .glb request returns 200. In this case, Content Security Policy (CSP) blocked the embedded textures through connect-src.

How embedded images become textures

A GLB can store image bytes inside the file as bufferViews. In three.js r183, GLTFLoader loads those images through this path when using ImageBitmapLoader:

How embedded image bytes become a texture
N20-01
How embedded image bytes become a texturebufferViewBlobURL.createObjectURL()blob:https://…ImageBitmapLoaderfetch(blob:…)createImageBitmap()governed by connect-src

The key step is fetch(): ImageBitmapLoader uses it to read the temporary blob URL. The CSP specification puts that request under connect-src, even though the data becomes an image.

Allow blob requests in connect-src

Allowing blob: in img-src does not authorize that fetch() request:

img-src 'self' data: blob: https:;
connect-src 'self' https: wss:;

Add blob: to the existing connect-src directive:

- connect-src 'self' https: wss:;
+ connect-src 'self' blob: https: wss:;

Keep blob: in img-src too: when GLTFLoader uses its TextureLoader fallback, the image loads through an <img> element instead.

Check the console for a blocked blob: request under connect-src, then reload the page after updating the policy. A successful .glb response confirms the model file arrived; its textures can still fail to load.

Related Logs