Triple-Stage AI Attack Chain Hits PyTorch

Black Hat Asia 2026 demo turns PyTorch TorchScript as_strided heap underflow into RCE even with weights_only=True, and shows it against OpenSearch.

7 min read
Diagram of PyTorch TensorImpl and StorageImpl memory layout showing storage_offset underflow
Black Hat Asia 2026 researchers mapped PyTorch memory to exploit as_strided for RCE.· BlackHat
Visual TL;DR
Untrusted PyTorch model fileDriver
an attacker supplied torch checkpoint opened by a victim application
From the article 6 mentionsTwo independent researchers demoed a triple-stage AI attack chain at Black Hat Asia 2026 that turns a PyTorch model file into remote code execution even with weights_only set to True.
Triple-stage exploit chainCore
model file to memory corruption to remote code execution in three linked steps
From the articleTwo independent researchers demoed a triple-stage AI attack chain at Black Hat Asia 2026 that turns a PyTorch model file into remote code execution even with weights_only set to True.
OpenSearch demo compromiseOutcome
researchers demonstrated the full chain against a live OpenSearch deployment on stage
torch.load with weights_only=TrueContext
mode docs called secure but still dispatches to torch.jit.load on TorchScript
From the article 5 mentionsThe researchers found torch.load with weights_only=True still calls torch.jit.load if the file is TorchScript format, and TorchScript exposes high-risk operators like torch.save and torch.from_file.
TorchScript as_strided bugDriver
C++ memory safety underflow in the as_strided operator exposed to loading path
From the articleCalling the API directly in Python reproduced the bug, but saving it via forward into a TorchScript file and reloading with torch.load with weights_only True initially hid it.
Untrusted PyTorch model fileDriver
an attacker supplied torch checkpoint opened by a victim application
From the article 6 mentionsTwo independent researchers demoed a triple-stage AI attack chain at Black Hat Asia 2026 that turns a PyTorch model file into remote code execution even with weights_only set to True.
torch.load with weights_only=TrueContext
mode docs called secure but still dispatches to torch.jit.load on TorchScript
From the article 5 mentionsThe researchers found torch.load with weights_only=True still calls torch.jit.load if the file is TorchScript format, and TorchScript exposes high-risk operators like torch.save and torch.from_file.
TorchScript as_strided bugDriver
C++ memory safety underflow in the as_strided operator exposed to loading path
From the articleCalling the API directly in Python reproduced the bug, but saving it via forward into a TorchScript file and reloading with torch.load with weights_only True initially hid it.
Heap underflow primitiveEffect
attacker controls arbitrary read and write over process memory via crafted strides
From the articleA second check rejects storage_offset less than zero, which is why minus 1 fails but 2^62 minus 1 succeeds and returns 0x41, the glibc heap chunk header, confirming an underflow.
Triple-stage exploit chainCore
model file to memory corruption to remote code execution in three linked steps
From the articleTwo independent researchers demoed a triple-stage AI attack chain at Black Hat Asia 2026 that turns a PyTorch model file into remote code execution even with weights_only set to True.
Initial PoC failsEffect
model serialization changes broke the researchers first weaponized proof of concept
RCE via native gadgetsOutcome
researchers pivoted from pickle RCE to native code execution through the underflow primitive
OpenSearch demo compromiseOutcome
researchers demonstrated the full chain against a live OpenSearch deployment on stage
Contents(8)

Two independent researchers demoed a triple-stage AI attack chain at Black Hat Asia 2026 that turns a PyTorch model file into remote code execution even with weights_only set to True.

Triple-Stage AI Attack Chain Hits PyTorch - BlackHat
Triple-Stage AI Attack Chain Hits PyTorch, from BlackHat

Presentation by researchers Lulay and Georgian was billed as model files to memory corruption to RCE and builds on their Black Hat USA 2025 work according to BlackHat.

What was the flawed assumption in torch.load?

Early PyTorch used pickle.load inside torch.load, so loading an untrusted checkpoint meant arbitrary code execution.

PyTorch added weights_only=True to load only clean weights and its docs at the time called that mode secure.

The researchers found torch.load with weights_only=True still calls torch.jit.load if the file is TorchScript format, and TorchScript exposes high-risk operators like torch.save and torch.from_file.

How does a memory bug survive a supposedly safe path?

Prior flaws were deserialization bugs in pickle and Keras, but the team hunted for C++ memory safety bugs in TorchScript operators instead.

They flagged functions taking offset or index parameters as likely to touch memory directly without proper bounds checks.

The target they chose is PyTorch (NYSE:PYTO) adjacent operator torch.as_strided, which takes tensor, size, stride and storage_offset.

How does as_strided turn into an exploit?

With six int64 elements the normal path computes 6 times 8 equals 48 bytes for size and 1 times 8 equals 8 for offset and correctly rejects out-of-bounds.

Passing 2 to the power of 62 as offset causes 2^62 times 8 to overflow to minus 8, so 48 plus minus 8 passes the check_in_bounds_for_storage check.

A second check rejects storage_offset less than zero, which is why minus 1 fails but 2^62 minus 1 succeeds and returns 0x41, the glibc heap chunk header, confirming an underflow.

What does the primitive actually allow?

The overflow value is stored as storage_offset in TensorImpl while StorageImpl still points to the real storage, so the new tensor reads and writes before its allocation.

That gives an out-of-bounds read to leak heap and library addresses and an out-of-bounds write to overwrite the weak table and function pointers.

The team then searches heap spray for StorageImpl by matching patterns like heap size 0x61 and data_ptr equals c10_ptr and uses the vtable and destructor pointers into libtorch_python.so and libc.so to locate system.

Why did model serialization break the PoC at first?

Calling the API directly in Python reproduced the bug, but saving it via forward into a TorchScript file and reloading with torch.load with weights_only True initially hid it.

The model file contained only the vulnerable call because TorchScript applies dead code elimination similar to V8 and drops unused tensors.

Adding a use of each heap spray tensor, such as printing its shape, preserved the objects in the serialized file and made the spray searchable in GDB again.

Why could Amazon (NASDAQ:AMZN) OpenSearch be hijacked?

OpenSearch is an open source search and observability platform that supports AI features and, as of version 2.4 to 2.5, loads models only as TorchScript or ONNX zip bundles.

The researchers deployed it with Docker Compose, enabled allow_registering_model_via_url and disabled only_run_on_ml_node, then registered a model group and zipped a minimal TorchScript model that asserts to leak errors.

Using torch.load from_file with a large length leaked etc passwd length 589 with full content, and the same as_strided underflow leaked tensor data through error messages.

Why did RCE fail there and what worked instead?

The classic overwrite of the destructor to call system was blocked by a syscall filter that bans execve and fork, so the command never executed even after stepping into system in GDB.

The team pivoted to file reads with open, read, write and used getdents plus write syscalls to dump files without the dirty data that torch.save adds.

They noted Amazon (NASDAQ:AMZN) managed OpenSearch was not affected because it does not allow allow_registering_model_via_url changes, and the open source maintainers responded that TorchScript is documented as unsafe and the risky options are off by default.

What actually fixes it?

Do not load untrusted models even with weights_only True, and enforce permission controls on who can register or deploy models.

Media inference servers using a PyTorch backend with TorchScript have the same exposure if they allow custom models.

For founders the lesson is narrow: as deserialization guards improve, the next wave is C++ operator memory bugs, and any product that hot-loads community models from Hugging Face inherits that risk until it sandboxes or validates at the syscall level.

© 2026 StartupHub.ai. All rights reserved. Do not enter, scrape, copy, reproduce, or republish this article in whole or in part. Use as input to AI training, fine-tuning, retrieval-augmented generation, or any machine-learning system is prohibited without written license. Substantially-similar derivative works will be pursued to the fullest extent of applicable copyright, database, and computer-misuse laws. See our terms.