Summary
The Thanos Receive component's gRPC RemoteWrite handler does not validate the tenant field, unlike the equivalent HTTP path which calls tenancy.IsTenantValid(). An unauthenticated remote attacker can set the tenant to a path traversal payload (e.g., ../../../../tmp/evil), causing tsdb.Open() to create TSDB data directories (WAL, chunks_head, lock) at arbitrary locations on the server filesystem.
Impact
CVSS 7.5 (High) — Arbitrary directory creation + disk exhaustion via TSDB WAL writes. The gRPC port defaults to 0.0.0.0:10901 with no authentication and no TLS by default.
Details
HTTP path (correctly validated):
// pkg/receive/handler.go:518
tenantID, tenantErr := tenancy.GetTenantFromHTTP(r, ...)
// → calls tenancy.IsTenantValid() → path.Base check
gRPC path (NOT validated):
// pkg/receive/handler.go:1167
func (h *Handler) RemoteWrite(ctx context.Context, r *storepb.WriteRequest) (*storepb.WriteResponse, error) {
if h.ingestorOnly {
return nil, h.writer.Write(ctx, r.Tenant, r.Timeseries) // No validation
}
return nil, h.handleRequest(ctx, rep, r.Tenant, wreq) // No validation
}
Path traversal via path.Join:
// pkg/receive/multitsdb.go
func (t *multiTSDB) defaultTenantDataDir(tenantID string) string {
return path.Join(t.dataDir, tenantID)
// path.Join("/data/receive", "../../../../tmp/evil") = "/tmp/evil"
}
Go's path.Join resolves .. sequences, so ../../../../tmp/evil traverses out of the data directory.
Attack chain:
- Connect to gRPC port (0.0.0.0:10901, no auth)
- Send WriteRequest with tenant =
../../../../tmp/evil
tsdb.Open("/tmp/evil", ...) creates WAL, chunks_head, and lock files
- Continuous writes fill disk → DoS
Suggested Fix
Add tenant validation in RemoteWrite():
func (h *Handler) RemoteWrite(ctx context.Context, r *storepb.WriteRequest) (*storepb.WriteResponse, error) {
if !tenancy.IsTenantValid(r.Tenant) {
return nil, status.Error(codes.InvalidArgument, "tenant is not valid")
}
// ...
}
Workarounds
- Enable gRPC TLS with client certificate authentication
- Restrict network access to gRPC port 10901
References
- CWE-22: Path Traversal
- CWE-306: Missing Authentication for Critical Function
Discoverer
IcySun (icysun@qq.com)
We request CVE assignment for this vulnerability.
Summary
The Thanos Receive component's gRPC
RemoteWritehandler does not validate thetenantfield, unlike the equivalent HTTP path which callstenancy.IsTenantValid(). An unauthenticated remote attacker can set the tenant to a path traversal payload (e.g.,../../../../tmp/evil), causingtsdb.Open()to create TSDB data directories (WAL, chunks_head, lock) at arbitrary locations on the server filesystem.Impact
CVSS 7.5 (High) — Arbitrary directory creation + disk exhaustion via TSDB WAL writes. The gRPC port defaults to
0.0.0.0:10901with no authentication and no TLS by default.Details
HTTP path (correctly validated):
gRPC path (NOT validated):
Path traversal via path.Join:
Go's
path.Joinresolves..sequences, so../../../../tmp/eviltraverses out of the data directory.Attack chain:
../../../../tmp/eviltsdb.Open("/tmp/evil", ...)creates WAL, chunks_head, and lock filesSuggested Fix
Add tenant validation in
RemoteWrite():Workarounds
References
Discoverer
IcySun (icysun@qq.com)
We request CVE assignment for this vulnerability.