KeiZen 1
Tiny binary classifier that detects secrets in .env files.
KeiZen 1 reads KEY=VALUE lines and classifies them as SECRET or NON_SENSITIVE. It runs in <1ms per line on modest hardware โ no GPU required.
Highlights
| Parameters | 4.4M (vs DistilBERT 66M) |
| ONNX INT8 size | 4.3 MB |
| Latency (CPU) | <1ms per line |
| Throughput | ~1,000 lines/sec on i3-6100 |
| Accuracy | 99.6% on 261 hand-crafted tests |
| Precision | 100% โ never flags non-sensitive as secret |
Architecture
Input: "KEY=VALUE line"
|
+--> Tokenizer (BERT WordPiece)
| |
| v
| BERT-Tiny (2 layers, 128 hidden, ~4.1M params)
| |
| v
| CLS Embedding (128-dim)
| |
+--> Feature Engine (29 numeric features)
|
v
Feature Projection (Linear 29->32 + BN + ReLU, ~1K params)
|
v
Feature Vector (32-dim)
|
v
Fusion: Concat(128, 32) = 160
|
v
Classifier: Linear(160->32) + ReLU -> Linear(32->2)
|
v
Softmax -> SECRET | NON_SENSITIVE
Base model: prajjwal1/bert-tiny (2 layers, 128 hidden, 2 attention heads)
Inference Pipeline
User --> Tokenizer --> input_ids + attention_mask --+
Feature Engine --> 29 numeric features ------+--> KeiZen 1 (ONNX)
|
BERT-Tiny + Fusion + Classifier
|
v
logits [0.02, 0.98]
|
v
{"label": "SECRET",
"confidence": 0.98}
Total latency: ~0.8ms on CPU
Engineered Features (29)
Features
|
+-- Entropy
| value_entropy, key_entropy
|
+-- Length
| value_length, key_length, line_length
|
+-- Key Patterns
| ALL_CAPS, SECRET/KEY/TOKEN, word_count, has_underscore
|
+-- Value Patterns
| hex, base64, uuid, ip, url, numeric, boolean, common_word
|
+-- API Detection
| sk_live_ prefix, ghp_ prefix, AKIA prefix, hf_ prefix
|
+-- Special
private_key, jwt, has_@, mixed_case, digit_ratio, alpha_ratio
The model combines raw text embeddings with hand-crafted features:
- Entropy: Shannon entropy of value and key
- Length: value length, key length, line length
- Key patterns: ALL_CAPS, contains SECRET/KEY/TOKEN/PASSWORD, word count
- Value patterns: hex, base64, UUID, IP, URL, numeric, boolean, common word
- API prefixes:
sk_live_,ghp_,AKIA,hf_,npm_, etc. - Special formats: private key, JWT,
@in value, mixed case, digit/alpha ratios
Benchmark Results
Overall Performance
| Metric | ONNX FP32 | ONNX INT8 |
|---|---|---|
| Accuracy | 99.62% | 99.62% |
| Precision | 100.00% | 100.00% |
| Recall | 98.92% | 98.92% |
| F1 Score | 99.46% | 99.46% |
Accuracy by Category
21 of 22 categories at 100%. The only miss: 1 of 4 connection strings misclassified (the model needs @ + password patterns in URIs to be more distinctive).
Latency Analysis
| ONNX FP32 | ONNX INT8 | |
|---|---|---|
| Mean | 0.84ms | 0.77ms |
| p50 | 0.83ms | 0.75ms |
| p95 | 1.08ms | 0.98ms |
| p99 | 1.37ms | 1.10ms |
Runs on Modest Hardware
Tested on potato โ an Intel i3-6100 @ 3.70GHz, 8GB RAM, no GPU, Debian 13.
potato Results
| Metric | ONNX FP32 | ONNX INT8 |
|---|---|---|
| Accuracy | 99.62% | 99.62% |
| Latency (mean) | 1.04ms | 0.91ms |
| Throughput | 973 l/s | 1,102 l/s |
Same accuracy, same model, <1ms on a 2015 i3. No GPU needed.
Quick Start
ONNX (recommended)
pip install onnxruntime transformers
import onnxruntime as ort
import numpy as np
from transformers import AutoTokenizer
# Load
session = ort.InferenceSession("keizen1_int8.onnx")
tokenizer = AutoTokenizer.from_pretrained("keizen1")
def predict(line):
enc = tokenizer(line, max_length=64, padding="max_length",
truncation=True, return_tensors="np")
feats = compute_features(line) # see benchmark.py
fv = np.array([[feats[k] for k in FEATURE_NAMES]], dtype=np.float32)
logits = session.run(None, {
"input_ids": enc["input_ids"].astype(np.int64),
"attention_mask": enc["attention_mask"].astype(np.int64),
"features": fv,
})[0]
probs = np.exp(logits) / np.exp(logits).sum(axis=1, keepdims=True)
pred = int(np.argmax(probs))
return {
"label": ["NON_SENSITIVE", "SECRET"][pred],
"confidence": float(probs[0][pred]),
"is_secret": pred == 1,
}
# Usage
predict("PORT=3000")
# {'label': 'NON_SENSITIVE', 'confidence': 0.9991, 'is_secret': False}
predict("STRIPE_API_KEY=sk_live_51Nzabc123...")
# {'label': 'SECRET', 'confidence': 0.9847, 'is_secret': True}
PyTorch / SafeTensors
from transformers import AutoTokenizer, AutoModel
import torch
model = KeiZen1.from_pretrained("keizen1") # see notebook for class definition
tokenizer = AutoTokenizer.from_pretrained("keizen1")
Files
| File | Size | Description |
|---|---|---|
keizen1_int8.onnx |
4.3 MB | Recommended โ quantized, fastest on CPU |
keizen1.onnx |
16.8 MB | Full precision ONNX |
keizen1/model.safetensors |
16.8 MB | SafeTensors (HuggingFace ecosystem) |
keizen1/config.json |
1 KB | Model config & feature names |
keizen1/tokenizer.json |
712 KB | BERT tokenizer |
Training
Synthetic Data (24K .env lines)
|
v
Feature Engineering (29 features + tokenizer)
|
v
Train/Val Split (80/20 stratified)
|
v
Fine-tune (8 epochs, LR=3e-5)
|
v
Best checkpoint (F1=0.995)
|
+---> SafeTensors (16.8 MB)
+---> ONNX FP32 (16.8 MB)
+---> ONNX INT8 (4.3 MB)
The model was trained on 24,000 synthetic .env lines (12K SECRET + 12K NON_SENSITIVE):
- Secrets: 100+ API key patterns (Stripe, AWS, GitHub, OpenAI, etc.), JWT tokens, passwords, private keys, DB connection strings, high-entropy strings
- Non-sensitive: ports, environments, hosts, feature flags, timeouts, log levels, booleans, paths, regions, protocols
Train it yourself:
pip install torch transformers scikit-learn onnx onnxruntime
jupyter notebook secret_detector.ipynb
Use Cases
KeiZen 1
|
+---------+-------+-------+---------+
| | | |
v v v v
CI/CD Pre-commit Code Review Container
Pipeline Hook Bot Scanner
| | | |
v v v v
Block .env Local git PR comment Docker inspect
push if hook scans flags env variables
secrets before commit exposed keys
found
- CI/CD pipelines: Scan
.envfiles before git push - Code review: Detect secrets in pull requests
- Secret scanning: Audit configuration files
- Pre-commit hooks: Block accidental secret commits
- Container scanning: Check environment variables in Docker configs
License
apache-2.0






