When a request matches ZAP's proxy exclude list, does it still reach the target host?
answer
- it marks, it does not refuse
- the sender handler ignores the mark
- listener notification is what gets switched off
- the client still gets a real response
- a noise filter, not a boundary
basics
~20 sYes. On the proxy path, exclusion marks a message rather than blocking it: the pipeline's final handler still sends it, with listener notification switched off. The host is reached and answers; only the record is suppressed.
solid answer
~40 sIt still reaches the host. In the `network` add-on, the local-server handler tests a proxied request against the global exclusion regexes and the session's exclude-from-proxy list and records the verdict on the handling context — it does not return early. Handlers built on the "non-excluded messages only" base are then skipped, but the sender handler is not built on that base: it is the final handler in the pipeline and it sends the message anyway, with a request configuration whose listener notification is off, then marks the context overridden. The response is written back to the client normally. So a proxy exclusion suppresses the history record and everything downstream of it — the passive engine, the report — while the bytes still leave the machine. It is a noise filter, not a containment boundary.
go deeper
Recall the headline: a request excluded on the proxy path is still sent. Exclusion changes what gets recorded, not where traffic goes.
Explain the mechanism — the handler marks the message excluded, skip-on-excluded handlers step aside, and the sender still sends it with listener notification off.
Show the operational consequence: the artefacts that would reveal the contact are the ones exclusion suppresses, so an empty report proves nothing about reachability.
Decide where a must-not-touch boundary genuinely lives in your setup, given that any boundary the scanner enforces is one a misconfiguration can remove.
## The answer, and the mechanism behind it Yes, it still reaches the host. Exclusion on ZAP's proxy path is a **marking** operation, not a blocking one, and the code makes that explicit. The `network` add-on's local-server handler is where a proxied message is first classified. It computes whether the message is excluded — testing the request URI against the global exclusion regexes and against the session's exclude-from-proxy list — and then records the verdict on the handling context. It does not return early, and it does not close the connection. It calls on into the handler pipeline exactly as it would for any other message. What the verdict then changes is which handlers *look* at the message: - Handlers written as "interested only in non-excluded messages" — an abstract base whose `handleMessage` runs its subclass only when the context is not marked excluded — skip it. The request and response handler bases are both built on it, so everything hanging off them is silently bypassed. - **The sender handler is not built on it.** It is the final handler in the proxy pipeline, and it sends the message regardless. For an excluded message it sends with a request configuration built with listener notification switched off, then marks the context overridden so the rest of the pipeline is short-circuited. The response is still written back to the client. From the browser's point of view nothing happened at all. ## What exclusion actually buys you | you might assume | what actually happens | |---|---| | the request is dropped | it is sent, by the final handler in the pipeline | | the host never hears from you | the host receives it and answers | | nothing is recorded | correct — listener notification is off, so it does not reach the history-driven machinery | | passive rules will not see it | correct, and for the same reason | | it is a containment boundary | it is a noise filter | So the feature is real and useful. It keeps a logout endpoint, a third-party analytics beacon or a chatty polling URL out of your history, out of the passive engine's queue and out of your report. It does exactly none of the thing its name suggests to a reader worried about *where traffic goes*. Note the scope of the claim. This is the **proxy** path — the global exclusion regexes and the session's exclude-from-proxy list, as consulted by the local-server handler. Other exclusion lists are read by the components that own them and can genuinely stop those components choosing a URL as a target. The dangerous case is the proxy path, because that is what people reach for when they mean "do not touch that". ## Why this is the most consequential sentence on this subject Everything else in ZAP's scope machinery is at least a decision about behaviour. This is a decision about bookkeeping that reads, in a configuration file, exactly like a decision about behaviour. The failure it produces is therefore quiet: 1. Someone decides a host or a path must not be touched during a run. 2. They add it to an exclusion list, because that is the control whose name matches the intent. 3. The run proceeds. The excluded URLs are absent from the history, absent from the report and absent from every count. 4. The traffic went out anyway. The only record that would have shown it is the record that was suppressed. The evidence and the event are removed by the same switch. That is worth saying plainly in an interview, because it is the reason this is not a trivia question: **the control that fails here also removes the trace of its own failure.** ## What to do instead - **Do not express a must-not-touch boundary as a proxy exclusion regex.** Express it as a target the run is never given, or as a boundary outside the process — the runner's own egress. A boundary the scanner enforces is a boundary a misconfiguration can remove. - **Use exclusion for what it is good at**: keeping known-noisy or destructive-if-recorded URLs out of the working set, so the report is about what you meant to test. - **Be careful what you promise about it.** "We excluded that host" is a statement about your report, not about your traffic, and it is worth saying which you mean when someone asks whether a host was touched. - **Separate it in your head from the mode.** A mode can refuse to start a scan. A proxy exclusion cannot refuse anything; it only changes who is told.
- If the request is still sent, what does a proxy exclusion actually remove?The notification. The message is sent with listener notification disabled, so it never reaches the listener-driven machinery: no history record, nothing for the passive engine to drain, nothing in the report. The handlers written to skip excluded messages are bypassed as well.
- How would you keep a host from being touched at all during a run?Not with a proxy exclusion. Either never give the run that target, or put the boundary where the scanner is not — network egress from the runner. A restricted `Control.Mode` can refuse to start a scan on an out-of-scope node, but it does not police the proxy path either, so it is not containment on its own.
- Why is this failure mode particularly hard to notice afterwards?Because the same switch removes the event and the evidence. The excluded URLs are missing from the history, the report and every count, so the artefacts you would inspect to find out whether a host was contacted are exactly the ones exclusion suppresses.
A proxy exclusion is the mute button on the recorder, not a lock on the door. The conversation still happens; you just have no tape of it.
saying these in an interview costs you the question
- Says an excluded URL is never requested at all
- Believes exclusion closes the connection or returns an error
- Treats a proxy exclude list as a containment boundary for a host
- Assumes an empty report proves a host was never contacted
- Confuses exclusion with a mode that can refuse a scan