Repository navigation
Description
Summary
The tenant hostname ValidatingAdmissionPolicy objects compare hostnames against the tenant apex using case-sensitive CEL operators (==, endsWith, startsWith). Automated review of #3200 flagged this as a potential case-based bypass.
It is not a live issue: the Kubernetes apiserver validates Ingress spec.rules[].host / spec.tls[].hosts[] and Gateway API hostnames as DNS-1123 (sub)domains, which reject any uppercase character (kubernetes/kubernetes#71140). A mixed-case hostname is therefore rejected by built-in validation and can never be persisted, so these policies only ever see already-lowercased hosts.
Still, normalizing with .lowerAscii() before the comparisons is cheap defense-in-depth — robust against any future validation change, and consistent with reviewer expectations. It should be applied uniformly across all three policies rather than just one.
Scope
Apply case-insensitive comparison (.lowerAscii() on both the hostname and the apex / root-host literal), plus a mixed-case test, to:
cozystack-ingress-hostname-policy(packages/system/cozystack-basics/templates/ingress-hostname-policy.yaml)cozystack-gateway-hostname-policy(packages/system/cozystack-basics/templates/gateway-hostname-policy.yaml)cozystack-route-hostname-policy(packages/system/cozystack-basics/templates/route-hostname-policy.yaml)
Update the matching helm-unittest and hack/e2e-apps/gateway.bats coverage.
Notes
- fix(cozystack-basics): validate legacy Ingress hostnames against the tenant apex #3200 (which introduces the ingress policy) intentionally ships with the current case-sensitive comparison — no change there; this is a consolidated follow-up.
- Priority: low (hardening, not a live vulnerability).
Activity
lexfrei commentedon Jul 16, 2026
Re-labelled after checking the uppercase-root-host half against the rendered CEL rather than the description.
This issue reads the problem as hardening, on the grounds that the resource-side host is validated lowercase so casing cannot be used to sidestep the comparison. That holds for the hostname operand. It does not hold for the two apex operands: the
namespace.cozystack.io/hostlabel value (Kubernetes permits uppercase in a label value) and the templated_cluster.root-host, which is free-form platform config — the platform chart has novalues.schema.json, and the value is read verbatim from thecozystackConfigMap. The Ingress policy templates that value into its outside-root exclusion.With
root-host: Example.ORG, the exclusion compares a lowercase host against the uppercase literal, never matches, and so stops excluding — the policy then admits any non-wildcard host. Evaluated with cel-go against the rendered pre-fix expression, a tenant whose apex isalice.example.orgis admitted fordashboard.example.org, for another tenant'svictim.example.org, and for the bare root apexexample.org. Post-fix all three are denied, and the anti-wildcard gate holds in both.That is a bypass of the control rather than defense-in-depth, hence
security/low→security/mediumandkind/cleanup→kind/bug. It stays belowhighbecause it is not tenant-reachable: only a trusted caller can set the root host, and a cluster carrying an uppercase one is already visibly broken, since the dashboard's own Ingress renders mixed-case and is rejected by hostname validation before it exists.priority/important-soonbecause the Ingress policy has only shipped in 1.6.0-rc so far — no stable release carries this, so no backport is needed, but it should land before 1.6.0 GA.fix(cozystack-basics): normalize tenant hostname VAP comparisons with…