Vector databases need the geometry of your embeddings to search them, so the vectors usually sit in the database exactly as the embedding model produced them, next to the documents' metadata. Anyone who gets a snapshot, a backup or an over-privileged database account gets both.
hadamask protects that data before it leaves your application.
- Embeddings go through a secret orthogonal transform. Queries get the same transform, so the database computes exactly the same cosine, dot-product and L2 scores as on the clear vectors. Index, database and recall stay the same.
- Metadata and document text are encrypted field by field with AES-256-GCM, with a fresh nonce per value and length padding.
- Filters still work. Fields declared
blindget keyed equality tokens; fields declaredplaintextstay in clear and support ranges. - Keys stay with you. It is a library, not a proxy or a service. The master key can stay wrapped by HashiCorp Vault, AWS KMS, Google Cloud KMS or Azure Key Vault.
The longer story, including what it leaks, is in the write-up.
What it is not
The embedding transform is obfuscation with measured leakage, not encryption. It hides the coordinate system, but the relative geometry of the corpus, which documents are similar to which, stays visible. In the paper's experiments, an attacker holding only the protected vectors and public data from the same distribution reached median accuracies of 81 to 87% on four-way topic inference. Metadata is encrypted. hadamask is alpha software and has not had an external cryptographic audit.
| What is stored | Protection | What a snapshot still reveals |
|---|---|---|
| Encrypted fields (the default) | AES-256-GCM, fresh nonce per value, field name and key id as associated data | That the field exists, and a size class for long values |
| Blind fields | Encrypted, plus an HMAC-SHA256 equality token | Which records share a value, and how often |
| Plaintext fields | None, by your choice | Everything |
| Embeddings | Keyed orthogonal transform | All pairwise similarities: clusters, duplicates, neighbourhoods. Not the coordinates |
Install
pip install "hadamask[pgvector]" # or qdrant, weaviate, milvus, chroma, ...
pip install "hadamask[all]" # every database, framework and key manager
from hadamask import MasterKey, MetadataPolicy, Protector
from hadamask.adapters.qdrant import QdrantStore
protector = Protector(MasterKey.generate("demo1"), MetadataPolicy(plaintext=["year"], blind=["client"]))
store = QdrantStore(client, protector)
store.create_collection("docs", dim=1536, metric="cosine")
store.upsert("docs", ids, embeddings, payloads)
hits = store.search("docs", query_embedding, k=5, where={"client": "ACME"})
Where it runs
Qdrant, Weaviate, Milvus, Chroma, pgvector, Elasticsearch, OpenSearch, Redis Stack and MongoDB Atlas Vector Search, behind one API, plus LangChain and LlamaIndex wrappers for any vector store those frameworks support. Every adapter passes the same contract test against a real server, including a check that only ciphertext reaches the database.
Paper
The method and its leakage are analysed in What a Secret Rotation Buys: Exact Retrieval and Measured Leakage in Vector Databases, Ionuț Cernica and Nirvana Popescu, Applied Sciences 16(20), 10259, 2026.
Security issues: please email [email protected] rather than opening a public issue.