Production-grade memory integrity defense for AI agents
Project description
memshield
A drop-in Python library that wraps any vector store to provide two things simultaneously:
- Memory poisoning defense — validates every retrieved chunk before it reaches your LLM, blocking injected instructions disguised as knowledge
- EU AI Act Article 12 audit logging — per-inference tamper-evident records of what your AI retrieved, with RFC 3161 timestamps, Ed25519 signatures, and GDPR crypto-shredding
One line of code. Same interface as your existing store.
store = shield.wrap(your_chroma_or_pinecone_store)
docs = store.similarity_search("what medication is the patient on?")
# poisoned entries blocked; Article 12 audit record written automatically
Why this exists
Security: Memory poisoning corrupts agent behavior permanently. Unlike prompt injection (attacker must be present each session), a poisoned vector store entry affects every future query across all users. Red-teaming tools find the vulnerability — MemShield blocks it at runtime.
Compliance: EU AI Act Article 12 (enforceable August 2026) requires high-risk AI systems to automatically generate tamper-evident logs of what data was retrieved at inference time, retained for at least 6 months. No RAG framework produces this natively.
Both problems share the same interception point: the retrieval layer.
Install
pip install memshield # core (no deps)
pip install memshield[openai] # OpenAI/Ollama provider
pip install memshield[audit] # Article 12 audit log (requires cryptography + rfc3161ng)
pip install memshield[audit,openai] # both
pip install memshield[all] # everything
Quick start
Poisoning defense only
from memshield import MemShield
from memshield.strategies import KeywordHeuristicStrategy, ConsensusStrategy, EnsembleStrategy
from memshield.adapters.openai_provider import OpenAIProvider
shield = MemShield(
strategy=EnsembleStrategy([
KeywordHeuristicStrategy(),
ConsensusStrategy(OpenAIProvider(model="gpt-4o-mini")),
])
)
store = shield.wrap(your_vectorstore)
docs = store.similarity_search("company refund policy")
# poisoned entries are blocked; clean entries pass through unchanged
With Article 12 audit logging
from memshield import MemShield, AuditConfig
from memshield.strategies import EnsembleStrategy, KeywordHeuristicStrategy, ConsensusStrategy
from memshield.adapters.openai_provider import OpenAIProvider
shield = MemShield(
strategy=EnsembleStrategy([
KeywordHeuristicStrategy(),
ConsensusStrategy(OpenAIProvider()),
]),
audit=AuditConfig(
store="./audit.db",
knowledge_base_id="kb_prod_v3",
pii_fields=["query", "content"], # AES-256-GCM encrypted at rest
key_store="./keys.db",
tsa_url="https://timestamp.sectigo.com", # RFC 3161, free, no account needed
),
)
store = shield.wrap(your_vectorstore)
docs = store.similarity_search(
"what medication is the patient on?",
user_id="u_123",
inference_id="req_xyz", # optional — correlate with your own request logs
)
record = shield.audit_log.last_record()
print(record.inference_id) # req_xyz
print(record.chain_hash) # sha256:8b3e...
print(record.timestamp_rfc3161) # base64-encoded TSA proof from Sectigo
GDPR right-to-erasure
# Deletes the user's encryption key. Ciphertext becomes permanently unreadable.
# Chain hashes, timestamps, and doc IDs remain intact for audit continuity.
shield.audit_log.erase_user(user_id="u_123")
Audit log schema
Every inference produces one record, aligned to ISO/IEC DIS 24970:2025:
{
"inference_id": "req_xyz",
"timestamp_iso": "2026-03-10T09:00:00.000Z",
"timestamp_rfc3161": "<base64 DER token from Sectigo TSA>",
"key_id": "<sha256 fingerprint of Ed25519 signing key>",
"user_id": "u_123",
"query_hash": "sha256:a3f8...",
"query_encrypted": "<aes-256-gcm ciphertext>",
"knowledge_base_id": "kb_prod_v3",
"retrieved": [
{
"doc_id": "doc_456", "chunk_index": 3,
"content_hash": "sha256:c9d2...", "content_encrypted": "<aes-256-gcm ciphertext>",
"score": 0.94, "verdict": "clean", "trust_level": "verified"
}
],
"blocked": [
{
"content_hash": "sha256:f1a9...", "content_encrypted": "<aes-256-gcm ciphertext>",
"verdict": "poisoned", "confidence": 0.97, "attack_type": "T1_instruction_override"
}
],
"chain_hash": "sha256:8b3e...",
"previous_chain_hash": "sha256:2d7a...",
"signature": "ed25519:...",
"iso24970_event_type": "retrieval",
"iso24970_schema_version": "DIS-2025"
}
Tamper evidence: append-only SQLite (WAL mode), SHA-256 hash chain, Ed25519 signature per record, RFC 3161 timestamp token. Expired records (default 180-day retention) are replaced with tombstones that preserve chain continuity.
CLI
memshield audit verify --db ./audit.db
memshield audit export --db ./audit.db --from 2026-01-01 --format jsonl
memshield audit inspect --db ./audit.db --inference-id req_xyz
memshield audit erase-user --db ./audit.db --key-store ./keys.db \
--user-id u_123 --knowledge-base-id kb_prod_v3
memshield keys rotate --key-file ./memshield.key
MCP server
Any MCP-compatible agent (Claude Code, Cursor) can use MemShield with one config entry:
{
"mcpServers": {
"memshield": {
"command": "memshield",
"args": ["mcp", "--audit-db", "./audit.db"]
}
}
}
Tools exposed: audit_inspect(inference_id), audit_verify(), audit_export(from_date?).
Supported vector stores
| Store | How to use |
|---|---|
| Chroma | shield.wrap(chroma_collection) |
| LangChain vectorstores | shield.wrap(langchain_vectorstore) |
| LlamaIndex retrievers | LlamaIndexRetrieverAdapter(retriever) then shield.wrap(...) |
| Pinecone | PineconeStoreAdapter(index, embed_fn) then shield.wrap(...) |
| pgvector | PgVectorStoreAdapter(conn, embed_fn) then shield.wrap(...) |
| Qdrant | QdrantStoreAdapter(client, collection, embed_fn) then shield.wrap(...) |
Validation strategies
from memshield.strategies import KeywordHeuristicStrategy, ConsensusStrategy, EnsembleStrategy
# Instant, zero-cost — catches obvious injection patterns
KeywordHeuristicStrategy()
# LLM-based consensus (A-MemGuard approach) — catches subtle attacks
ConsensusStrategy(OpenAIProvider(model="gpt-4o-mini"))
# Ensemble — flag if either detects poisoning (maximum recall)
EnsembleStrategy([KeywordHeuristicStrategy(), ConsensusStrategy(provider)], mode="any_poisoned")
# Ensemble — majority vote (balanced precision/recall)
EnsembleStrategy([KeywordHeuristicStrategy(), ConsensusStrategy(provider)], mode="majority")
Benchmark
memshield-bench — 1,178 labeled entries across 10 attack types, including AgentPoison (NeurIPS 2024) data:
| Strategy | Precision | Recall | F1 |
|---|---|---|---|
| Keyword heuristic | 100% | 14.5% | 25.4% |
| LLM consensus | 97.1% | 98.6% | 97.8% |
| Ensemble (majority) | 100% | 100% | 100% |
| Ensemble (any_poisoned) | 94.5% | 100% | 97.2% |
Keyword heuristic catches 0% of AgentPoison attacks — sophisticated attacks are disguised as reasoning traces with no obvious instruction patterns. LLM consensus is required.
Configuration
from memshield import ShieldConfig, FailurePolicy
config = ShieldConfig(
confidence_threshold=0.7,
failure_policy=FailurePolicy.BLOCK, # or ALLOW_WITH_WARNING, ALLOW_WITH_REVIEW
enable_provenance=True,
enable_drift_detection=True,
)
shield = MemShield(strategy=..., config=config)
What MemShield is not
- Not a full EU AI Act compliance solution. Article 12 logging covers what was retrieved. It does not produce Annex IV technical documentation or Article 9 risk management plans. For complete Article 12 coverage pair with an LLM observability tool (Langfuse, Helicone).
- Not a managed service. Self-hosted only.
- Not a TypeScript library. Python only.
Alternatives
Most AI security products operate at the prompt/response boundary. MemShield operates at the retrieval layer — where poisoning actually happens.
Closest alternatives: NVIDIA NeMo Guardrails (retrieval rails, broader scope), Daxa (pre-vectorization scanning, complementary).
Development
git clone https://github.com/npow/memshield.git
cd memshield
pip install -e ".[dev]"
pytest
License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file memshield-0.2.0.tar.gz.
File metadata
- Download URL: memshield-0.2.0.tar.gz
- Upload date:
- Size: 534.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2ecfe4b2e533d3bc1181fcfbd4b60590ea4adbd276040ea90c234bd1343be597
|
|
| MD5 |
8b0f59d85b7db62814bb433a0d29af8b
|
|
| BLAKE2b-256 |
0482cbc7e7a19959d84e4533cc0b9a40d2028dd61ba9f71417aa9c006ee81d50
|
Provenance
The following attestation bundles were made for memshield-0.2.0.tar.gz:
Publisher:
publish.yml on npow/memshield
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
memshield-0.2.0.tar.gz -
Subject digest:
2ecfe4b2e533d3bc1181fcfbd4b60590ea4adbd276040ea90c234bd1343be597 - Sigstore transparency entry: 1063847111
- Sigstore integration time:
-
Permalink:
npow/memshield@351d6573a1eff61ebc9b73189f5f216c316905d8 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/npow
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@351d6573a1eff61ebc9b73189f5f216c316905d8 -
Trigger Event:
push
-
Statement type:
File details
Details for the file memshield-0.2.0-py3-none-any.whl.
File metadata
- Download URL: memshield-0.2.0-py3-none-any.whl
- Upload date:
- Size: 51.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
216a4b6ab88a8271b3861cb734e97c7db4884a3fe524558b0ad671d4854cc509
|
|
| MD5 |
31685b65ed2c8f9e89e2ba6b5bb741c9
|
|
| BLAKE2b-256 |
bfe56d8dfeb601678e39371d415e4ab3b13d26f9695a8b72b07244d68c023a53
|
Provenance
The following attestation bundles were made for memshield-0.2.0-py3-none-any.whl:
Publisher:
publish.yml on npow/memshield
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
memshield-0.2.0-py3-none-any.whl -
Subject digest:
216a4b6ab88a8271b3861cb734e97c7db4884a3fe524558b0ad671d4854cc509 - Sigstore transparency entry: 1063847167
- Sigstore integration time:
-
Permalink:
npow/memshield@351d6573a1eff61ebc9b73189f5f216c316905d8 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/npow
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@351d6573a1eff61ebc9b73189f5f216c316905d8 -
Trigger Event:
push
-
Statement type: