In OWASP ZAP, where does the active-scan engine live, and where do its attack rules come from?
answer
- two halves, shipped apart
- the scheduler stayed at home
- payloads arrive as add-ons
- paros.core.scanner versus ascanrules
basics
~20 sZAP's active-scan engine ships in core, in org.parosproxy.paros.core.scanner. The rules that craft the payloads ship separately, as scan-rule add-ons. A build with no rule add-ons still has a working scheduler with almost nothing to run.
solid answer
~40 sZAP's active scan is two halves that ship apart. The **engine** is core: `Scanner` fans out one `HostProcess` per site, `HostProcess` walks the Sites tree and drives each rule over the nodes it found, and `AbstractPlugin` — the base class every active rule extends — owns `sendAndReceive`, the one method that puts an attack request on the wire. The **rules**, the classes that build a payload and read the response, ship as add-ons: the `ascanrules` family in the `zap-extensions` repository. Core keeps one active rule of its own, `ScriptsActiveScanner`, and even that is marked `@Deprecated(forRemoval = true)` with the live version in the `scripts` add-on. The asymmetry is worth remembering because the passive side went the other way — its engine moved out to the `pscan` add-on.
go deeper
Remember the shape: the machinery that runs a scan is in ZAP core, the things that actually attack are add-ons. If nobody installed scan-rule add-ons, a scan still runs and still reports nothing.
Be able to name the core classes — Scanner, HostProcess, AbstractPlugin — and say that the shipped rules live in the ascanrules add-ons. Explain why that is the opposite arrangement from the passive engine.
Treat engine and rules as two release surfaces when you own a pipeline. Know which one to suspect when finding counts move, and pin the image so both halves move together rather than one drifting.
Decide the team's stance on add-on drift: a pinned image with frozen rules is reproducible but goes stale, and a self-updating one finds more but makes every result non-comparable. Pick deliberately and write it down.
## The split in one sentence ZAP's active scan is two products running in one process. The **engine** — the code that decides which URLs get attacked, which rule runs against them, how often, and how the request physically leaves the process — ships inside ZAP core, in the package `org.parosproxy.paros.core.scanner`. The **rules** — the classes that build a payload and read the response to decide whether it proved anything — ship as installable add-ons. Neither half does anything useful alone. ## What core actually contains | piece | class | job | |---|---|---| | the fan-out | `Scanner` | creates one `HostProcess` per site — scheme, host and port together — and runs them on a pool | | the scheduler | `HostProcess` | walks the Sites tree, builds the list of nodes to attack, and drives each rule over that list | | the rule contract | `AbstractPlugin` | the base class every active rule extends; owns `sendAndReceive`, the only method that sends an attack request | | the fire-count shapes | `AbstractHostPlugin`, `AbstractAppPlugin`, `AbstractAppParamPlugin` | subclasses that fix how often the engine invokes a rule | | the baseline prober | `Analyser` | requests deliberately non-existent paths before rules start, so rules can tell a real page from a soft "not found" | All of that is core, and none of it carries a deprecation marker. ## What the add-ons contain The shipped attack rules live in the `ascanrules` family of add-ons — one class per rule, each extending one of core's base classes. They carry the payload strings, the response oracles and the alert text. Core ships exactly one active rule of its own, `ScriptsActiveScanner` (the rule that runs user-supplied active scripts), and even that is annotated `@Deprecated(forRemoval = true)`; the live implementation sits in the `scripts` add-on. So the honest statement is: **core keeps the engine plus a shim, and every working rule is an add-on.** ## Why the asymmetry is the fact to memorise ZAP has moved several subsystems out of core over the years. The local HTTP proxy and the certificate authority went to the `network` add-on. The traditional spider left with no shim at all. The **passive**-scan engine moved to the `pscan` add-on. The active-scan engine is the one that stayed. That makes "where does this live?" a question with opposite answers on the two sides of the same scanner, and it changes what each kind of change can break: - an active **rule** update is an add-on update, and it changes only what gets sent; - an active **engine** change is a core change, and it can alter target selection, ordering, concurrency and the send path for every rule at once; - a build with no scan-rule add-ons still has a fully functioning scheduler that finds nothing. ## What it means for a pipeline 1. **Two upgrade surfaces, two changelogs.** Core moves on its own line; each rule add-on versions independently. When a scan starts reporting more — or fewer — findings after an image refresh, a rule add-on change is far more likely than an engine change. Read that changelog first. 2. **Pin both halves together.** Pinning a container tag pins the engine and the add-on set at once. Letting add-ons update themselves inside a pinned image reintroduces exactly the drift the pin was for. 3. **A clean run proves the engine ran, not that rules did.** If the rule add-ons you assumed were present are absent, the engine still completes a scan and still reports nothing. "No findings" and "nothing installed to find them with" look identical from outside. 4. **Some of the traffic is the engine's own.** `HostProcess` starts an `Analyser` for each start node, and it requests random non-existent paths before any rule fires, so that rules can later distinguish a genuine page from a site that answers everything with a friendly page. "No rules installed" therefore does not mean "no requests sent" — which matters when you have to explain to a target owner exactly what your job did. ## How to check it yourself The clones make this a two-line question. Search core for the engine's own classes and the add-on repository for the rules that extend them: - `grep -rn "class HostProcess" <core>/zap/src/main/java` lands in `paros/core/scanner`; - `grep -rln "extends AbstractAppParamPlugin" <extensions>/addOns` lands almost entirely under `addOns/ascanrules*`. That is the whole claim, measured rather than remembered. ## The words to use Say *"core's active-scan engine"* and *"the `ascanrules` add-ons"*, never *"ZAP's scanner"*. In this tool "scanner" can mean the active engine, the passive engine or the whole program, and those three live in different repositories on different release cadences. Naming the half you mean is the difference between a claim a colleague can verify and one they cannot.
- Does ZAP core ship any active scan rule of its own?One, and it is on its way out. `ScriptsActiveScanner` — the rule that runs active *scripts* — sits in core's `org.zaproxy.zap.extension.ascan` package but is annotated `@Deprecated(forRemoval = true)`; the live implementation is in the `scripts` add-on. Core keeps the engine and a shim, not a working rule set.
- What practical difference does the split make to a CI pipeline?Two upgrade surfaces. Core fixes scheduling, target selection and the send path; each rule add-on versions independently and changes only what gets sent. When findings move after an image refresh, look at the rule add-on changelog before suspecting the engine.
- If no rule sends anything, does the engine still touch the target?Yes. `HostProcess` starts an `Analyser` per start node before rules run, and it requests deliberately non-existent paths to learn how the site answers for a missing resource. That traffic is the engine's own and reaches the target regardless of which rules are installed.
saying these in an interview costs you the question
- Says the whole active scanner is an add-on, like the passive one
- Assumes the core jar alone carries the attack rules
- Thinks updating scan rules also changes the scheduling engine
- Claims the engine sends nothing of its own before rules run
- Uses the bare word scanner without saying which half is meant