Meilisearch is a fast, open-source Rust-based search engine popular for adding full-text search to web applications — its simplicity and ease of deployment also make it one of the more commonly misconfigured data services. When Meilisearch is launched without a --master-key argument, the entire API requires no authentication — any client on the network can list all indices, retrieve all indexed documents page by page via the /indexes/{uid}/documents endpoint, execute searches returning all matching document fields, and trigger full database exports via the /dumps endpoint; when a master key is set, Meilisearch auto-generates default API keys that developers embed in client-side JavaScript for direct browser-to-Meilisearch search — a search-only key exposed in JavaScript gives read access to all indexed content; if the master key itself is embedded in client-side code, all derived keys can be regenerated and full administrative access is possible; and Meilisearch's /health and /version endpoints always respond without authentication, confirming the service presence. This guide covers systematic Meilisearch security assessment.
# Meilisearch default port: 7700
# Always responds to /health without authentication
# Check Meilisearch health (responds regardless of auth config)
curl -s http://meilisearch.example.com:7700/health 2>/dev/null
# Returns: {"status":"available"}
# Get version (no auth required)
curl -s http://meilisearch.example.com:7700/version 2>/dev/null | \
python3 -c "
import json,sys
data = json.load(sys.stdin)
print(f\"Meilisearch version: {data.get('pkgVersion','?')}\")
" 2>/dev/null
# Check if authentication is required
AUTH_STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
http://meilisearch.example.com:7700/indexes 2>/dev/null)
if [ "$AUTH_STATUS" == "200" ]; then
echo "CRITICAL: Meilisearch running without master key — no authentication required"
elif [ "$AUTH_STATUS" == "401" ]; then
echo "Authentication enforced — master key is set"
fi
# When no master key is set, the entire API is open
# List all indices (exposes all search data namespaces)
curl -s "http://meilisearch.example.com:7700/indexes?limit=100" 2>/dev/null | \
python3 -c "
import json,sys
data = json.load(sys.stdin)
results = data.get('results', [])
print(f'Indices: {len(results)}')
for idx in results:
print(f\" {idx['uid']:40} docs={idx.get('numberOfDocuments',0):>8} primary_key={idx.get('primaryKey','?')}\")
" 2>/dev/null
# Retrieve all documents from a specific index (paginate to get everything)
INDEX_UID="your-index-name"
OFFSET=0
LIMIT=1000
while true; do
RESPONSE=$(curl -s \
"http://meilisearch.example.com:7700/indexes/${INDEX_UID}/documents?limit=${LIMIT}&offset=${OFFSET}" \
2>/dev/null)
COUNT=$(echo "$RESPONSE" | python3 -c "
import json,sys
data = json.load(sys.stdin)
results = data.get('results',[])
print(len(results))
" 2>/dev/null)
if [ "$COUNT" == "0" ]; then break; fi
echo "$RESPONSE" >> /tmp/meilisearch_dump_${INDEX_UID}.json
echo "Retrieved ${COUNT} docs at offset ${OFFSET}"
OFFSET=$((OFFSET + LIMIT))
done
# Trigger a full database dump (exports all indices to a .dump file on the server)
curl -s -X POST "http://meilisearch.example.com:7700/dumps" \
-H "Content-Type: application/json" 2>/dev/null | \
python3 -c "
import json,sys
data = json.load(sys.stdin)
print(f'Dump task UID: {data.get(\"taskUid\",\"failed\")}')
" 2>/dev/null
--master-key <strong-random-value> or the MEILI_MASTER_KEY environment variable; without a master key, there is no authentication whatsoeverindexes restriction in API key configuration to prevent a key for one index from accessing others| Security Test | Method | Risk |
|---|---|---|
| Meilisearch running without master key (no authentication) | GET /indexes returns 200 without Authorization header — complete API access without credentials | Critical |
| All indexed documents retrievable via /documents endpoint | GET /indexes/{uid}/documents — paginates through all documents returning full raw content | Critical |
| Full database dump via /dumps endpoint | POST /dumps — exports all Meilisearch data to a .dump file on the server | Critical |
| Search-only API key in client-side JavaScript | Read page source for Authorization headers or meili_search_key strings — search key reads all indexed content | High |
| Master key exposed in client-side JavaScript or environment dump | Grep JS bundles for MEILI_MASTER_KEY — master key allows creating admin API keys | Critical |
| API key listing via /keys endpoint | GET /keys with admin key — lists all API keys including their permissions and index scopes | High |
Ironimo tests Meilisearch deployments for instances running without a master key giving complete unauthenticated API access including document retrieval and database dumps, client-side JavaScript embedding the master key or admin API keys enabling full administrative access, search-only API keys exposed in public JavaScript allowing enumeration of all indexed document content, the /dumps endpoint accessible without administrative authorization enabling full data export, and sensitive fields indexed in Meilisearch that should not be searchable or accessible via the search API.
Start free scan