Score (query, document) pairs for vector/RAG poisoning signals: vector-text mismatch, instruction-like payloads, NaN, suspiciously round numbers. Python port of @mukundakatta/vector-poison-score.
Project description
vector-poison-score
Score (query, document) pairs for vector/RAG poisoning signals. Detects vector-text mismatch, zero/NaN/suspiciously-round vectors, instruction-like payloads, link farms, oversized chunks. Pure Python, zero runtime dependencies.
Python port of @mukundakatta/vector-poison-score. The JS sibling has the original heuristics; this port adds vector-aware signals on top.
Install
pip install vector-poison-score
# Optional: faster cosine via numpy
pip install "vector-poison-score[numpy]"
Usage
from vector_poison_score import score, filter_poisoned
q_vec = [0.1, 0.2, 0.3, 0.4]
d_vec = [0.1, 0.2, 0.3, 0.41] # very close to q_vec
q_text = "Who is the CEO of Anthropic?"
d_text = "Buy cheap watches at example.com" # totally unrelated
s = score(q_vec, d_vec, d_text, q_text)
s.score # 0.25 (one signal)
s.signals # ["vector_text_mismatch"]
s.severity # "low"
# Bulk-filter retrieved chunks
records = [
{"id": "a", "embedding": q_vec, "text": "About Anthropic..."},
{"id": "b", "embedding": d_vec, "text": d_text},
]
filter_poisoned(
records,
max_score=0.2,
query_vec=q_vec,
query_text=q_text,
) # -> drops record 'b'
Signals
| Signal | Trigger |
|---|---|
vector_text_mismatch |
Cosine(query, doc) >= 0.7 but Jaccard(query terms, doc terms) <= 0.1. The classic poisoned-embedding signature. |
zero_vector |
Doc vector is all zeros. |
nan_vector |
Doc vector contains NaN or +/-inf. |
suspiciously_round |
>= 70% of doc-vector entries are within 1e-3 of an integer (likely hand-crafted). |
instruction_like_payload |
Doc text matches the prompt-injection regex (mirrors JS sibling). |
link_farm |
Doc text has > 5 URLs (mirrors JS sibling). |
oversized_chunk |
Doc text > 20000 chars (mirrors JS sibling). |
score = min(1.0, len(signals) / 4). Severity: >= 0.66 -> high, >= 0.33 -> medium, else low.
API differences from the JS sibling
- JS:
scoreVectorPoison({ text }), text-only. Python:score(query_vec, doc_vec, doc_text, query_text)-- adds vector-aware signals (mismatch, zero, NaN, round) on top of the text checks. - JS:
filterPoisoned(docs, { maxScore }). Python:filter_poisoned(records, max_score=, text_key=, vector_key=, query_vec=, query_text=)-- record-shape configurable, query inputs optional. PoisonScoreis a frozen dataclass; severity is a typed string literal.
See the JS sibling for the original heuristics and broader design notes.
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 vector_poison_score-0.1.0.tar.gz.
File metadata
- Download URL: vector_poison_score-0.1.0.tar.gz
- Upload date:
- Size: 6.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
882d2d7de8774cf1ef467efe6c24c673388d6889faf0288b23b4fa3dd997ee79
|
|
| MD5 |
559437b5985a4769ed03fd9075cb13aa
|
|
| BLAKE2b-256 |
d3b85ef17b81ecda9b575e08fd445f66fc9e563a65bd15f881f36efc0823b860
|
File details
Details for the file vector_poison_score-0.1.0-py3-none-any.whl.
File metadata
- Download URL: vector_poison_score-0.1.0-py3-none-any.whl
- Upload date:
- Size: 6.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
560b556a8e1dd8584b2b826e93f124a7aa4a60f21b9c80f6ced43ec0d98af558
|
|
| MD5 |
e27950695ed2c7c885a352cdda62c042
|
|
| BLAKE2b-256 |
5a393052549c8541f02f665c673000897d700944332ff8fded66959d81a1c9b5
|