Docs · Quickstart · Threat model · Website
An agent reads a customer record, asks the model about it, calls an API and writes a log line. Each step is fine on its own. Together they send an email address to the LLM provider, an SSN to a third party and an API key to your log storage, and nothing in a normal agent stack notices.
Taintward notices. It finds sensitive values in every tool call and model call, follows them through the whole run, and changes them for where they are going before they leave.
The round trip
Masks break agents: a model that reads Remind [PII] ([PII]) cannot write
the email. Placeholders do not. The model gets <PERSON_1> and <EMAIL_1>,
does its job, and the answer comes back with the real values in it.
The same value always gets the same placeholder within a run, so the model
can still tell two people apart. If it rewrites one ([EMAIL_1],
EMAIL_1), it is still restored. The map from placeholder to value never
leaves your process.
In numbers
Measured on one laptop, and on public datasets the rules were never tuned on. How: benchmark · placeholders with real models.
Where it runs
See it work
git clone https://github.com/DCchoudhury15/Taintward && cd Taintward
docker compose up --build
Open http://localhost:16686 and pick taintward-hr-bot. A demo HR agent
leaks a fake SSN and AWS key to an LLM, an external API and a log. All three
calls show up flagged, and the real values are nowhere in the traces.
Add it to your agent
Python · LangChain, LangGraph, OpenAI Agents SDK, CrewAI, LlamaIndex, Pydantic AI, Google ADK, LiteLLM, OpenAI, Anthropic
pip install "taintward[langchain] @ git+https://github.com/DCchoudhury15/Taintward"
python -m spacy download en_core_web_sm
import taintward as tw
tw.init("my-agent", destinations={"search_db": "internal", "send_email": "external"})
tools = tw.wrap_langchain_tools(tools)
model = tw.protect_langchain_model(model) # or tw.protect_openai(OpenAI())
with tw.run():
agent.invoke(...)
Every framework gets the same two calls, one for its tools and one for its
model: tw.wrap_crewai_tools(...) and tw.protect_crewai_llm(...),
tw.wrap_adk_tools(...) and tw.protect_adk_model(...), and so on
(the full table).
TypeScript · Vercel AI SDK, generateText and streamText
import { wrapLanguageModel } from "ai";
import { taintwardMiddleware } from "taintward/ai-sdk";
const model = wrapLanguageModel({
model: openai("gpt-4.1"),
middleware: taintwardMiddleware(),
});
MCP · no code changes: put taintward-gateway --config gateway.yaml in
your MCP client config in place of the real server.
LiteLLM proxy · no code changes: add
taintward.sdk.integrations.litellm.TaintwardGuardrail as a guardrail. The
model providers get placeholders, and the apps behind the proxy still get
answers with real values.
More: Python integrations · TypeScript SDK · MCP gateway · Kubernetes
Where it stops
- It protects the calls that go through it. A client or tool you did not wrap is not seen.
- It does not stop prompt injection. It limits what an injected instruction can get out.
- A value that is encoded, split across fields or in an unknown format can slip past detection.
Every known gap and a hardening checklist: threat model.
Background
Built on the formal model from AgentRaft (Lin et al., 2026), which found data over-exposure in 57% of the agent call chains it studied. AgentRaft runs offline and asks three LLMs to judge each step. Taintward runs live, with no LLM in the decision: how the parts map. It was called AgentWard before 0.2.0.
Development
python -m pytest -q # Python
cd collector/processor/taintpolicy && go test ./... # Go collector processor
cd packages/taintward-js && npm ci && npm test # TypeScript
Apache-2.0
Metadata
Release files for taintward 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| taintward-0.3.0.tar.gz | 168.9 kB | With provenance | Details for taintward-0.3.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| taintward-0.3.0-py3-none-any.whl | Python 3 | none | any | Details for taintward-0.3.0-py3-none-any.whl |
Total release size: 354.5 kB
Release files / taintward-0.3.0.tar.gz
| Download URL | taintward-0.3.0.tar.gz |
|---|---|
| Size | 168.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
00c7eebe18f0f0c5d87cb2949081b56715164ff8379f2df233d77267f29c1004
|
|
BLAKE2b-256 checksum How to use checksums |
6b90e4467d340074f6b941b4bac2af1336bd30292117f134d5d9a2c8f5c9a702
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 30, 2026.
Transparency logRelease files / taintward-0.3.0-py3-none-any.whl
| Download URL | taintward-0.3.0-py3-none-any.whl |
|---|---|
| Size | 185.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
306dee59439c0764706a298177240e629d2b6382ff82f7d9f365115affc18515
|
|
BLAKE2b-256 checksum How to use checksums |
a613e862d4aceeee4cbce396a1f40b26066e7e0a9b9b8900088e5336e614f344
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 30, 2026.
Transparency logSecurity for taintward 0.3.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for taintward-0.3.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 30, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.