Security context
Low· 5.3GHSA-rrmf-rvhw-rf47 CVE-2025-3000CWE-119Published Mar 31, 2025

PyTorch is vulnerable to memory corruption through its torch.jit.script function

Research this vulnerability

Research is free — Hunters explains how the bug works, the root-cause code pattern, how the fix addresses it, and how to test whether a target is affected, in chat. Investigate & write exploit is a paid run — the engine reads the advisory and fix commits, then builds and validates a working proof-of-concept exploit with reproduction steps.

Affected versions

0 → fixed in 2.13.0

Details

A vulnerability classified as critical has been found in PyTorch 2.6.0. This affects the function torch.jit.script. The manipulation leads to memory corruption. It is possible to launch the attack on the local host. The exploit has been disclosed to the public and may be used.

The fix

[JIT] Reject bare `list`/`tuple` value annotations (#188779)

Nikita Shulga· Jul 2, 2026, 06:16 AM+442b90c94991c
test/jit/test_list_dict.py+20 0
@@ -57,6 +57,26 @@ def ternary_predicate(l: List[int]):
self.checkScript(ternary_predicate, ([1, 2, 3],))
self.checkScript(ternary_predicate, ([],))
+ def test_bare_container_annotation(self):
+ err = r"Attempted to use list without a contained type"
+
+ with self.assertRaisesRegex(RuntimeError, err):
+
+ @torch.jit.script
+ def bare_list_empty():
+ x: list = []
+ return x
+
+ # `isinstance` against a bare container is still valid (it is a
+ # type-erased runtime check, not a value's element type).
+ @torch.jit.script
+ def uses_isinstance(x: List[int]):
+ if isinstance(x, list):
+ return len(x)
+ return 0
+
+ self.assertEqual(uses_isinstance([1, 2, 3]), 3)
+
def test_in_check(self):
def int_in(x: List[int]) -> bool:
return 2 in x
torch/csrc/jit/frontend/ir_emitter.cpp+24 2
@@ -3104,6 +3104,28 @@ struct to_ir {
}
}
+ // Parse a value's declared type annotation. Bare `list`/`tuple` resolve to
+ // the type-erased AnyListType/AnyTupleType, which are only meaningful as
+ // `isinstance` targets, not as a value's element type. Reject them here (as
+ // is already done for `typing.List`/`typing.Tuple`) instead of letting them
+ // flow into the emitters, where they crash or produce confusing errors.
+ TypePtr parseTypeHintFromExpr(const Expr& type_expr) {
+ auto type = typeParser_.parseTypeFromExpr(type_expr);
+ const char* container = nullptr;
+ if (type->kind() == AnyListType::Kind) {
+ container = "list";
+ } else if (type->kind() == AnyTupleType::Kind) {
+ container = "tuple";
+ }
+ if (container) {
+ throw(
+ ErrorReport(type_expr)
+ << "Attempted to use " << container << " without a contained type. "
+ << "Please add a contained type, e.g. " << container << "[int]");
+ }
+ return type;
+ }
+
void emitSingleAssignment(const Assign& stmt) {
if (!stmt.rhs().present()) {
throw(
@@ -3116,7 +3138,7 @@ struct to_ir {
auto v = Var(stmt.lhs());
TypePtr type = nullptr;
if (stmt.type().present()) {
- type = typeParser_.parseTypeFromExpr(stmt.type().get());
+ type = parseTypeHintFromExpr(stmt.type().get());
}
auto rhs_sugared_val = emitSugaredExpr(rhs, 1, type);
// START BC HACK
@@ -3178,7 +3200,7 @@ struct to_ir {
TypePtr type_hint = nullptr;
if (stmt.type().present()) {
- type_hint = typeParser_.parseTypeFromExpr(stmt.type().get());
+ type_hint = parseTypeHintFromExpr(stmt.type().get());
}
const auto lhs = Select(stmt.lhs());
auto lhsObject = emitSugaredExpr(lhs.value(), 1);

References