PAC-C020 · zscaler-forwarding-and-app-pac-mixed

Forwarding Profile and App Profile roles mixed in one Zscaler Client Connector PAC

high · Correctness

Zscaler Client Connector uses two PAC files with different jobs. The Forwarding Profile PAC steers traffic to the client (${ZAPP_LOCAL_PROXY}) or around it; the App Profile PAC sends what the client received to the cloud (${GATEWAY}). A file that does both is used in the wrong slot somewhere.

Why it matters

In Tunnel mode Zscaler’s guidance is explicit: use the Forwarding Profile PAC only to bypass traffic away from Zscaler Client Connector or to steer it to the client, never to tunnel traffic to the Zscaler cloud. In Tunnel with Local Proxy mode the Forwarding Profile PAC must return PROXY ${ZAPP_LOCAL_PROXY}, which the client replaces with its loopback listener, and the App Profile PAC then chooses the data centre with ${GATEWAY}. When one file contains both ${ZAPP_LOCAL_PROXY} (or ${ZAPP_TUNNEL2_BYPASS}) and ${GATEWAY}, either the browser is sent straight to a Public Service Edge, skipping the client and its tunnel, or the client is asked to forward to itself. Keep the two files separate and keep the App Profile PAC as simple as possible.

How to fix

Split the file. Forwarding Profile PAC returns ${ZAPP_LOCAL_PROXY} / ${ZAPP_TUNNEL2_BYPASS} and DIRECT only; the App Profile PAC returns ${GATEWAY} / ${SECONDARY_GATEWAY} and the cloud-side exceptions.

Examples

Bad

function FindProxyForURL(url, host) {
  if (isPlainHostName(host)) {
    return "DIRECT";
  }
  if (dnsDomainIs(host, ".partner.example.net")) {
    return "PROXY ${GATEWAY}:80; PROXY ${SECONDARY_GATEWAY}:80";
  }
  return "PROXY ${ZAPP_LOCAL_PROXY}";
}
Open bad example in checker

Good

function FindProxyForURL(url, host) {
  if (isPlainHostName(host)) {
    return "DIRECT";
  }
  return "PROXY ${ZAPP_LOCAL_PROXY}";
}
Open good example in checker

Zscaler pack only. The good example is a Forwarding Profile PAC for Tunnel with Local Proxy mode.

Related rules

References