Skip to main content

agentmemorytaintgap

Catch untrusted content being written into an AI agent's long-term memory as if it were a trusted fact.

Prompt injection usually gets pictured as a single bad turn: a poisoned web page or tool result sneaks into one prompt, the model says something wrong once, and the blast radius ends there. Agent memory breaks that assumption. A growing class of agent frameworks let the agent persist content — a tool result, a summary, a "fact" — into a long-term memory store that gets read back and fed into every future prompt as if it were the agent's own trusted conclusion. If the content that gets written was actually attacker-controlled (a malicious tool response, a crafted user message, a poisoned web page), and nothing strips or tags it first, the poison survives for the lifetime of that memory store — this is the "agent memory poisoning" risk that's an increasingly-discussed, distinct branch of prompt injection in 2026.

agentmemorytaintgap reads your source with Python's ast module — no imports, no execution — and flags the memory-write call sites where that can happen:

$ agentmemorytaintgap agent/

BLOCKER  AT001 agent/handler.py:3:4   Memory-write call stores content traced back to an untrusted origin (tool output / external fetch / raw user input) with no sanitization or provenance-tagging call in this function (agent memory poisoning risk).
        agent_memory.save_context({"input": user_query}, {"output": tool_result})

1 file(s) scanned · 1 blocker(s) · 0 warning(s)

Exit code 1 on a blocker, so it drops straight into pre-commit or CI.

What it flags

Rule Severity Fires when…
AT001 blocker a memory-write call's stored value traces (single-hop, same function) back to a provably untrusted origin — tool output, an HTTP/fetch response, or a raw user-input parameter — with no sanitize/tag call on it anywhere in that function.
AT002 warning a memory-write call's stored value origin could not be confidently traced either way (a bare parameter with no naming signal, or a longer assignment chain). Lower confidence — worth a human glance, not a confident blocker.

The LLM's own generated response (e.g. llm.invoke(...)) is treated as trusted and is never flagged — the concern here is specifically external content being stored as if it were the agent's own conclusion.

Recognized memory-write shapes

  • LangChain-shaped: .save_context(...), .chat_memory.add_message(...) / .add_user_message(...) / .add_ai_message(...).
  • Generic vector-store-as-memory: .add(...) / .upsert(...) called on a variable whose name contains memory, mem_store, or long_term — there is no single standard "agent memory" API the way there is for HTTP, so this is a naming heuristic, documented honestly in DETAILS.md.
  • Custom memory helpers: a call to remember(...), store_memory(...), or save_memory(...), as a free function or bound method.

Recognized untrusted origins

  • A tool call: .run(...) / .invoke(...) on a variable named like tool, or a call to a function decorated with a recognizable @tool decorator.
  • An external fetch: requests/httpx/aiohttp .get/.post/...(...), or a call to a function literally named fetch.
  • A raw user-input function parameter (named like user_input, user_message, raw_input, user_query, or message).

Safe-marker short-circuit

If a call whose name contains sanitize, clean, validate, tag_source, or mark_untrusted is applied to the value anywhere in the same function before the memory write, the finding does not fire — the short-circuit is deliberately generous, the same style as its sibling tools.

How it relates to echofence

echofence and agentmemorytaintgap are both prompt-injection-adjacent AST linters, and they are deliberately distinct, non-overlapping tools:

  • echofence — input side, single turn. Flags untrusted external content reaching a live LLM prompt directly — the indirect variant of OWASP LLM01. The risk window is one request/response cycle.
  • agentmemorytaintgap — persistence side, every future turn. Flags untrusted content being written into long-term memory that will be read back and replayed as trusted context across every subsequent turn, potentially for the lifetime of the memory store. The artifact, the timing, and the risk shape are different: a poisoned prompt affects one answer; a poisoned memory write affects all future answers until someone notices and purges the store.

See DETAILS.md for the full, honest comparison — including why this is not just "echofence but for a different sink."

Install

pip install agentmemorytaintgap

Usage

agentmemorytaintgap agent/                # scan a directory
agentmemorytaintgap memory_handler.py      # scan a file
agentmemorytaintgap agent/ --strict        # AT002 warnings fail the run too
agentmemorytaintgap agent/ --json          # machine-readable output

In CI

- run: pip install agentmemorytaintgap
- run: agentmemorytaintgap agent/ --strict

Exit codes: 0 clean · 1 a blocker (AT001), or any finding under --strict · 2 usage error.

Honest limitations

agentmemorytaintgap is a pragmatic, heuristic, single-hop, same-function-scope analyzer — not full data-flow / taint analysis. See DETAILS.md for the complete breakdown, but concretely:

  • It only recognizes the memory-write shapes and naming conventions listed above. A memory variable that doesn't contain memory/mem_store/ long_term in its name, or a tool call that doesn't match the recognized @tool/.run()/.invoke() shapes, is invisible to v0.1.
  • Tracing is single-hop and scoped to one function. A value laundered through a helper function it doesn't look inside of, or passed across functions before being written to memory, will not be traced.
  • A sanitize/tag call anywhere in the function short-circuits the finding — it trusts that the call actually does what its name implies; it does not verify that.

Treat it as a fast reviewer that catches the obvious, high-value cases on every PR, paired with human judgment for the rest.

License

MIT © Jay Tank

Metadata

Release files for agentmemorytaintgap 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for agentmemorytaintgap 0.1.0
File Size Uploaded Provenance
agentmemorytaintgap-0.1.0.tar.gz 17.1 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for agentmemorytaintgap 0.1.0
File Interpreter ABI Platform
agentmemorytaintgap-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 28.8 kB

Release files / agentmemorytaintgap-0.1.0.tar.gz

Download URL agentmemorytaintgap-0.1.0.tar.gz
Size 17.1 kB
Tags Source
SHA-256 checksum
How to use checksums
19d641479449b5166f0bab04f6ac5507b2660c825164ae529a981f4546d42bf2
BLAKE2b-256 checksum
How to use checksums
e69c47e2059868222d14b44e3af5058cc85a325af7ce621cd07a94513e026264
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.10.12

Release files / agentmemorytaintgap-0.1.0-py3-none-any.whl

Download URL agentmemorytaintgap-0.1.0-py3-none-any.whl
Size 11.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
14ef1db3b623b69b6c81c2770cc946cc74187f022e178949de3dd11e518b07bb
BLAKE2b-256 checksum
How to use checksums
d45ace53b1765a7fca890dd0f3b1fc874350d69f6908934475cfeefe1ad01dd2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.10.12

Security for agentmemorytaintgap 0.1.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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A 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.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page