Skip to main content

Security hardening validation โ€” September 2026

Baseline: 32dff5b1b7bf520eb748dfd6857bfc7cb4cb28b8 (v1.66.1). This review followed the architecture, security, compatibility, fleet-cache and peer-cache documentation, plus the historical tenant-label and secure-defaults designs. The objective is to preserve Grafana visibility, tenant boundaries, progressive metadata loading and historical cache reuse while making execution bounded and failures visible. It is not a certification of every deployment.

Findings and review unitsโ€‹

FindingsFix and regression coverageReview
Label routing admitted unmapped wildcard tenants; tail allocated unbounded client messages; security lane skipped intended testsDeny unsafe wildcard before label-mode shortcut; 4 KiB fragmented-message bound preserving control frames; enumerate security test selectionPolicy and tail
Cold reads lost native tenant headers; reload reused old-scope cached data; implicit trusted identity was absent from cache keys; field batching lost request contextImmutable admission scope across hot/cold, caches, coalescers and background work; consistent identity forwarding/fingerprints; scope-aware label indexTenant isolation
Appended label constraint broke LogsQL pipelinesUse backend-enforced JSON extra_stream_filters; verify enforcement with foreign data presentTenant isolation
Rounded final-response keys mixed disjoint time windows and tuple profiles; cold benchmark mostly measured hitsExact response contract keys; preserve metadata/aligned-window caches; verify one upstream call per benchmark operationCache contracts
Unbounded subquery work, backend fanout and template expansion; upstream failures became successful empty resultsTotal evaluation/byte/sample limits, fixed worker pool, body-lifetime backend permits, bounded template execution and error propagationExecution limits
Expired unread disk entries blocked admission; oversized coalesced responses were truncatedIncremental expiry sweep even without writes; explicit response-size errors and bounded buffer retentionExecution limits
Vulnerable documentation image parser dependencyIntegrity-checked CJS/ESM patch and timeout-isolated tests; reduced build permissions/timeoutsDocs hardening
Live parity exposed backtick formatting, skipped production tuple evaluation, and range-wide topk rankingDecode template literals, format real tuple shapes, preserve categorized fields, enforce budgets before streaming, rank at each timestampIntegration #525; production-route unit tests and live API/browser checks

Measured compatibilityโ€‹

All live checks used isolated local Compose projects and dedicated ports/data. Existing development containers and production deployments were not modified.

Stack/checkObserved result
VictoriaLogs v1.30.0 (measured before the support change), v1.50.0, v1.52.0Native and label tenants isolated across hot/cold reads with caches enabled and disabled; repeated requests return own data and exclude foreign/default data. Nine tests per version including subtests.
Loki 3.6.0 and 3.7.1, VL v1.50.0Identical visible lines for disjoint one-second windows in the same former cache bucket, repeated requests, backtick formatting and escaped printf literals. Changing topk/bottomk winners match at each timestamp for rate and count_over_time.
Grafana 13.0.1 / Logs Drilldown 2.0.4Three strict browser tests pass across direct Loki, normal proxy and native-metadata proxy: 18 page states verify exact marker presence/absence and formatted text. Plugin version verified through Grafana API.
Grafana synthetic and ingress tailTwo tests require newly ingested markers in visible live log rows, beyond merely opening WebSockets. Both pass.
Broader Explore / Drilldown browser suite107 passed and 12 existing explicit skips across eight suites. After the final scope/cache performance change, all 18 focused Explore/Drilldown/visibility tests passed again. Skips remain gaps, not passes.
Go unit suite and race detectorFull final suite: 4,816 tests passed across 14 packages with go test -race ./... -count=1 on revision 5c33387, including empty-window ranking and scope/cache performance fixes. CI status is recorded in the integration PR.
Static/runtime dependency checksgo vet ./... passed; govulncheck@latest ./... reported no reachable Go vulnerabilities at review time.
WebsiteFresh npm ci verifies all 20 patched bundles; two CJS/ESM subprocess regression groups pass; production build passed. Registry audit still flags 18 affected dependency-tree entries from two image-size advisories.

The requested current-version review additionally ran on Loki 3.7.7, Grafana 13.2.1 and Logs Drilldown 2.5.2, with runtime versions verified through their APIs. All 107 selected browser tests passed with the same 12 existing skips, both before and after the final empty-window ranking fix. Live tenant, exact-window and formatting tests pass; topk/bottomk tests now also cover empty leading/trailing windows and byte-based aggregations. The Compose review override pins these versions for reproducible manual acceptance.

The final scope/cache implementation avoids repeated configuration serialization on cache hits. Local Apple M5 measurements (GOMAXPROCS=1, three one-second runs) were 1.73โ€“2.01 ยตs / 872 B / 14 allocations for query-range hits and 497โ€“517 ns / 48 B / 3 allocations for label hits. These are local microbenchmarks, not a production latency guarantee; the integration PR also runs the CI comparison.

The live version sample covers the oldest VL support band, pinned runtime and newer packaging, and both supported Loki minor families. It does not replace the complete patch-version matrix in test/e2e-compat/compatibility-matrix.json.

Reproduce the new gatesโ€‹

Start the existing compatibility stack, then supply its actual endpoints:

LOKI_URL=http://127.0.0.1:13101 PROXY_URL=http://127.0.0.1:13100 \
VL_URL=http://127.0.0.1:19428 \
go test -tags=e2e ./test/e2e-compat -run '^TestHardeningLive_' -count=1

cd test/e2e-ui
GRAFANA_URL=http://127.0.0.1:3002 VL_URL=http://127.0.0.1:19428 \
LOKI_URL=http://127.0.0.1:13101 \
npx playwright test tests/security-hardening-visibility.spec.ts tests/explore.spec.ts

The security CI script selects TestHardeningLive_*; the browser additions carry the existing @explore-core and @explore-tail tags. Test ingestion URLs now honor environment overrides so custom-port runs cannot seed another local stack. The manual acceptance guide includes per-PR changes, expected results and the rebuild procedure after every approved merge.

Compatibility and remaining readiness workโ€‹

These fixes are not wholly free of behavior changes. Unsafe wildcard requests, oversized client tail messages and excessive query work are rejected. Exact cache keys invalidate old entries and can increase misses. Formatting buffers before responding. Range topk may expose more than k changing winners. Read the migration guide before rollout.

Delete remains unsupported: the always-registered /loki/api/v1/delete handler targets a path VictoriaLogs rejects, and no adapter for VL's asynchronous deletion API exists. The existing browser suite also contains explicit known-gap skips and permissive legacy assertions. The new strict tests do not turn those gaps into guarantees.

A separate correction of the legacy exhaustive helper exposed a serious test limitation: it sends millisecond integers, which Loki treats as nanoseconds, and therefore often compares an empty epoch window with current proxy data. An isolated run without the UI generator confirmed invalid-IP and parser-error mismatches and invalid binary matching. Strict value checks also exposed quantile errors and a warmed-field-mapping regexp capture defect. Earlier reference timeouts and aggregate resource failures on a long-running generator stack are not isolated reproductions. These defects (IP validation, parser-error ordering, implicit many-to-one binary matching, quantile grouping and the regexp capture rewrite) were fixed in v1.68.0; the measured baseline, corrections and remaining limits are in real-window compatibility findings. The legacy suite's green status is not execution-parity evidence. The malformed-template hardening regression uses seeded data and correct timestamps directly.

The pre-merge review additionally reproduced a hot/cold merge stall with one backend permit: 502 at a 250 ms request deadline. Consuming bounded response bodies inside their workers restored a successful two-backend response. The new forward/backward and body-failure regressions and the full uncached race suite pass with this correction.

Before broad shared production rollout, run the full supported-version matrix, a representative concurrent/tenant workload soak, backend outage and disk-full fault injection, and a canary watching rejected queries, queue wait, backend calls, cache misses, memory and query latency. Remaining test priorities are strict parsed-field filter interactions, multi-stage formatting order, alerting behavior on partial backend failure, and tenant-scoped peer/persisted cache restarts under configuration reload. Retain the local image-size patch only until a verified upstream fix can replace it; see website/SECURITY.md.

Upstream contracts checked: Loki HTTP API, Loki template functions, VL query constraints, VL security model.