Cross-Origin Security Restrictions in WebGL
WebGL enforces strict security boundaries governed by the Same-Origin Policy (SOP) and Cross-Origin Resource Sharing (CORS) mechanisms to prevent malicious websites from extracting sensitive data across domains. Because WebGL allows direct GPU access and programmatic reading of pixel data, unauthorized cross-origin images, videos, and canvas elements are strictly barred from being uploaded as textures without explicit cryptographic and server authorization.
The Core Threat: Information Leakage
In a standard HTML context, browsers allow elements like
<img> to render cross-origin resources without CORS.
However, WebGL fundamentally changes the security equation. Fragment
shaders can inspect, sample, and manipulate pixel values directly, and
operations like gl.readPixels() allow raw graphical memory
to be extracted back into JavaScript.
Without restrictions, an attacker could load a sensitive document—such as a user's webmail inbox, banking dashboard, or intranet portal—into a WebGL texture and use shaders to read the text and imagery byte-by-byte. Even without direct pixel-read APIs, subtle timing attacks on GPU execution times can infer the content of loaded images.
Canvas Tainting vs. WebGL Execution Blocks
The standard HTML5 2D Canvas allows untrusted cross-origin images to
be drawn, but it applies a "tainted" flag that permanently disables
methods like toDataURL(), toBlob(), or
getImageData().
WebGL adopts a stricter posture:
- WebGL completely refuses to load a cross-origin element into texture
memory using
texImage2DortexSubImage2Dunless proper CORS validation has occurred. - If an application attempts to pass an untrusted cross-origin source
into a WebGL context, the browser immediately throws a
SECURITY_ERRDOM exception, halting the texture upload entirely.
CORS Requirements for Textures
To load an external visual resource—such as an image or video hosted on a Content Delivery Network (CDN)—into a WebGL texture, two criteria must be satisfied:
- Client-Side Declaration: The HTML element must
explicitly request cross-origin privileges before the asset begins
loading. This is achieved by setting the
crossOriginproperty:const image = new Image(); image.crossOrigin = "anonymous"; image.src = "https://cdn.example.com/texture.jpg"; - Server-Side Authorization: The remote server
hosting the asset must respond to the HTTP request with the appropriate
CORS header:
Or explicitly specify the requesting origin:Access-Control-Allow-Origin: *Access-Control-Allow-Origin: https://yourdomain.com
If the server omits this header or explicitly rejects the origin, the
image will trigger an onerror event, and passing it to
gl.texImage2D() will fail.
Redirects and HTTP Caching Pitfalls
Browsers cache resources based on their request headers. If an image
is first loaded by an ordinary <img> tag without the
crossorigin attribute, the browser may cache the response
without CORS headers. If WebGL later attempts to load the same asset
with crossOrigin = "anonymous", the browser might serve the
cached version lacking the Access-Control-Allow-Origin
header, causing an unexpected security failure. Assets intended for
WebGL textures must consistently use CORS headers across all requests or
be served with appropriate Vary: Origin HTTP headers.