In ZAP, what does protect mode check against scope, and at what point in a scan?
answer
- asked once, at the door
- the start node, not every request
- MODE_VIOLATION is the API-facing refusal
- the scan engine never reads the mode
- safe refuses scans, not traffic
basics
~20 sProtect mode checks only the start nodes of a scan, once, when the scan is asked to start. Over the API the refusal is MODE_VIOLATION. Nothing re-checks the mode afterwards, so it bounds admission rather than traffic.
solid answer
~40 sThe mode is an admission check at scan-start entry points, not a filter on traffic. Core's active-scan extension opens `startScan` with a switch: `safe` throws immediately, `protect` walks the target's start nodes and throws unless each is `isIncludedInScope()`, and `standard` and `attack` fall through. The API path does the same and raises `ApiException.Type.MODE_VIOLATION`; the `spider` add-on raises its own exception. After admission the mode is never consulted again — core's active-scan engine package, core's HTTP sender and the `network` add-on's proxy contain no mode check, and the `network`, `pscan` and `automation` add-ons implement the mode-changed listener as no-ops. So `safe` does not stop the proxy forwarding traffic, and `protect` bounds where a scan may begin, not what it then sends.
go deeper
Recall that protect mode can refuse to start a scan, and that the refusal happens up front rather than partway through.
Explain the switch at the entry point: safe throws outright, protect tests the start nodes against scope, standard and attack fall through untouched.
Demonstrate the limit — the engine, the sender and the proxy hold no mode check, so the gate is admission-only and safe mode leaves proxied traffic flowing.
Judge what an admission-only control is worth in your environment, and where the per-request boundary has to live instead if you need one.
## Where the check lives `protect` mode is easy to over-read as "ZAP will only touch things in scope". What the source actually does is narrower, and the narrowness is the whole point of the question. The check is an **admission check at a scan-start entry point**. In core's active-scan extension, `startScan` opens with a switch on `Control.getSingleton().getMode()`: - `safe` — throws immediately; no scan is created. - `protect` — walks the target's **start nodes** and throws unless each reports `isIncludedInScope()`. - `standard` and `attack` — fall through with no check at all. The same shape is repeated at every other entry point, with a different exception type at each: | entry point | what it throws in `safe` / out-of-scope `protect` | |---|---| | core's active-scan extension `startScan` | `InvalidParameterException` | | core's active-scan API, and the spider, AJAX-spider and client-spider add-ons' APIs | `ApiException.Type.MODE_VIOLATION` | | the `spider` add-on's extension `startScan` | `IllegalStateException` | | core's request-sending API views and actions | `MODE_VIOLATION`, via a helper that returns false in `safe` and falls back to a scope test in `protect` | `MODE_VIOLATION` is the API-facing name for this refusal. It is what a caller driving ZAP over its control surface sees; a caller going through an extension directly sees an ordinary exception. ## What is never re-checked Once a scan is admitted, the mode is not consulted again. This is measurable rather than inferred: - **The active-scan engine never reads the mode.** Core's `org.parosproxy.paros.core.scanner` package — the scanner and host-process classes that actually drive the rules — contains no call to `getMode()`. - **The sending layer never reads it.** Core's HTTP-sender package contains no mode reference either, so no request is filtered on its way out on the basis of the mode. - **The proxy never reads it.** In the `network` add-on, the only mode-related member is a mode-changed listener with an empty body. The passive-scan add-on and the `automation` add-on implement the same listener as explicit no-ops. Consequences follow directly, and both surprise people: 1. **`safe` mode does not stop traffic.** It refuses to start scans. A browser pointed at the proxy still reaches whatever it asks for, and the sender still sends. `safe` is not a kill switch. 2. **`protect` bounds the start, not the run.** It asks a single question — is the node you are starting from in scope? — and then stands aside. It is an entry condition, not a per-request filter. ## Why the distinction is not pedantic An unattended job is exactly the case where the difference bites. Picture a nightly run pointed at a host nobody signed for. If the mode had been left at `standard`, nothing was ever asked. If someone had set `protect` and defined a context, the run would have been refused **at the moment it tried to start on that host** — which is genuinely useful, and is the strongest thing the program offers. But if the start node were in scope and the target's own configuration led elsewhere, the mode would have nothing further to say, because it is never evaluated again. So `protect` is worth setting and worth setting accurately, and it is not containment. The sentence to have ready is: *it is an admission check on the start node, evaluated once, and the engine that sends the traffic has no knowledge of it.* ## Reading the failure Because the gate fires at start, its failure is loud and early: the scan does not begin, and the caller gets a refusal naming the mode. That is the good case — an early, attributable stop. It also means a run that got past the gate tells you nothing about the mode's opinion of anything it did afterwards. If the run completed, the only thing the mode established is that the first node was acceptable when it was asked. ## How to answer this Say where the check is (a start-time switch at each entry point), what it examines in `protect` (the start nodes, against scope), what name the refusal carries over the API (`MODE_VIOLATION`), and then the part that separates a senior answer from a middle one: the engine, the sender and the proxy never consult the mode, so nothing is re-checked and `safe` does not block traffic.
- Does `safe` mode stop ZAP's proxy forwarding a request?No. The mode is consulted at scan-start entry points only. The `network` add-on's proxy pipeline contains no mode check — its mode-changed listener has an empty body — and core's HTTP sender contains none either. A browser configured through ZAP in `safe` mode still reaches whatever it asks for.
- Why do different callers see different errors for the same refusal?Because the check is duplicated at each entry point rather than centralised. Core's active-scan extension throws an invalid-parameter exception, the `spider` add-on throws an illegal-state exception, and the API implementors raise `ApiException.Type.MODE_VIOLATION`. Only a caller coming through the control surface sees the `MODE_VIOLATION` name.
- If a scan was admitted in `protect` mode, what has the mode established?Only that the start nodes were in scope at the instant the scan was requested. The engine that then drives the rules never consults the mode, so nothing the scan subsequently sends has been checked against it. Completion is not evidence that the mode approved of the run.
saying these in an interview costs you the question
- Says protect mode filters every request a scan sends
- Believes safe mode blocks all outgoing traffic including the proxy
- Thinks MODE_VIOLATION can be raised mid-scan by the engine
- Assumes the scan engine re-evaluates scope on each request
- Treats a completed scan as proof the mode approved of it