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.

Test a PAC file Browse the rules

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 checker

The mistakes

  1. 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
  2. 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
  3. 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
  4. 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
  5. 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 -sI headers.

Reference

Latest articles

All articles

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";
}