PAC-X009 · unanchored-substring-pattern

Pattern with leading and trailing * is a substring match

high · Security and fail-safety

shExpMatch(host, "*example.com*") or shExpMatch(url, "*abc*") is true for any string that contains the characters anywhere. Over url this includes query strings an attacker controls; over host it includes look-alike domains.

Why it matters

A glob that starts and ends with * is a contains-test. shExpMatch(url, "*example.com*") matches http://evil.test/?r=example.com; whoever controls a link controls the query string, so the branch (typically DIRECT) is reachable for any destination. Over host, *abc* matches abc.test, xyzabc.example and example.com.abc-attacker.test.

Patterns that contain :// or end in /* are anchored at the scheme or path boundary and are not flagged. The grade is capped at C because the bypass is externally triggerable without any control over DNS or the network.

How to fix

Anchor the pattern: use host with "*.example.com" / host == "example.com", or a URL pattern with scheme and path boundaries ("http://www.example.com/*").

Examples

Bad

function FindProxyForURL(url, host) {
  if (shExpMatch(url, "*example.com*")) {
    return "DIRECT";
  }
  return "PROXY proxy.corp.example:8080";
}
Open bad example in checker

Good

function FindProxyForURL(url, host) {
  if (host == "example.com" || shExpMatch(host, "*.example.com")) {
    return "DIRECT";
  }
  return "PROXY proxy.corp.example:8080";
}
Open good example in checker

Related rules

References