secure-torch
Model Trust Gateway — Unified, defense-in-depth Python library for safely loading AI model files.
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)
| File | Size | Uploaded | |
|---|---|---|---|
| secure_torch-0.2.0.tar.gz | 33.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| 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 logRelease 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