Back to Blog
critical SEVERITY4 min read

Model Fetching Without Integrity Verification in ONNX Loading

A machine learning application was fetching ONNX model files and chunks over the network without verifying their integrity, creating an opening for model poisoning attacks. The fix adds cryptographic integrity verification at the point where downloaded chunks are reassembled and cached, ensuring models have not been modified in transit or at rest.

O
By Orbis AppSec
•Published October 1, 2026•Reviewed October 1, 2026

Answer Summary

The affected code fetches ONNX model chunks and entire models using the Fetch API without verifying their cryptographic integrity. An attacker intercepting network traffic or compromising a cache storage layer could modify model weights in flight, causing the application to run a poisoned model without detection. The fix adds integrity verification calls after chunk reassembly and cache retrieval, using a dedicated model integrity validation function. CWE is unknown.

Vulnerability at a Glance

cweN/A
fixAdded cryptographic integrity verification function called on all fetched and cached model buffers
riskDownloaded ML models could be silently modified, leading to model poisoning and arbitrary behavior change
languageJavaScript
root causeFetch calls for model chunks and cached models lack integrity verification before use
vulnerabilityMissing Subresource Integrity (SRI) and cryptographic signature verification on downloaded machine learning models

The Vulnerability Explained

A machine learning application was fetching ONNX model files and model chunks using the browser's Fetch API without any cryptographic verification. The vulnerable code path looked like this:

// Vulnerable: no integrity check
return combined.buffer; // Return the final ArrayBuffer

and:

// Vulnerable: no verification of cached model
if (cachedResponse) {
  log("Using cached model");
  return await cachedResponse.arrayBuffer();
}

The problem is clear: after downloading model chunks or retrieving them from cache storage, the application immediately used them without verifying that the bytes matched an expected cryptographic hash or signature. This created two attack surfaces:

  1. Network-level tampering: An attacker on the network path (via MITM, DNS poisoning, or BGP hijacking) could intercept the fetch request and return a modified model.
  2. Cache poisoning: An attacker with write access to the browser's cache storage could swap out a legitimate model with a poisoned one, and the application would use it without question.

The impact is severe: a poisoned ONNX model runs arbitrary computation on the host's hardware. An attacker could:
- Exfiltrate input data (images, audio, user-submitted content) sent to the model.
- Produce incorrect outputs to bias application decisions (e.g., if this is a classification or detection model).
- Use the inference process as a side-channel to leak information about the host device.

Affected Versions

Affected not applicable (first-party code)
Fixed in not applicable (first-party code)
Ecosystem N/A
CVE / GHSA not assigned
CWE unknown

This vulnerability was present in the application's model-loading helper functions. The fix was applied directly to the codebase.

The Fix

The fix introduces a new integrity verification step at two critical junctures: after chunks are reassembled, and after a cached model is retrieved. Here's what changed:

After chunk reassembly:

// Fixed: integrity verification applied
return verifyModelIntegrity(combined.buffer, MODEL_PATH);

After cache retrieval:

// Fixed: verify cached model before use
if (cachedResponse) {
  log("Using cached model");
  return verifyModelIntegrity(
    await cachedResponse.arrayBuffer(),
    MODEL_PATH
  );
}

The verifyModelIntegrity() function is imported from a dedicated integrity module and checks the downloaded buffer against a cryptographic hash derived from MODEL_PATH. The key insight in the implementation is that chunks are byte-sequential splits of the original model file, so the expected integrity hash is always tied to MODEL_PATH, regardless of which directory or cache the chunks were fetched from. This prevents an attacker from substituting chunks from a different model and having them pass verification.

By calling verifyModelIntegrity() immediately after every fetch or cache operation, the application ensures that:
- Any modification in transit is detected before the model reaches inference code.
- Cache poisoning attempts are caught at retrieval time.
- The integrity check is performed consistently across all model-loading paths.

Key Takeaways

  • Never trust downloaded ML models without verification: The fetch() API does not provide integrity guarantees. Always verify downloaded models against a known cryptographic hash before use, especially when models are the decision-making component of an application.

  • Chunks and caches need the same integrity checks: It is easy to assume a cached model is "already trusted," but cache storage is writable and can be targeted by attackers with local access. Apply integrity verification uniformly on all code paths that return model buffers, not just fresh downloads.

  • Integrity verification must happen before model inference: The verification call must be positioned after all network and cache operations but before the buffer is passed to the ML inference engine. A single path bypass compromises the entire defense.

  • Split models still need unified identity verification: When a model is split into multiple chunks for efficient download, the integrity verification must check against the complete original file hash, not individual chunks. This prevents an attacker from substituting a different model's chunks.

How Orbis AppSec Detected This

Source: The model buffer returned by the fetchAndCombineChunks() function and the cachedResponse.arrayBuffer() call in the cache retrieval path.

Sink: The return statements that hand the model buffer to the calling code without verification, and ultimately to ONNX inference APIs.

Missing control: No cryptographic integrity check (SRI hash, signature, or HMAC) was performed on the fetched or cached model data before it was used.

CWE: Unknown (related to lack of cryptographic signature verification on critical data).

Fix: Added calls to verifyModelIntegrity() before every return of a model buffer, ensuring the downloaded or cached bytes match an expected cryptographic identity.

Orbis AppSec automatically detected this vulnerability and opened a pull request with the fix. Try Orbis AppSec on your repositories to find and fix issues like this automatically.

Conclusion

Machine learning models are data with consequences. When they are downloaded or cached, they must be verified with the same rigor you would apply to code signatures or executable checksums. This vulnerability shows how easy it is to overlook integrity verification in the model-loading path—especially when chunks and caches create multiple code paths that can return model data. The fix ensures that every model, whether freshly downloaded, reassembled from chunks, or loaded from cache, is cryptographically verified before it reaches inference code. For developers building ML applications, this is a critical pattern to adopt: integrity verification on all external data sources, applied consistently and early.

Prevention and further reading

Frequently Asked Questions

What happens if a model is modified after being cached but before the integrity check?

The modified model will be detected at the point the integrity verification function is called, either immediately after reassembly or immediately after cache retrieval. The integrity check uses the expected model path as the verification identity, so any deviation will be caught before the model is passed to the ML inference engine.

Why does the fix always verify against MODEL_PATH regardless of which directory chunks were fetched from?

The model is split into byte-sequential shards, so the cryptographic identity is tied to the complete MODEL_PATH file, not the directory structure. Chunks from any source that are reassembled must match the original MODEL_PATH's integrity hash, preventing an attacker from substituting chunks from a different model or directory.

Does this fix affect the public API of the model-loading functions?

No. The functions `fetchAndCombineChunks()` and `cacheModelChunks()` return the same ArrayBuffer type before and after. The fix is internal — the integrity verification is transparent to callers, they receive the same data type but with guaranteed authenticity.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #3

Related Articles

high

nanoid 3.3.11 Integer Overflow: Predictable ID Generation

An integer overflow in nanoid 3.3.11's internal randomness generation causes the library to fall back to predictable ID sequences, undermining the cryptographic guarantees of its supposedly unguessable identifiers. The fix upgrades the dependency tree to patched versions 3.3.12 or 5.1.11.

high

generateUUID() Ditches MD5 for SHA-256 to Fix CWE-328

The `generateUUID()` helper built request-identifying UUIDs by hashing an input string with MD5, a cryptographically broken algorithm susceptible to collisions. The fix swaps the hash function for SHA-256, reducing the chance that two different inputs produce the same generated identifier.

high

API_URL Defaults to HTTP Without HTTPS Enforcement

An API client defaults to unencrypted HTTP connections, leaving all API communications—including sensitive project data—vulnerable to interception. Although an `upgradeToHttps()` helper function existed, it was applied inconsistently across the codebase. The fix ensures HTTPS enforcement is applied uniformly before every HTTP request.

high

HTTP Client `danger_accept_invalid_certs` Permitted MITM Credential

The HTTP client's `validate_certs` parameter allowed disabling TLS certificate validation through `danger_accept_invalid_certs(true)`, exposing Basic Auth credentials to interception. The fix replaces this dangerous capability with a hard error, forcing developers to use proper certificate management instead.

critical

JWT Authentication Disabled Signature Validation in

A critical misconfiguration in JWT authentication explicitly disabled signature validation, allowing attackers to forge valid tokens with arbitrary claims and bypass authentication entirely. The fix re-enables signature validation on all incoming bearer tokens, restoring the security boundary of the authentication layer.

critical

i18next-fs-backend 2.6.4 Prototype Pollution via Crafted Missing-Key

A critical prototype pollution vulnerability in i18next-fs-backend 2.6.4 allows attackers to modify Object.prototype through maliciously crafted translation key strings. The fix upgrades the package from 2.6.4 to 2.6.6, eliminating the unsafe key handling that permitted this attack vector.