How would you standardise where OWASP ZAP scope is declared across many unattended pipelines?
answer
- only one layer travels with the repository
- pick a home, then bound the exceptions
- what you give up by choosing it
- a quieter run is not a safer one
- measure what was reached, not what was written
basics
~20 sPut the boundary in the plan's context block. It is the only scope layer a plan can express, so the only one that lives in the repository and gets reviewed. Bound the exceptions, and say what it cannot express: a query-keyed rule.
solid answer
~50 sChoose the **context block in the plan** as the single sanctioned home. It is the only scope layer expressible in a plan, so it is the only one that can sit in the application's repository and be reviewed as a diff, and it is the layer every scanning component consults once a job is bound to it. Say plainly what that costs: a context is matched with the query removed, so a boundary expressed in query parameters cannot live there. Bound the two exceptions — the session exclude-from-scan list reached through `activeScan-config`, where the key must always be present because the job replaces the list, and the `network` add-on's global exclusions, which no plan can write and which return an empty list when the add-on is absent. Then measure URLs reached per run, because a scope mistake produces a quiet green result rather than a failure.
go deeper
Recall that scope belongs in the plan file next to the application, not in settings on a build machine, so that a change to it is visible.
Be able to say which layers a plan can and cannot write, since that is what decides where a fleet-wide standard can live at all.
Argue the trade rather than the rule: reviewability against expressiveness, and what signal tells you a scope change did more than it meant to.
Own the decision and its cost. Name the home, bound the exceptions, state what the chosen layer cannot express, and put a measurement behind it because the failure mode is silence.
## The problem you are actually solving Across a fleet of pipelines running OWASP ZAP, "what may this run touch?" can be answered in at least three unrelated places: a context's include and exclude lists, the session's per-subsystem exclusion lists, and the `network` add-on's global exclusions. They are stored differently, read by different components, matched by different rules, and only some of them can be written in the file that lives beside the application. A standard that does not choose between them is not a standard; it is a recommendation that each team will resolve differently, and you will find that out from an incident rather than from a review. ## What should carry the boundary The **context block in the automation plan** is the only credible home for it, for reasons that are properties of the tool rather than preferences: - It is the only scope layer expressible in a plan, so it is the only one that can live in the application's repository, be diffed, and be reviewed by the people who know what the application is. - It is the layer every scanning component consults, directly or through the derived scope value, once a job is bound to the context. - It is version-controlled by construction, which means a change to what a scan may reach arrives as a reviewable change rather than as a setting someone altered on a machine. What you give up by choosing it is real and should be stated rather than discovered: a context is matched against the URL **with the query removed**, so any boundary that can only be expressed in terms of a query parameter cannot live here at all. ## The exceptions, and how to bound them 1. **An endpoint that must be kept away from the active scanner specifically.** The session's exclude-from-scan list is the right layer, and a plan can reach it through the `activeScan-config` job. Make that job the only sanctioned writer, and require the key to be present whenever the job is — the job replaces the list from its own data, so an `activeScan-config` with no exclusions silently clears whatever was there. 2. **Third-party noise on the wire** — asset hosts, telemetry endpoints, update services. That is the global layer. Accept that it cannot be written in a plan, that it needs the add-on present, and that it returns an empty list without complaint when the add-on is missing. If it is part of your standard, it belongs in the image or the base configuration, and something has to assert that it is actually there. ## What each layer costs you | layer | lives in | reviewable as a diff | can express a query-keyed rule | |---|---|---|---| | a context's include and exclude lists | the plan, beside the application | yes | no — the query is removed first | | the session exclude-from-scan list | the plan, via one job only | yes, if that job is the only writer | yes | | the `network` add-on's global exclusions | the image or base configuration | no | yes | The row that decides the standard is the middle column, not the right one. A boundary nobody can see in a diff is a boundary nobody reviews, and this is a setting whose mistakes are silent. ## Rules worth writing down - **Scope rules are full-match regexes over paths.** Every entry ends in `.*` unless it genuinely means one URL, and every literal dot is escaped. - **A pattern is written for one named layer** and is never copied into another. Anchoring is the only property that survives the move; the string it is matched against and whether case matters both change. - **Prefix every list-layer pattern with an inline case-insensitive flag**, as the shipped defaults do. It costs nothing where the layer already sets that flag. - **One context per plan unless there is a reason for more.** Exclusion crosses context boundaries: any in-scope context's exclude removes a URL every other context included. - **A narrower scope is not a safer result.** It is a quieter one. Everything a scan does not reach is absent from the report in the same way a genuinely clean endpoint is. ## How you would know it is working The thing to measure is not whether the scope block looks right but what each run actually reached: the count of URLs visited and how it moved when the block last changed. That number falling is the only early signal that a scope change did more than it meant to, and it is the one you want on a dashboard rather than in a log. Pair it with a review rule — a change to a context block gets the same scrutiny as a change to a deployment manifest — and with a periodic read of what is set outside the plan, because that is where the layers you standardised away will quietly reappear. ## Where the judgment actually is None of the above is forced by the tool; it is a choice about where the cost lands. Putting the boundary in the plan buys reviewability and pays for it in expressiveness. Putting it in the base image buys consistency and pays for it in invisibility — nobody reading the repository can see what the run will not touch. A team that cannot state which trade it made has not made one.
- A team insists on keeping scope in the base image so nobody can widen it. What do you say?That it is a real trade and they should name it. Configuration in the image is consistent and hard to alter locally, but it is invisible to anyone reading the application's repository, it cannot be reviewed alongside the change that needed it, and only the global layer actually lives there — a context cannot. If they accept invisibility, something must still assert the setting is present, because its absence is silent.
- What would you put on a dashboard to catch a scope mistake?The number of URLs each run reached, tracked over time, alongside the commit that last changed the context block. A scope error does not fail; it narrows. The reached count falling sharply while the run stays green is the only early signal, and it is worth more than any amount of reading the regexes back.
- Why cap the number of contexts a standard plan may declare?Because exclusion is session-wide. Any in-scope context's exclude pattern removes a URL that every other context included, so a second context added for an unrelated job can quietly subtract from the first. One context unless there is a stated reason keeps that interaction out of the fleet.
saying these in an interview costs you the question
- Standardises on a layer without saying what it cannot express
- Treats a narrower scope as a safer scan result
- Puts scope in machine configuration where no review sees it
- Assumes a scope mistake will show up as a failed run
- Copies one team's exclusion patterns between layers as a shared library