Trailing * in a host pattern matches attacker-controlled suffixes
high
shExpMatch(host, "example.com*") matches example.com.evil.test and example.comms.test. Anyone who controls a domain can append the trusted name as a subdomain label and inherit the rule.
Why it matters
shExpMatch is a glob over the whole string. A trailing * after a hostname does not mean
“this domain”; it means “any string that starts with these characters”. example.com*
matches example.com.evil.test (lab, 2026-05-20), example.com-cdn.test and
example.comms.test. Registering such names requires no cooperation from the owner of
example.com. If the rule grants DIRECT or a privileged proxy, an attacker gets the same
treatment for a host they control. A trailing * after an IP prefix (192.168.1.1*) has
the same problem and additionally matches 192.168.1.10 through 192.168.1.19.
Trailing * is legitimate in URL patterns after a slash (http://intranet.corp.example/*)
where it stands for the path.
How to fix
Match the domain exactly (host == "example.com") and its subdomains with "*.example.com" or dnsDomainIs(host, ".example.com"); never end a host pattern with *.
Examples
Bad
function FindProxyForURL(url, host) {
if (shExpMatch(host, "example.com*")) {
return "DIRECT";
}
return "PROXY proxy.corp.example:8080";
}
Open bad example in checkerGood
function FindProxyForURL(url, host) {
if (host == "example.com" || shExpMatch(host, "*.example.com")) {
return "DIRECT";
}
return "PROXY proxy.corp.example:8080";
}
Open good example in checkerEngine behaviour
| Engine | Behaviour | Source |
|---|---|---|
| pacparser | "example.com*" matches example.com.evil.test | lab, verified 2026-05-20 |
Related rules
- Leading * without a dot matches look-alike domains PAC-X004
- Wildcard inside a domain label PAC-X012
- Pattern with leading and trailing * is a substring match PAC-X009
- IP range matched as a text prefix PAC-X006