The WAF decides the app. The app label on logs and policies comes only from the WAF's own
host-to-app routing, never from a client header.
Strip before set. Every WAF-owned header (X-Client-*, X-WAF-*, X-Bot-*, X-Request-ID,
X-Origin-Auth, X-TLS-JA4) and every client-supplied forwarding header (X-Forwarded-For,
Forwarded, X-Real-IP, X-Forwarded-Host) is deleted on the way in, then set by the WAF if the
app enables it. Forged values never reach an origin.
Origin secret: an optional per-app X-Origin-Auth header lets the origin reject anything that
didn't come through the WAF.
Config validation: every rendered HAProxy config is checked with haproxy -c before it goes
live; a failed deploy leaves the previous config running.
Control-plane data is never templated. All strings from the control plane are marked unsafe
for Ansible templating, so free-text fields such as a robots.txt section or a header value can't
execute template code on the deploy runner.
Secrets are never logged: secret-handling tasks run with no_log, and deploy logs posted back to the
GUI exclude them. Rotation steps are in the WAF repository's runbook.