CSP violation during KTX2 decoder load

Good day, all!

We tried to remove unsafe-eval from our CSP header and start facing this issue

Error

Failed to load KTX2 texture data: Error: KTX2 container - could not transcode the data. EvalError: Refused to evaluate a string as JavaScript because ‘unsafe-eval’ is not an allowed source of script in the following Content Security Policy…

Would be really nice to have safe version of this transcoder. I saw that we can specify url, but I don’t know where I can find safe version.

Place where violated script is loaded: Babylon.js/packages/tools/ktx2Decoder/src/Transcoders/mscTranscoder.ts at 58b580163165b836a89efa39f3978c8618bb90b4 · BabylonJS/Babylon.js · GitHub

P.S.: Related issue? web - Chrome extension refused to evaluate a string as JavaScript because 'unsafe-eval' in emscripten generated file - Stack Overflow

good day!

I am not sure at what point you get the error, and i will be really happy to see a reproduction.
Just as a note, there is an open draft PR that probably handles your use-case - it allows loading an external package (that we will provide) or provide the devs to inject the dependency themselves, so you don’t use our CDN at any point:

Preparation for the external dependencies package by RaananW · Pull Request #14773 · BabylonJS/Babylon.js (github.com)

1 Like

ktx2.zip (14.3 KB)

→ yarn/npm
→ yarn build
→ docker-compose up -d

→ Check console, you should see error

1 Like

Thanks, that’s very helpful. I’ll check it later today

1 Like

Sorry for a long delay! I was working on the architecture of the ktx2decoder package and just delayed answering this one.

The issue here is the URL we are creating from what some environment consider unsafe string (we generate the worker using a string converted to Blob). I didn’t try docker (because I don’t have docker installed), but on chrome it does work as expected. Anyhow, you can now avoid using our CDN and use the KTX2Decoder library yourself locally. There are a few changes to the architecture. Mainly:

  1. Add @babylonjs/ktx2decoder and vite-plugin-arraybuffer to your package.json
  2. add “worker.js”:
import * as KTX2Decoder from "@babylonjs/ktx2decoder";
import { workerFunction } from "@babylonjs/core/Misc/khronosTextureContainer2Worker";
import mscTranscoderJsModule from "@babylonjs/ktx2decoder/wasm/msc_basis_transcoder";
import { MSCTranscoder as jsMSCTranscoder } from "@babylonjs/ktx2decoder/Transcoders/mscTranscoder";
globalThis.KTX2DECODER = KTX2Decoder;
globalThis.MSC_TRANSCODER = undefined;
jsMSCTranscoder.JSModule = mscTranscoderJsModule;
workerFunction(KTX2Decoder);
  1. Change initScene.js:
import { Engine } from "@babylonjs/core/Engines/engine";
import { Scene } from "@babylonjs/core/scene";
import { Texture } from "@babylonjs/core/Materials/Textures/texture";
import wasmMSCTranscoder from "@babylonjs/ktx2decoder/wasm/msc_basis_transcoder.wasm?arraybuffer";
import {
  KhronosTextureContainer2,
} from "@babylonjs/core/Misc/khronosTextureContainer2";
import { AutoReleaseWorkerPool } from "@babylonjs/core/Misc/workerPool";
import { initializeWebWorker } from "@babylonjs/core/Misc/khronosTextureContainer2Worker";
import "@babylonjs/core/Materials/Textures/Loaders/ktxTextureLoader"

export function initScene(element) {
  const engine = new Engine(element);
  const scene = new Scene(engine);

  const agentPool = new AutoReleaseWorkerPool(4, () => {
    const worker = new Worker(new URL("./worker.js", import.meta.url), {
      type: "module",
    });
    return initializeWebWorker(worker, {
      wasmMSCTranscoder,
    });
  });

  const ktx2 = new KhronosTextureContainer2(engine, {
    workerPool: agentPool,
  });

  const texture = new Texture(
    "./2d_etc1s.ktx2",
    scene,
    false,
    true,
    Texture.TRILINEAR_SAMPLINGMODE,
    () => {
      console.log(texture);
    },
    (message, exception) => {
      console.error("Can't fetch texture", message, exception);
    }
  );
}

Since you sent a zip file and not a repo i couldn’t submit a PR to show the changes :slight_smile:

While working on that I also found a few things I can improve (and I will submit a PR). mainly, the worker code can be simpler.

This will only use local files, avoid using our cdn or any unsafe initialization of a worker.

2 Likes

No worries. Thanks for your work. I will try this change as soon as I can :wink:

1 Like