Les bases vectorielles sont devenues un actif sensible des architectures LLM modernes. Pinecone, Weaviate, Qdrant, Chroma, pgvector — chacune a son modèle de sécurité, ses défauts par défaut, et ses pièges de configuration. Plusieurs disclosures publiques en 2024-2025 ont mis en évidence des instances exposées sur Internet sans authentification, des fuites cross-tenant via API keys mal scopées, et des snapshots accessibles publiquement. Pour les RAG, qui dépendent intégralement de ces bases, la posture de pentest est non-négociable.
Cet article documente la méthodologie de pentest par produit (Pinecone, Weaviate, Qdrant, Chroma, pgvector), les surfaces d'attaque communes, les outils et une checklist de 30 contrôles. Pour le contexte global RAG : sécuriser un système RAG. Pour le pentest pipeline complet : pentest pipeline RAG.
Surface d'attaque commune
Sept surfaces récurrentes sur toutes les vector DB :
| # | Surface | Pourquoi exploitable |
|---|---|---|
| 1 | Auth API | Tokens simples, parfois absents en self-hosted |
| 2 | Network exposure | Ports par défaut sans firewall ; Shodan détecte |
| 3 | Tenant/namespace isolation | Filtres metadata pas toujours durs |
| 4 | Metadata filter injection | Filters construits depuis input non validé |
| 5 | Snapshot/backup exposure | Dumps en S3/GCS public par mégarde |
| 6 | Admin endpoints | Endpoints gestion avec auth faible |
| 7 | Embedding inversion | Vol DB = vol documents (Vec2Text 2023) |
Chacune doit être testée explicitement. Voir sécuriser un système RAG pour le contexte théorique.
Méthodologie de pentest en 7 phases
Phase 1 — Reconnaissance externe
# Scan ports par défaut
nmap -p 6333,6334,8080,8000,5432,9200 target.example
# Pinecone est SaaS, pas de port à scanner
# Qdrant : 6333 (REST), 6334 (gRPC)
# Weaviate : 8080 (REST), 50051 (gRPC)
# Chroma : 8000 (REST)
# pgvector : 5432 (Postgres)
# Recherche d'exposition Internet
# Shodan / Censys queries
# - "qdrant" port:6333
# - "weaviate" port:8080
# - "chroma" port:8000
# - cloud provider IPs avec ports vectorIdentifier toutes les instances joignables et leur version (banner grabbing).
Phase 2 — Authentification
| Test | Pinecone | Weaviate | Qdrant | Chroma | pgvector |
|---|---|---|---|---|---|
| API sans token | N/A (cloud) | Tester (peut être désactivée) | Tester | Tester | Tester |
| API avec token vide | Tester | Tester | Tester | Tester | N/A |
| API avec token leakée | Audit GitHub, env files | Idem | Idem | Idem | Idem |
| Scope d'un token API | Tester accès cross-namespace | Tester accès cross-class | Tester | Tester | RBAC postgres |
Phase 3 — Tenant / namespace isolation
# Test générique d'isolation tenant
def test_tenant_isolation(client, ns_a: str, ns_b: str):
canary = "TENANT_A_CANARY_3f4d92"
# Insérer canary dans ns_a
client.upsert(
namespace=ns_a,
vectors=[("canary_doc", embed(canary), {"text": canary})],
)
# Tenter requêtes depuis ns_b
test_queries = [
("avec namespace explicite ns_b", {"namespace": ns_b}),
("sans namespace", {}), # défaut éventuellement permissif
("avec metadata filter", {"namespace": ns_b, "filter": {}}),
]
leaked = []
for label, params in test_queries:
results = client.query(vector=embed(canary), top_k=10, **params)
if any(canary in r.metadata.get("text", "") for r in results):
leaked.append(label)
return leakedPhase 4 — Metadata filter abuse
Si l'application construit dynamiquement les filters depuis input utilisateur, tester l'injection :
# Cas vulnérable : filter construit depuis user input
def vulnerable_query(user_query: str, user_id: str, raw_metadata_filter: str):
# raw_metadata_filter vient d'un paramètre URL non validé
return vdb.query(
vector=embed(user_query),
filter=json.loads(raw_metadata_filter), # injection JSON possible
)
# Payload d'attaque
attack_filter = '{"$or": [{"user_id": "victim"}, {"user_id": "attacker"}]}'
# → renvoie les docs de victim sans authentificationTest : tenter de manipuler le filter pour élargir le scope au-delà du user authentifié.
Phase 5 — Snapshot et backup exposure
# Vérifier accessibilité des snapshots
# Qdrant : endpoint snapshots
curl -s http://target:6333/snapshots
curl -s http://target:6333/collections/{name}/snapshots
# S3 / GCS buckets de backup
# Lister les buckets liés au projet et tester accès anonymous
aws s3 ls s3://company-vector-db-backups --no-sign-request 2>&1Beaucoup de disclosures 2024-2025 viennent de buckets de backup mal configurés.
Phase 6 — Admin / management endpoints
# Qdrant
curl http://target:6333/collections # liste collections
curl http://target:6333/cluster # info cluster
curl -X POST http://target:6333/collections/test_create \
-d '{"vectors": {"size": 4, "distance": "Cosine"}}' # création
# Weaviate
curl http://target:8080/v1/schema # schema complet
curl http://target:8080/v1/.well-known/ready
curl http://target:8080/v1/meta # version + modules
# Chroma
curl http://target:8000/api/v1/heartbeat
curl http://target:8000/api/v1/collectionsVérifier auth requise pour : list, create, delete, reindex, snapshot.
Phase 7 — Embedding inversion
Si dump d'embeddings obtenu, tester la reconstruction des documents source :
import vec2text # https://github.com/jxmorris12/vec2text
# Charger le modèle d'inversion (entraîné par Morris et al.)
inversion_model = vec2text.load_pretrained_corrector("text-embedding-ada-002")
# Pour chaque embedding leaké
for embedding in leaked_embeddings[:100]:
reconstructed = vec2text.invert_embeddings(
embeddings=embedding.reshape(1, -1),
corrector=inversion_model,
num_steps=20,
)
print(f"Reconstructed: {reconstructed[0]}")Mesurer la fidélité de reconstruction (BLEU, ROUGE, ou inspection manuelle). Une fidélité élevée prouve l'équivalence dump ≈ fuite KB.
Spécificités par produit
Pinecone
Modèle : SaaS managé, multi-region. Authentification par API key. Isolation par index + namespace.
Surfaces typiques :
- API key over-scoped (donne accès tenant-wide alors qu'il devrait être limité).
- Application qui ne passe pas le
namespacedans les requêtes → query sur le namespace par défaut. - Metadata filters construits depuis input utilisateur sans validation.
Tests recommandés :
- Inventaire des API keys côté client (env files, GitHub leaks via gitleaks/trufflehog).
- Test d'isolation namespace (cf. phase 3).
- Vérifier que le SDK utilise bien le namespace dans toutes les opérations.
# Recherche d'API keys leakées
# trufflehog filesystem --regex '(pcsk_[a-zA-Z0-9-_]+)' --since-commit HEAD~100Weaviate
Modèle : self-hosted ou Weaviate Cloud. Auth via API key, OIDC, ou anonymous (par défaut sur certaines versions !). Isolation par class + multi-tenancy explicite.
Surfaces typiques :
- Auth désactivée par défaut historiquement → instance ouverte si exposée Internet.
- Modules d'inférence (
text2vec-openai, etc.) qui stockent des tokens API tiers en config. - Multi-tenancy non activée par défaut sur les anciennes versions.
- gRPC port (50051) parfois ouvert sans auth en plus du REST.
Tests recommandés :
GET /v1/.well-known/readysans auth → si réponse, instance probablement ouverte.GET /v1/schemasans auth → liste les classes (souvent suffisante pour une fuite).- Tester l'auth OIDC si configurée (validation des claims, expiration, audience).
- Audit configuration multi-tenant :
tenant: <name>doit être strict.
Qdrant
Modèle : self-hosted ou Qdrant Cloud. Auth via API key (à activer explicitement). Isolation par collection + champ payload.
Surfaces typiques :
- Auth désactivée par défaut sur self-hosted → exposé public dangereux.
- Snapshots endpoint (
/snapshots,/collections/{}/snapshots) parfois sans auth séparée. - Collection management endpoints ouverts.
- gRPC port 6334 oublié dans les firewalls qui bloquent le 6333.
Tests recommandés :
GET /→ renvoie info serveur si pas d'auth.- Tester
GET /collectionspour l'énumération. - Tester création de collection :
POST /collections/test. - Vérifier configuration snapshots : doivent être stockés dans un volume sécurisé, pas dans l'output mounted.
# Test rapide d'exposition
curl -sI http://target:6333/collections
# 200 OK sans auth = problèmeChroma
Modèle : pensé initialement pour dev local. v0.4+ ajoute des options de déploiement serveur. Auth limitée nativement, à mettre derrière un reverse proxy.
Surfaces typiques :
- Pas d'auth native dans les versions précoces — toujours auth via reverse proxy.
- Mode "in-memory" exposé sans persistence sécurisée.
- API REST standard avec endpoints de gestion non protégés si pas de proxy.
- HTTP par défaut, à passer en HTTPS via reverse proxy.
Tests recommandés :
GET /api/v1/heartbeat→ confirme exposition.GET /api/v1/collections→ énumération.- Vérifier le reverse proxy : auth, TLS, rate limit, IP allowlist.
pgvector
Modèle : extension Postgres. Hérite de toute la sécurité Postgres. Isolation possible via Row-Level Security (RLS).
Surfaces typiques :
- RLS non activée → SELECT classique bypass tous les filtres logiques.
- pg_hba.conf permissif (
trustau lieu demd5ouscram-sha-256). - Connection pooling (PgBouncer, etc.) qui partage les credentials.
- Embedding column stockée en clair sur disque sans chiffrement.
Tests recommandés :
- Audit pg_hba.conf, postgresql.conf.
SHOW row_security;doit être ON pour les schemas multi-tenant.- Test RLS : se connecter avec un user et tenter SELECT sur des données d'un autre tenant.
- Audit des extensions actives (
SELECT * FROM pg_extension) — pas seulement vector.
Outils
| Outil | Usage |
|---|---|
nmap | Scan ports par défaut |
| Shodan / Censys | Détection exposition Internet |
| Burp Suite / Postman | Test API |
trufflehog / gitleaks | Recherche d'API keys leakées |
| Custom Python (SDK officiel) | Test d'isolation tenant et metadata filter abuse |
vec2text | Embedding inversion |
nuclei (templates custom) | Tests automatisés sur multiple instances |
Trivy / Checkov | Audit configurations K8s/Docker/Terraform |
| Garak (NVIDIA) | Tests RAG-level (au-dessus de la VDB) |
Checklist 30 contrôles
A — Réseau et exposition
- Ports par défaut (6333, 8080, 8000, 5432) firewallés.
- Pas d'instance accessible Internet sans VPN/PrivateLink.
- TLS forcé sur tous les endpoints.
- Pas d'IP publique sur le service VDB en cloud (privé only).
- Rate limiting au niveau load balancer / WAF.
B — Authentification
- Auth obligatoire (jamais désactivée).
- Tokens API rotables, scope minimum.
- Pas de tokens en clair dans GitHub / env files / configs publiques.
- OIDC validé strictement si utilisé (claims, exp, aud).
- Endpoints admin avec auth séparée et plus stricte.
C — Tenant et ACL
- Tenant_id (namespace) en filter dur, pas optionnel.
- ACL propagées en metadata des vecteurs.
- Pre-filter au niveau VDB (pas seulement post-filter applicatif).
- Test d'isolation effectif (canary token cross-tenant).
- Multi-tenancy native activée (pour Weaviate, etc.).
D — Données et chiffrement
- Chiffrement at-rest natif activé (cloud) ou volume chiffré (self-hosted).
- Snapshots/backups chiffrés.
- Snapshots non accessibles publiquement (S3/GCS bucket policies).
- Embeddings traités comme données sensibles (équivalent KB en clair).
- Pas de données sensibles dans les metadata indexées si les metadata sont moins protégés.
E — Logs et monitoring
- Logs structurés des requêtes (qui, quoi, quand).
- Alertes sur volume anormal (extraction probable).
- Alertes sur tentatives d'auth échouées.
- Audit des modifications de schema / collections.
- Métriques de coverage (pour détecter scanning).
F — Operations
- Version VDB à jour, CVE patchées.
- Configuration RBAC documentée.
- Procédure de rotation de tokens.
- Plan de réponse à incident (compromission VDB = data breach).
- Audit de pentest annuel + à chaque release majeure.
Mapping OWASP LLM Top 10 v2
| OWASP | Lien VDB pentest |
|---|---|
| LLM02 Sensitive Information Disclosure | Fuite via misconfig, ACL, embedding inversion |
| LLM04 Data and Model Poisoning | Corpus poisoning via VDB compromise |
| LLM08 Vector and Embedding Weaknesses | Catégorie centrale |
| LLM03 Supply Chain | VDB cloud/SDK comme dépendance externe |
LLM08 reste la catégorie de référence. Les pentests VDB sont la déclinaison opérationnelle de cette catégorie.
Points clés à retenir
- 7 surfaces communes à toutes les VDB : auth, network, tenant isolation, metadata filter, snapshots, admin endpoints, embedding inversion.
- Méthodologie 7 phases : recon → auth → isolation → filter abuse → snapshots → admin → inversion.
- Spécificités produit : Pinecone (API keys + namespaces), Weaviate (auth historiquement off + modules), Qdrant (auth off par défaut self-hosted + 6334 oublié), Chroma (pensé dev, exiger reverse proxy auth), pgvector (RLS obligatoire en multi-tenant).
- Tests d'isolation tenant : insérer canary, requérir depuis autre tenant, vérifier absence.
- Embedding inversion via
vec2text: prouver l'équivalence dump ≈ fuite KB. - Outils incontournables : nmap, Shodan/Censys, Burp, trufflehog/gitleaks, vec2text, scripts custom.
- Checklist 30 contrôles : réseau (5), auth (5), tenant/ACL (5), chiffrement (5), logs (5), ops (5).
- Sur Pinecone (SaaS), majorité des fuites = API keys mal scopées côté client, pas bugs serveur.
- Sur self-hosted (Weaviate, Qdrant, Chroma), majorité des fuites = auth absente par configuration.
Pentester une vector database, c'est traiter une couche d'infrastructure critique avec la même rigueur qu'une base de données relationnelle. Les outils sont matures, la méthodologie est documentée, les patterns d'erreur sont stables. Reste à intégrer cet audit aux cycles de sécurité existants (annuel + release majeure).







