PAC file tester: check your proxy.pac before your users do
A PAC file decides, for every request, whether traffic goes through your proxy or straight to the internet. Small mistakes route traffic around the proxy without anyone noticing. This free online PAC file tester runs your proxy.pac or wpad.dat in the Chromium, Firefox, pacparser or Windows engine profile you choose, traces a URL through it step by step, explains every finding and grades the file from A+ to F.
No PAC file yet? Create one with the PAC file generator, or copy one of the PAC file examples.
Spot the 5 mistakes
This PAC looks reasonable and works in a quick test. It still has five problems that each send traffic past the proxy or slow every request down.
// proxy.pac - sample with 5 deliberate mistakes. Can you spot them?
function FindProxyForURL(url, host) {
// internal servers go direct
if (dnsDomainIs(host, "corp.example")) {
return "DIRECT";
}
// partner portal is reachable without the proxy
if (shExpMatch(url, "*partner.example.com*")) {
return "DIRECT";
}
// private address space goes direct
if (shExpMatch(host, "10.*")) {
return "DIRECT";
}
if (isInNet(host, "192.168.0.0", "255.255.0.0")) {
return "DIRECT";
}
if (shExpMatch(host, "*.example.net")) {
return "PROXY proxy.corp.example:8080";
}
}
Open this PAC in the checkerThe mistakes
- Line 4: "corp.example" without a leading dot also matches evilcorp.example, so a look-alike domain bypasses the proxy. PAC-X003: dnsDomainIs pattern without a leading dot matches look-alike domains
- Line 8: shExpMatch on url instead of host: any URL with "partner.example.com" in its path or query string goes direct. PAC-C001: Hostname pattern applied to url instead of host
- Line 12: "10.*" is a text prefix, not a network. It matches the public host name 10.example.com and every 10.x name. PAC-X006: IP range matched as a text prefix
- Line 15: isInNet on a host name triggers a blocking DNS lookup for every request, and gives a different answer inside and outside the network. PAC-P002: isInNet called with a hostname
- Line 21: No unconditional return at the end: every other host gets undefined, which browsers treat as DIRECT. Traffic silently bypasses the proxy. PAC-X001: No unconditional return at the end of FindProxyForURL
What the checker does
- Parses your file and runs it for your URL and client IP in the engine profile you choose, inside a sandboxed worker in your browser.
- Shows a live trace of the path the script took: each test with true or false, each call with its arguments and result, and the line that decided. The quickest way to find out why a URL goes the wrong way; see PAC file troubleshooting.
- Annotates your file: an explanation comment above each rule, in plain words, which you can copy or download.
- Lets you set what
myIpAddress(), DNS lookups and the date and time return, so location- and time-based rules can be tested. - Keeps your file in your browser: it runs in a sandboxed worker on a separate origin, and only anonymised facts are sent for the grade.
- Rates the file A+ to F across errors, security, correctness, compatibility, performance and best practice.
- Optionally checks delivery from pasted
curl -sIheaders.
Reference
- The 20 most dangerous PAC mistakes
- PAC function reference with per-engine availability
- Engine profiles: how Chromium, Firefox, pacparser and Windows differ
- WPAD and wpad.dat: discovery and its risks
Latest articles
- dateRange and timeRange are always false on Windows
In a PAC file on Windows, dateRange() and timeRange() return false for every argument, so time-based proxy rules never apply. What works and what to do.
- Windows runs PAC files differently from Chrome and Firefox
Windows answers some proxy.pac calls differently from Chrome and Firefox, from dateRange to shExpMatch and newer JavaScript. What differs and how to test.
- pactester vs Chrome, Edge, Firefox and Windows: why a PAC file passes in pactester and fails in the browser
pactester (pacparser) does not always answer like Chrome, Edge, Firefox or Windows WinHTTP. Which PAC functions differ, and how to test your proxy.pac.
A minimal correct PAC
function FindProxyForURL(url, host) {
host = host.toLowerCase();
// internal names and domains go direct
if (isPlainHostName(host) || dnsDomainIs(host, ".corp.example")) {
return "DIRECT";
}
// default route: always the last statement
return "PROXY proxy1.corp.example:8080; PROXY proxy2.corp.example:8080";
}