Neutralise prompt-injection / tool-poisoning in untrusted MCP/LLM tool text before it reaches the system prompt.
Project description
pantheon-tool-sanitizer
Neutralise prompt-injection / tool-poisoning in untrusted tool text before it reaches an LLM's system prompt. Zero dependencies, ~40 lines.
The problem: when your agent consumes tools from an external source — an MCP server, a plugin registry, a third-party API — that source's tool name and description are attacker-controlled, and they get rendered into the trusted instruction channel (the planner's system prompt). A hostile server can weaponise that.
Extracted from PANTHEON, where it guards the inbound MCP transport — the point where a governed agent consumes an external, possibly-hostile server's tools.
The attack (tool poisoning)
A malicious tool description can:
- fake a tool-call — embed
<function_calls>…or a{"action": ...}object so the model believes a tool ran; - hide or reorder text — Unicode zero-width and bidirectional-override characters render invisibly, so your human review sees one thing and the model sees another (
safeIGNORE ALL PRIOR RULES); - smuggle instructions across lines — a multi-line description that reads as new system directives.
The fix
from tool_sanitizer import sanitize_remote_tool_text
safe_name = sanitize_remote_tool_text(remote_tool["name"], max_len=64)
safe_desc = sanitize_remote_tool_text(remote_tool["description"])
if not safe_name: # a name that sanitises to nothing (pure markup/invisibles) is unsafe → skip the tool
continue
sanitize_remote_tool_text collapses the whole vector to inert, single-line prose:
- strips invisible / bidi / control characters,
- removes tool-protocol markup (so it can't fake a tool call),
- flattens whitespace so nothing spans lines or injects instructions,
- caps the length,
- returns
""when nothing safe remains — a signal to skip that tool entirely.
Run it on every untrusted tool name and description before they touch the prompt. strip_tool_markup is also exported for cleaning model output (so a user never sees raw markup).
Install
pip install pantheon-tool-sanitizer # or copy the single tool_sanitizer.py file
Scope
This is one specific control — input sanitisation of tool metadata. It is not a full agent-security layer (you still want capability gating, approval on consequential actions, and treating tool output as untrusted data). It closes the tool-poisoning-via-metadata hole cleanly.
License
Apache-2.0. See LICENSE.
Project details
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 pantheon_tool_sanitizer-0.1.0.tar.gz.
File metadata
- Download URL: pantheon_tool_sanitizer-0.1.0.tar.gz
- Upload date:
- Size: 8.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
125591eef3099c8c897018d4a76386ccea0a4b9db8f23645b5671d2843a81a7e
|
|
| MD5 |
d51b7ffc24ccf19312d88a13c93fca0a
|
|
| BLAKE2b-256 |
9ada22850c9d59a9328ca78f50369a02c4c308c055fc307409ebb9c2c6db0f4c
|
Provenance
The following attestation bundles were made for pantheon_tool_sanitizer-0.1.0.tar.gz:
Publisher:
publish.yml on Igfray/pantheon-tool-sanitizer
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pantheon_tool_sanitizer-0.1.0.tar.gz -
Subject digest:
125591eef3099c8c897018d4a76386ccea0a4b9db8f23645b5671d2843a81a7e - Sigstore transparency entry: 2156062925
- Sigstore integration time:
-
Permalink:
Igfray/pantheon-tool-sanitizer@61aad7bb1a2a1b34180f644fd0c7fa2ab5db15b2 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/Igfray
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@61aad7bb1a2a1b34180f644fd0c7fa2ab5db15b2 -
Trigger Event:
push
-
Statement type:
File details
Details for the file pantheon_tool_sanitizer-0.1.0-py3-none-any.whl.
File metadata
- Download URL: pantheon_tool_sanitizer-0.1.0-py3-none-any.whl
- Upload date:
- Size: 8.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7e22ef201a98d4674b43f7aefb73e0ecbd420795166a130a8677ff510671b774
|
|
| MD5 |
a7b2528aaaa18a102133fb662269db92
|
|
| BLAKE2b-256 |
8cbe80f73fda70f14c7fd944a2edbd9d89ef0cefa6431fb5b30d6e9fe71efb01
|
Provenance
The following attestation bundles were made for pantheon_tool_sanitizer-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on Igfray/pantheon-tool-sanitizer
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pantheon_tool_sanitizer-0.1.0-py3-none-any.whl -
Subject digest:
7e22ef201a98d4674b43f7aefb73e0ecbd420795166a130a8677ff510671b774 - Sigstore transparency entry: 2156062981
- Sigstore integration time:
-
Permalink:
Igfray/pantheon-tool-sanitizer@61aad7bb1a2a1b34180f644fd0c7fa2ab5db15b2 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/Igfray
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@61aad7bb1a2a1b34180f644fd0c7fa2ab5db15b2 -
Trigger Event:
push
-
Statement type: