model-secure
v1.1.2
Published
Cryptographic signing and verification for AI model files. Prove your model hasn't been tampered with.
Downloads
233
Maintainers
Readme
model-secure
Cryptographic integrity for AI model files.
Sign your models. Verify they haven't been tampered with. Zero dependencies.
The Problem
- 23% of the top 1,000 Hugging Face models have been found compromised or containing hidden payloads
- $12B in estimated losses from model supply chain attacks in 2025
- Less than 5% of published models have any form of cryptographic signing
- Model files are downloaded and executed with full trust -- no integrity verification
model-secure fixes this. It signs model files with ECDSA P-256 and creates a portable manifest that travels with your model. Anyone with your public key can verify the model hasn't been tampered with.
Install
npm install -g model-secureOr as a library:
npm install model-secureQuick Start (CLI)
1. Generate keys
model-secure keygen --output ./keys/2. Sign a model directory
model-secure sign ./my-model/ \
--key ./keys/private.pem \
--name "llama-3-8b" \
--version "1.0.0" \
--format safetensors \
--framework transformers \
--signer "[email protected]"This creates .model-manifest.json in the model directory.
3. Verify a model
model-secure verify ./my-model/ --key ./keys/public.pemOutput:
VERIFIED -- model integrity confirmed
Model: llama-3-8b v1.0.0
Format: safetensors (transformers)
Files: 4 verified, 0 failed
Signed: 2026-03-29T12:00:00.000Z
Signer: [email protected]If tampered:
TAMPERED -- model integrity check FAILED
Model: llama-3-8b v1.0.0
Files: 3 verified, 1 FAILED
FAILED: model-00002-of-00004.safetensors
Expected: sha256:abc123...
Actual: sha256:def456...
DO NOT LOAD THIS MODEL4. Hash a single file
model-secure hash ./model.safetensors
# sha256:a1b2c3... model.safetensors5. Inspect a manifest
model-secure info ./my-model/Library API
const {
generateKeyPair,
hashFile,
signModel,
verifyModel,
verifyFiles,
createManifest,
loadManifest,
} = require('model-secure');generateKeyPair()
const { publicKey, privateKey } = generateKeyPair();
// Returns PEM-encoded ECDSA P-256 keyshashFile(filePath)
const hash = await hashFile('./model.safetensors');
// Returns SHA-256 hex string
// Uses streaming -- handles multi-GB files without loading into memorysignModel(options, privateKey)
const manifest = await signModel({
name: 'my-model',
version: '1.0.0',
format: 'safetensors',
framework: 'transformers',
signer_id: '[email protected]',
files: [
{ path: './model-00001.safetensors' },
{ path: './model-00002.safetensors' },
],
}, privateKey);verifyModel(manifest, publicKey)
const result = verifyModel(manifest, publicKey);
// { valid: true, model_name, model_version, signed_at, signer_id, files_count }verifyFiles(manifest, directory)
const result = await verifyFiles(manifest, './my-model/');
// { verified: true, results: [{ path, expected, actual, match }] }createManifest(directory, options, privateKey)
const manifest = await createManifest('./my-model/', {
name: 'my-model',
version: '1.0.0',
format: 'safetensors',
framework: 'transformers',
}, privateKey);
// Scans directory, hashes model files, signs, writes .model-manifest.jsonloadManifest(directory)
const manifest = loadManifest('./my-model/');Supported Formats
| Format | Extensions | Framework |
|--------|-----------|-----------|
| SafeTensors | .safetensors | Hugging Face Transformers |
| PyTorch | .bin, .pt, .pth | PyTorch |
| GGUF | .gguf | llama.cpp, Ollama |
| ONNX | .onnx | ONNX Runtime |
| TensorFlow | .pb, .h5, .keras, .tflite | TensorFlow / Keras |
How It Works
- Hashing: Each model file is hashed with SHA-256 using streaming (handles files of any size)
- Manifest: File hashes, model metadata, and timestamp are assembled into a canonical JSON manifest
- Signing: The manifest is signed with ECDSA P-256 (NIST FIPS 186-5) using IEEE P1363 format
- Verification: Anyone with the public key can verify the signature and re-hash files to confirm integrity
The .model-manifest.json file travels with the model. Upload it alongside your model files to Hugging Face, S3, or any model registry.
Why ECDSA P-256?
- NIST-approved, FIPS 186-5 compliant
- 128-bit security level
- Compact signatures (64 bytes)
- Hardware acceleration on modern CPUs
- Same algorithm used by TLS, code signing, and secure boot
Comparison with Sigstore
| | model-secure | Sigstore |
|---|---|---|
| Dependencies | Zero | 50+ (cosign, Rekor, Fulcio, CT log) |
| Setup | npm install | Install cosign + configure OIDC |
| Offline signing | Yes | No (requires Fulcio CA) |
| Manifest portability | JSON file travels with model | Signature stored in Rekor log |
| Language | Node.js (any platform) | Go binary |
| Verification | Single public key | Requires Rekor + CT log access |
| Model-specific metadata | Yes (format, framework, file list) | Generic blob signing |
Security
- ECDSA P-256 with SHA-256 (NIST FIPS 186-5)
- IEEE P1363 signature format with low-S normalization (prevents malleability)
- Canonical JSON serialization (RFC 8785) for deterministic signing
- Streaming file hashing (constant memory for any file size)
- No network calls -- fully offline operation
For more on securing AI infrastructure, see the OWASP MCP Security Cheat Sheet.
License
MIT -- Copyright (c) 2026 CyberSecAI Ltd
