Skip to content

Receive gRPC RemoteWrite: Tenant field not validated (path traversal) #8812

@icysun

Description

@icysun

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:

  1. Connect to gRPC port (0.0.0.0:10901, no auth)
  2. Send WriteRequest with tenant = ../../../../tmp/evil
  3. tsdb.Open("/tmp/evil", ...) creates WAL, chunks_head, and lock files
  4. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions