skip to content

In a ZAP packaged-scan rule file, what does an OUTOFSCOPE line do that a verdict line cannot?

level: middleimportance: should knowfreq 38%

answer

  1. not a verdict, a different line
  2. column three becomes a pattern
  3. matched from the start of the URL
  4. the finding disappears rather than moving

basics

~20 s

An OUTOFSCOPE line is not a verdict. Its third column is a regex, and any finding from that rule whose URL matches is discarded before any bucket is chosen, so it appears in no count at all.

solid answer

~50 s

A verdict line decides which bucket a rule's findings land in. An `OUTOFSCOPE` line decides whether a finding exists at all: the third column holds a regular expression, and any finding raised by that rule on a matching URL is thrown away before the verdicts are consulted. That makes it per **rule and URL**, where a verdict is per rule only -- useful when one endpoint legitimately trips a rule that is worth keeping everywhere else. Two details bite. The regex is applied as a match from the **start** of the URL, not a search, so a pattern written for a path fragment never fires unless you anchor it at the scheme. And column one accepts forms a verdict line does not: `*` for every rule, or a comma-separated list of ids. Because the finding is discarded, it shows up in no bucket -- not even the ignored count.

code

bash · 13 lines
bash
cat > rules.conf <<'EOF'
# columns are TAB separated
# column one here may be one id, a comma-separated list, or *

*	OUTOFSCOPE	https://example\.com/healthz.*

# this line loads cleanly and never fires: the pattern is applied
# from the START of the URL, and no URL begins with a slash
*	OUTOFSCOPE	/healthz.*

# write it this way if you want to match a path anywhere
*	OUTOFSCOPE	.*/healthz.*
EOF

go deeper

for a junior

Recall that this line takes a regular expression rather than a note, and that it removes matching findings instead of reclassifying them. The pattern has to start where the URL starts.

for a middle

Explain the ordering: exclusions are applied while findings are collected, before any verdict is consulted, which is why the finding shows up in no count. Contrast that with an IGNORE verdict, which keeps and moves it.

for a senior

Show judgment about breadth. A wildcard exclusion silently removes coverage with nothing in the output to signal it, so argue for the narrowest pattern that solves the case and for checking the counts after adding one.

for a principal

The call worth owning is which exclusions a team may add unilaterally and which need a second reader, given that this is the one construct in the file whose effect leaves no trace in the run output.

## Two kinds of line in one file The tab-separated file that ZAP's packaged scan scripts read with `-c` or `-u` carries two different kinds of line, told apart by what is in column two. - If column two is one of the level words, the line is a **verdict**: it says which bucket that rule's findings land in, and the buckets are what the run's exit code is derived from. - If column two is the single word `OUTOFSCOPE`, the line is a **filter**. Column three stops being a note and becomes a regular expression. That difference matters more than it looks. A verdict is per rule. A filter is per rule **and** per URL, and it is the only thing in this file that can say "this rule is right in general and wrong here". ## What the filter actually does When the run collects its findings it walks them in a fixed order before any verdict is applied: 1. A small built-in list of example and internal rule ids is dropped outright. 2. Each remaining finding is tested against the out-of-scope patterns for its rule id, and against the patterns registered under `*`. A match discards the finding. 3. Every finding the scan marked as informational risk is discarded too, whatever the file says. 4. Only what survives is sorted into `IGNORE`, `INFO`, `WARN` and `FAIL`. So an out-of-scope match is a deletion, not a downgrade. The finding is not quietly reclassified; it is gone, and it will not appear in any of the counts the run prints. | | `IGNORE` verdict | `OUTOFSCOPE` line | |---|---|---| | scope | the whole rule | that rule on URLs matching a regex | | effect on the exit code | none -- the finding does not gate | none -- the finding no longer exists | | still visible in the output? | yes, in the ignored count | no, it appears nowhere | | column one forms accepted | one rule id | one id, a comma-separated list, or `*` | | on a full or API scan | an active rule marked this way is switched off before the scan | the rule still runs; only matching findings are dropped | ## The anchoring trap The pattern is compiled as an ordinary regular expression and then applied with a **match from the beginning of the string**, not a search anywhere inside it. The URL it is matched against is the full URL the finding was raised on, scheme included. That has one practical consequence that catches nearly everyone the first time: - `https://example\.com/static/.*` works, because it starts where the URL starts. - `/static/.*` never fires, because the URL does not begin with a slash. - `.*/static/.*` works, because the leading `.*` absorbs the scheme and host. There is no error and no warning when a pattern never matches. The line loads, the run proceeds, and the findings you thought you had excluded come back in the warning bucket. The only way to notice is that the count did not change. ## Column one, and why it is different here On a verdict line, column one is a single numeric rule id. On an out-of-scope line it accepts more: - a single rule id, scoping the filter to that rule; - a comma-separated list of ids, which registers the same pattern for each of them; - `*`, which applies the pattern to every rule. The list and the wildcard are parsed **only** on this branch. Putting either on a verdict line does not broaden the verdict -- it produces a key that matches no rule, and the line silently does nothing. ## When this is the right instrument, and when it is not Reach for an out-of-scope line when a specific endpoint is a genuine exception: a health check that returns a bare string and trips a header rule, a static asset host outside the application, a deliberately unauthenticated status page. Those are cases where the rule is correct everywhere else and you do not want to lose it. Do **not** reach for it as a general quietening tool. Because the finding vanishes from every count, an over-broad pattern -- especially one registered under `*` -- can remove real coverage and leave a run looking cleaner than it is, with nothing in the output to show it happened. If your reason is "this rule is wrong for this application", that is a verdict line. If it is "this rule is wrong for this URL", that is an out-of-scope line, and the narrower you can write the pattern, the more the exclusion is worth. A practical habit: write the pattern, run once, and compare the printed counts against the previous run. A filter that is doing what you intended changes exactly one number.

  • Why does a finding excluded this way not show up in the ignored count?
    Because the exclusion happens earlier. The run discards out-of-scope findings while it is collecting them, before anything is sorted by verdict, so there is no bucket left for the finding to be counted in. An `IGNORE` verdict keeps the finding and moves it; this removes it.
  • Can a single pattern cover several rules at once?
    Yes. Column one on an out-of-scope line accepts a comma-separated list of rule ids, which registers the same pattern against each of them, or `*` to apply it to every rule. Both forms are parsed only on this kind of line.
  • How would you tell that an exclusion pattern is not matching anything?
    Nothing reports it -- a pattern that never fires is indistinguishable from one that had nothing to exclude. Compare the printed per-bucket counts before and after adding the line; a working filter moves exactly one of them.

saying these in an interview costs you the question

  • Calls OUTOFSCOPE a fifth verdict level
  • Writes a bare path regex and expects it to match
  • Expects excluded findings to appear in the ignored count
  • Thinks the pattern is searched anywhere inside the URL
  • Uses a wildcard exclusion where a rule verdict was meant