ONNX-Stego is a Python proof-of-concept for hiding short authenticated messages
inside float32 ONNX model weights. It embeds bits in the least significant
mantissa bit of selected weights, while using modern authenticated encryption
for the hidden payload.
This project demonstrates that neural-network model files can act as covert carriers for authenticated messages, while preserving model validity and minimizing numerical impact. It provides a reproducible ONNX proof, cryptographic payload protection, and reference-based natural weight selection to emulate hiding inside fine-tuning noise.
The project is built for defensive research, watermarking experiments, provenance notes, and steganography analysis on neural-network artifacts.
This is a Side-Project created mainly because of https://github.com/X-3306/Project-Onyx
- The carrier is a real ML artifact: the payload is embedded in ordinary
.onnxweights, so the resulting file remains a valid model rather than a custom container disguised as one. - Cryptography is separated from steganography: the hidden bytes are protected with ChaCha20-Poly1305 before embedding. The model hides where the ciphertext is stored; the AEAD layer protects the message itself.
- Positions are keyed and reproducible: sender and receiver derive the same embedding positions from the master key using a ChaCha20-backed deterministic CSPRNG with unbiased sampling. (Header positions are static per master key, payload positions are re-rerived per message from the master key and a fresh per-message salt)
- Reference-aware embedding is supported: natural selection can restrict writes to weights that already differ from a reference model, matching the practical "hide inside fine-tuning changes" threat model.
- ONNX storage details are handled explicitly: the implementation supports
both
raw_dataandfloat_data, and normalizes weight bytes as little-endianfloat32before touching mantissa bits. - The proof is measurable: tests and scripts check extraction, wrong-key rejection, tamper detection, ONNX validity, simple LSB statistics, and inference drift.
READ SECURITY.md for better understanding implementation, security and known-limitations.
- Generate a 256-bit master key.
- Inspect the available
float32LSB capacity of an ONNX model. - Embed text messages into ONNX
float32weights. - Extract messages with the same master key.
- Detect wrong keys or modified payload bits through AEAD authentication.
- Use either:
uniformselection: keyed positions across all float32 weights.naturalselection: keyed positions only inside weights whose absolute delta from a reference model is above a configured threshold.
- Sanitize common ONNX metadata fields before writing the stego model.
ONNX-Stego is strongest when used with a legitimate model update workflow.
Note:
squeezenet1.0-12-cover.onnxis a deterministic fine-tune surrogate for reproducibility only. Do not use it as a real embedding example in operational scenarios.
- Choose a public reference model, for example a model from ONNX Model Zoo or a model exported from PyTorch/TensorFlow to ONNX.
- Fine-tune that model on a normal task. This creates a cover model whose weights naturally differ from the public reference.
- Share, out of band, with Receiver B:
- the exact reference model identity or file hash,
- the 256-bit master key,
- the
natural-min-abs-deltathreshold, - the ONNX-Stego version or commit.
- Embed the message into the fine-tuned cover model using natural selection:
onnx-stego embed `
--model cover-finetuned.onnx `
--output stego.onnx `
--key "<MASTER_KEY>" `
--message "short authenticated message" `
--selection-mode natural `
--reference-model reference.onnx `
--natural-min-abs-delta 1e-5- Send only
stego.onnxthrough the ordinary channel.
B needs:
stego.onnx- the same 256-bit master key
- the same reference model
- the same natural-selection threshold
- this tool
Extraction:
onnx-stego extract `
--model stego.onnx `
--key "<MASTER_KEY>" `
--selection-mode natural `
--reference-model reference.onnx `
--natural-min-abs-delta 1e-5If the key is wrong, the reference model differs, the threshold differs, or the payload bits were modified, extraction fails authentication.
Uniform LSB embedding works technically, but it modifies positions across the whole model without explaining why those positions should have changed. In a better operational setup, A first fine-tunes the model for a plausible task. Fine-tuning changes many weights for a legitimate reason. Natural selection then restricts hidden bits to weights that already changed relative to the reference model, making the stego edits hide inside an existing model-update story.
This project does not perform fine-tuning for you. It expects A (You) to bring a reference (base) model and a fine-tuned cover model.
python -m pip install -e .For development and empirical verification:
python -m pip install -e ".[dev]"Generate a key:
onnx-stego keygenInspect a model:
onnx-stego inspect model.onnxEmbed a message with uniform selection:
onnx-stego embed `
--model model.onnx `
--output stego.onnx `
--key "<MASTER_KEY>" `
--message "hello from inside the weights"Extract it:
onnx-stego extract --model stego.onnx --key "<MASTER_KEY>"The proof/ directory contains a complete public demonstration.
Model used:
squeezenet1.0-12from ONNX Model Zoo on Hugging Face- Source: https://huggingface.co/onnxmodelzoo/squeezenet1.0-12
- License: Apache-2.0, as inherited from ONNX Model Zoo
- Reason for my choice: it is public, compact enough for a repository, works with
ONNX tooling, small enough to upload on github and has about 1.24 million
float32weights, which keeps the example embedding density low.
Proof files:
proof/squeezenet1.0-12-reference.onnx: downloaded public reference modelproof/squeezenet1.0-12-cover.onnx: deterministic fine-tune surrogate used only for reproducible publication proofproof/squeezenet1.0-12-stego.onnx: final model containing the hidden messageproof/manifest.json: hashes, key, threshold, and extraction command
The embedded public demo message is:
SECRET OF X-3306
Extract it:
onnx-stego extract `
--model proof/squeezenet1.0-12-stego.onnx `
--key onxs1_AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8 `
--selection-mode natural `
--reference-model proof/squeezenet1.0-12-reference.onnx `
--natural-min-abs-delta 1e-5Rebuild the proof:
python scripts/build_proof.pyThe included proof uses a deterministic fine-tune surrogate so the repository can be reproduced without a dataset or GPU. In real use, replace that surrogate with ACTUAL fine-tuning.
Run the test suite:
python -m pytestRun the smoke test:
python scripts/empirical_demo.pyChecks cover:
- message round-trip
- wrong-key rejection
- tamper rejection
- ONNX checker validity
- conversion from
float_datatoraw_data - little-endian
float32handling - simple LSB ratio and chi-square statistics
- inference output drift on a synthetic ONNX model
- natural selection against a reference model
is in SECURITY.md.
Use this project for legitimate research, watermarking, provenance experiments, and defensive analysis. Do not use it to bypass monitoring, policy, law, or the consent of systems and people that handle the model files.
python -m pip install -e ".[dev]"
python -m pytest
python scripts/empirical_demo.py
python scripts/build_proof.pyCode in this repository is released under the MIT License. The included proof
model is derived from ONNX Model Zoo's SqueezeNet model and is documented in
proof/manifest.json as Apache-2.0 sourced material.
