Sanitizing User-Uploaded glTF Models for Web Servers

Serving user-uploaded 3D assets like glTF (GL Transmission Format) and GLB files introduces significant security risks, ranging from path traversal and cross-site scripting (XSS) to denial-of-service (DoS) via decompression bombs. To safeguard your infrastructure and client browsers, web servers must systematically validate file structure, strip unapproved URIs, enforce resource limits, and sanitize metadata before distributing models to end users.

Prefer and Enforce Self-Contained GLB

glTF files can be distributed either as standalone JSON (.gltf) pointing to external bin/texture files, or as single, self-contained binary files (.glb).

  • Restrict uploads to GLB: Whenever possible, mandate the binary format (.glb). This avoids complex multi-file upload management, prevents external asset references, and confines all data chunks to a single stream.
  • Validate the GLB container header: Verify that the 12-byte header begins with the correct magic number (0x46546C67 for glTF), specifies version 2, and that the declared total length matches the exact byte length of the uploaded file.

Schema and Structural Validation

Do not rely solely on MIME types or file extensions, as they are trivially spoofed.

  • Khronos Schema Validation: Parse the internal JSON manifest and validate it strictly against the official Khronos glTF 2.0 JSON schema. Reject any files that fail structural compliance.
  • Chunk Order and Alignment: In GLB files, verify that the first chunk is strictly the JSON chunk (0x4E4F534A) and the optional second chunk is strictly the binary buffer (BIN\x00 / 0x004E4942). Discard files with unexpected trailing data or unaligned byte padding.

URI and Path Traversal Neutralization

When processing standard .gltf files or GLBs with image/buffer references:

  • Ban Local File Schemes: Explicitly disallow protocols like file://, blob:, javascript:, or absolute operating system paths.
  • Disallow External URIs: Strip or reject references to remote domains (http://, https://) to prevent your servers or users' browsers from being used for Server-Side Request Forgery (SSRF) or unauthorized outbound tracking.
  • Neutralize Path Traversal: If external assets are supported, normalize all relative paths and explicitly block directory traversal sequences (such as ../ and ..\). All referenced assets must resolve strictly within the designated temporary upload sandbox.
  • Data URI Sanitization: If data: URIs are permitted for textures, restrict them strictly to safe, non-executable MIME types (image/png, image/jpeg, image/webp).

Extension Whitelisting and Metadata Stripping

glTF supports arbitrary extensions (extensionsUsed, extensionsRequired) and custom metadata dictionaries (extras).

  • Whitelist Extensions: glTF allows custom extensions that may trigger unhandled parser behaviors. Compare all declared extensions against an explicit whitelist of supported Khronos/vendor extensions (such as KHR_materials_unlit or KHR_draco_mesh_compression). Reject files declaring unknown entries under extensionsRequired.
  • Sanitize extras Objects: The extras property can contain arbitrary JSON, which could be reflected into the client DOM and lead to Cross-Site Scripting (XSS). Recursively scrub HTML tags, script constructs, and control characters from string values, or completely drop extras if application-specific metadata is not required.

Resource Limits and Decompression Bomb Mitigation

Malicious models can easily freeze the user's browser, crash WebGL contexts, or exhaust server RAM.

  • Limit Geometry Complexity: Set hard ceilings on total triangle counts, vertex counts, and mesh primitive counts based on your target platform's performance thresholds.
  • Prevent Buffer Overlaps: Validate that buffer views (bufferViews) and accessors (accessors) reference non-overlapping, in-bounds memory ranges within the binary chunk to avoid out-of-bounds read vulnerabilities.
  • Inspect Texture Dimensions: Extract and inspect image headers without fully decompressing them into memory. Enforce limits on texture dimensions (e.g., maximum 4096×4096) and total texture count to prevent WebGL memory crashes.
  • Guard Against Draco Decompression Bombs: If Draco mesh compression is enabled, enforce an uncompressed size threshold before decoding to prevent zip-bomb-style CPU and memory exhaustion.

Normalization and Pipeline Re-encoding

The most robust sanitization strategy is to re-encode the file using a headless, isolated processor (such as @gltf-transform/core).

  • Run the file through an automated headless pipeline in an isolated, short-lived container.
  • Unpack the model, validate components programmatically, discard unapproved nodes and attributes, and serialize the model into a freshly generated GLB file.
  • Discard the original uploaded binary entirely, ensuring that malformed payloads or exploit attempts targeting WebGL parsers are neutralized during the transformation step.

Safe Web Server Delivery

Once the model is cleaned and stored, configure your delivery infrastructure defensively:

  • Content-Type Headers: Serve .glb files with model/gltf-binary and .gltf files with model/gltf+json.
  • Security Headers: Enforce X-Content-Type-Options: nosniff to stop browsers from interpreting JSON or binary chunks as executable HTML or JavaScript.
  • Isolated Origins: Host user-generated models on a separate, dedicated media domain (e.g., user-assets.example.com) without session cookies.
  • Content Security Policy (CSP): Ensure the rendering environment's CSP restricts connect-src and img-src to prevent client-side WebGL loaders from making unapproved outbound network requests.