Skip to content

[PATCH] validateExternalUri strict-mode regex susceptible to catastrophic backtracking on adversarial input #351

@ormidales

Description

@ormidales

Category: security
Severity: patch
File(s): src/core/GltfLoader.ts (validateExternalUri)

Description

The strict-mode allowlist regex /^[A-Za-z0-9._\-/]+$/ is applied to both the raw URI and its decoded form via candidates.every(…). For typical inputs this is benign, but the regex engine on some JS runtimes exhibits non-linear backtracking when the input contains many alternating allowed/disallowed characters (e.g. a 10 000-character string of a.). Since validateExternalUri is called inside resolveBuffers for every buffer entry in a glTF asset, a malformed asset can trigger this in a loop.

Problematic code example

// src/core/GltfLoader.ts — validateExternalUri
if (strict && !candidates.every((v) => /^[A-Za-z0-9._\-/]+$/.test(v))) {
  throw new Error();
}

Suggested fix

Add an explicit length cap before running the regex to bound execution time regardless of input content.

const MAX_URI_LENGTH = 2048;
if (strict) {
  if (candidates.some((v) => v.length > MAX_URI_LENGTH)) {
    throw new Error(`Buffer ${bufferIndex}: URI exceeds maximum allowed length in strict mode.`);
  }
  if (!candidates.every((v) => /^[A-Za-z0-9._\-/]+$/.test(v))) {
    throw new Error();
  }
}

Acceptance criteria

  • A URI length cap (e.g. 2048 characters) is enforced before the strict-mode regex runs
  • A unit test confirms that a URI longer than the cap is rejected in strict mode
  • Non-strict mode is unaffected

Metadata

Metadata

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions