Skip to main content

secure-torch

Model Trust Gateway — Unified, defense-in-depth Python library for safely loading AI model files.

CI PyPI Python License: Apache 2.0


What is secure-torch?

Loading third-party AI models is a supply chain risk. torch.load, ONNX Runtime, and safetensors have all been vectors for RCE, data exfiltration, and silent model tampering.

secure-torch is a Model Trust Enforcement Layer — not just a safe loader wrapper.

It adds what the ML ecosystem is missing:

Feature What it does
Signature verification Verify model provenance before loading (online + offline)
Trust policy enforcement Block models from untrusted publishers
Pickle opcode validation Inspect opcodes without executing — blocks RCE payloads
Sandbox isolation Load in restricted subprocess (seccomp on Linux)
Explainable threat scoring Named breakdown, not a magic number
SBOM parsing SPDX AI Profile support (experimental)

How it complements safetensors

safetensors solves unsafe deserialization and memory safety. secure-torch adds the trust layer on top — signature verification, publisher policy, and provenance validation — for safetensors, PyTorch pickle, and ONNX alike.


Quick Start

pip install secure-torch

Drop-in usage

import secure_torch as torch          # drop-in replacement

model = torch.load("model.pt")        # safe by default

Require a valid signature

model = torch.load(
    "model.pt",
    require_signature=True,
    bundle_path="model.pt.sigstore",  # online Rekor verification
)

Offline verification (enterprise / air-gapped)

model = torch.load(
    "model.pt",
    require_signature=True,
    pubkey_path="trusted.pub",        # Ed25519 public key
    bundle_path="model.pt.sig",       # raw signature bytes
)

Trusted publishers allowlist

model = torch.load(
    "model.pt",
    trusted_publishers=["huggingface.co/meta", "openai.com"],
)

Audit first, block later (gradual adoption)

model, report = torch.load("model.pt", audit_only=True)

print(report.threat_level)       # ThreatLevel.LOW
print(report.score_breakdown)    # {'unsigned_model': 40}
print(report.warnings)           # ['No signature bundle found']

Sandbox isolation

model = torch.load("model.pt", sandbox=True)
# Model loaded in restricted subprocess (strict exec/network blocking via seccomp on Linux)

Other compatibility surfaces

torch.jit.load("model.pt")  # secure pipeline for local artifacts
torch.hub.load("pytorch/vision", "resnet50")      # remote convenience passthrough
torch.from_pretrained("bert-base-uncased")        # remote convenience passthrough
torch.save(model, "model.pt")

torch.hub.load and direct torch.from_pretrained calls do not currently enforce secure-torch security checks for remote fetches. Passing security arguments (require_signature, trusted_publishers, audit_only, max_threat_score, sandbox, sbom_*, bundle_path, pubkey_path) raises SecurityError. For enforced security controls, download artifacts first and call torch.load(local_path, ...), or use secure_torch.patch_huggingface(...) for Hugging Face download interception.

Hugging Face integration (automatic download scanning)

import secure_torch
from transformers import AutoModel

# Global monkey-patch: intercept hf_hub_download and validate model files.
secure_torch.patch_huggingface(require_signature=False, max_threat_score=20)

model = AutoModel.from_pretrained("gpt2")

# Optional cleanup when done.
secure_torch.unpatch_huggingface()

patch_huggingface(...) hooks huggingface_hub.file_download.hf_hub_download. For model-like files (.pt, .pth, .bin, .safetensors, .onnx), secure-torch runs format detection, validators, signature/publisher checks, and threat policy evaluation before returning the downloaded file path. Unsafe artifacts are blocked with UnsafeModelError.

Interactive CLI audit

# Styled report (rich-enabled when available)
secure-torch audit model.pt

# Machine-readable output
secure-torch audit model.pt --json

Pipeline

Every secure_load() call runs this fixed pipeline — steps cannot be skipped:

secure_load(file)
  1. format detect        ← .safetensors / .pt / .onnx / magic bytes
  2. signature verify     ← fail fast if require_signature=True
  3. threat score         ← explainable named dict
  4. policy enforce       ← trusted_publishers check
  5. sandbox load         ← subprocess (+ seccomp on Linux)
  6. return tensors

Threat Scoring

Scores are named and explainable — not a magic number:

model, report = torch.load("model.pt", audit_only=True)
print(report.score_breakdown)
# {
#   'unsigned_model': 40,
#   'custom_ops_detected': 30,
#   'unknown_publisher': 20,
# }
# total: 90 → ThreatLevel.CRITICAL
Score Threat Level
0 SAFE
1–19 LOW
20–49 MEDIUM
50–79 HIGH
80+ CRITICAL

Default max_threat_score is 20 (MEDIUM). Adjust with max_threat_score=N.


SBOM Policy (Experimental)

Note: SPDX AI Profile is not yet widely adopted (early 2026). This feature is forward-looking — secure-torch is helping establish the standard.

from secure_torch.sbom.spdx_parser import parse_sbom
from secure_torch.sbom.opa_runner import OPAPolicyRunner

sbom = parse_sbom("model.spdx.json")
runner = OPAPolicyRunner("policy/production.rego")
denials = runner.evaluate(sbom, context={"environment": "production"})

if denials:
    raise RuntimeError(f"Policy violations: {denials}")

Example policy (policy/production.rego):

package secure_torch.policy

deny[msg] {
    input.sensitivePersonalInformation == "yes"
    msg := "Model contains sensitive personal information"
}

deny[msg] {
    ds := input.aiProfile.trainingDatasets[_]
    startswith(ds.license, "GPL")
    input.environment == "production"
    msg := sprintf("GPL dataset '%v' blocked in production", [ds.name])
}

Supported Formats

Format Validator Notes
.safetensors Header + dtype allowlist Complements safetensors library
.pt / .pth / .bin Pickle opcode validator Never executes pickle
.onnx Protobuf inspector Custom op domain detection

Signature Verification

Mode 1 — Online (Sigstore / Rekor)

# Sign your model
cosign sign-blob model.pt --bundle model.pt.sigstore

# Verify on load
torch.load("model.pt", require_signature=True, bundle_path="model.pt.sigstore")

Mode 2 — Offline (Ed25519 pubkey)

# Sign
openssl genpkey -algorithm ed25519 -out private.pem
openssl pkey -in private.pem -pubout -out public.pem
openssl pkeyutl -sign -inkey private.pem -in model.pt -out model.pt.sig

# Verify on load
torch.load("model.pt", require_signature=True, pubkey_path="public.pem", bundle_path="model.pt.sig")

CVE Coverage

CVE Attack Status
CVE-2023-44271 PyTorch pickle RCE (Salesforce) ✅ Blocked
GHSA-v9fq-2296 HuggingFace metadata injection ✅ Scored
CVE-2024-5980 NVIDIA Triton ONNX custom op RCE ✅ Scored

Installation

pip install secure-torch

# With ONNX support
pip install secure-torch[onnx]

# With Sigstore online verification
pip install secure-torch[sigstore]

# With offline public-key verification
pip install secure-torch[crypto]

# Everything
pip install secure-torch[all]

Development

git clone https://github.com/Avanishk05/secure-torch
cd secure-torch
pip install -e .
pip install pytest pytest-cov mypy ruff bandit
pytest tests/

License

Apache 2.0 — see LICENSE.

Release files for secure-torch 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for secure-torch 0.2.0
File Size Uploaded
secure_torch-0.2.0.tar.gz 33.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for secure-torch 0.2.0
File Interpreter ABI Platform
secure_torch-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 73.8 kB

Release files / secure_torch-0.2.0.tar.gz

Download URL secure_torch-0.2.0.tar.gz
Size 33.7 kB
Tags Source
SHA-256 checksum
How to use checksums
96c47115e7a2259b47f4dba352a81a6da635f4f0f21c09343375e678405fb380
BLAKE2b-256 checksum
How to use checksums
66da26b44083953aa2f03a117870a8180f7147b6792b874691c14f1a65735a9e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Feb 26, 2026.

Transparency log

Release files / secure_torch-0.2.0-py3-none-any.whl

Download URL secure_torch-0.2.0-py3-none-any.whl
Size 40.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e4e69fbf3b1f54750d68e281bf009fba3a0543feaf83eabddb86bd948e478a6e
BLAKE2b-256 checksum
How to use checksums
81606c55e54a9afb5588f53f1af5b091a178fd433d06a1ce7250ed08a9f58538
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Feb 26, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page