crowdsecurity/crowdsec · critical

failed to decompress obfuscator wasm

Error message

failed to decompress obfuscator wasm: %w

What it means

This error is returned by compileObfuscatorModule when io.ReadAll on the gzip reader of the embedded obfuscator WASM fails mid-stream. The gzip header was valid but the payload is truncated or corrupt. It is raised once (guarded by sync.Once) during NewChallengeRuntime.

Solutions

  1. Rebuild and redeploy the crowdsec binary from a clean source tree (make build).
  2. Compare the deployed binary checksum with a freshly built one to confirm corruption.
  3. Regenerate the embedded obfuscator wasm asset with the project build tooling.
  4. If reproducible in a clean build, report upstream with the wrapped gzip error.
Defensive patterns

Strategy: try-catch

Validate before calling

// Decompress fully in a test to detect truncation
if _, err := io.ReadAll(mustGzipReader(obfuscatorWasmGz)); err != nil {
    t.Fatalf("embedded wasm truncated: %v", err)
}

Try / catch

if _, err := io.ReadAll(zr); err != nil { return fmt.Errorf("failed to decompress obfuscator wasm: %w", err) }

Prevention

When it happens

Trigger: Calling NewChallengeRuntime/Configure when reading the decompressed obfuscatorWasmGz stream fails — truncated embedded asset, bit rot in the binary, or corrupted memory of the byte slice.

Common situations: Truncated binaries from interrupted downloads/deploys; corrupted embedded assets in a custom build; running a binary damaged by disk issues.

Understand the failure class

Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.

Related errors


AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06). Data as JSON: /api/errors/e3589b4c9ff8e378. Report an issue: GitHub.

Appendix: source

Thrown at pkg/appsec/challenge/challenge.go:324

// all appsec runners. Pass WithXxx options to override defaults.
// compileObfuscatorModule decompresses the baked-in obfuscator WASM (once,
// process-wide) and compiles it for the given runtime. Pre-compiling lets each
// ObfuscateJS call merely instantiate the module instead of re-parsing the WASM
// bytes, which would otherwise cost ~4-5s per call.
func compileObfuscatorModule(ctx context.Context, r wazero.Runtime) (wazero.CompiledModule, error) {
	var obfuscatorWasmErr error

	obfuscatorWasmOnce.Do(func() {
		zr, err := gzip.NewReader(bytes.NewReader(obfuscatorWasmGz))
		if err != nil {
			obfuscatorWasmErr = fmt.Errorf("failed to create gzip reader for obfuscator wasm: %w", err)
			return
		}
		defer zr.Close()

		obfuscatorWasm, err = io.ReadAll(zr)
		if err != nil {
			obfuscatorWasmErr = fmt.Errorf("failed to decompress obfuscator wasm: %w", err)
			return
		}
	})

	if obfuscatorWasmErr != nil {
		return nil, obfuscatorWasmErr
	}

	compiledMod, err := r.CompileModule(ctx, obfuscatorWasm)
	if err != nil {
		return nil, fmt.Errorf("failed to compile obfuscator wasm module: %w", err)
	}

	return compiledMod, nil
}

// compilerSupported mimics the check performed by wazero for SSE4.1
// We cannot rely in wazero on the wazero check, as it is used to choose whether to use the compiler or interpreter mode

View on GitHub (pinned to 909b515798)