skip to content

In ZAP's packaged scans, what is the tab-separated file passed with -c, and what is on each line?

level: middleimportance: must knowfreq 50%

answer

  1. tabs, not spaces, and three tokens minimum
  2. column one is the rule id
  3. the generator writes everything at WARN
  4. anything unlisted defaults to warning

basics

~10 s

It is a per-rule verdict file: each tab-separated line pins one numeric scan-rule id to IGNORE, INFO, WARN or FAIL, with an optional note. Any rule the file omits defaults to WARN.

solid answer

~50 s

The packaged scan scripts take a plain tab-separated file -- `-c` reads it from disk, `-u` fetches it over HTTP, and `-g` writes a starting copy with every rule already at `WARN`. Lines beginning with `#` are comments; every other line must carry at least three tab-separated tokens or the parser rejects the file. Column one is the numeric scan-rule id, column two is the verdict, column three a free-text note, and an optional fourth field your own message, printed beside that rule's findings. Column two takes one of five level words -- `PASS`, `IGNORE`, `INFO`, `WARN`, `FAIL` -- or the special word `OUTOFSCOPE`, which turns the line into a URL filter instead; anything else raises. A rule the file never mentions defaults to `WARN`, which `-i` flips to `INFO`. The verdict decides which bucket that rule's findings land in, and the buckets are what the exit code is derived from.

code

bash · 9 lines
bash
# -g writes a starting file: every rule the run knows, all at WARN
zap-baseline.py -t https://example.com -g rules.conf

# each line is TAB separated: <rule id> <verdict> <note> [<your message>]
#   <noisy-rule-id>\tIGNORE\t(rule name)\taccepted, tracked elsewhere
#   <blocking-rule-id>\tFAIL\t(rule name)\tmust not regress

# feed the edited copy back in; -u would fetch the same format over HTTP
zap-baseline.py -t https://example.com -c rules.conf

go deeper

for a junior

Recall that the file is tab-separated, that column one is the numeric rule id and column two the verdict, and that anything you leave out is treated as a warning. Generating a starting copy is what -g is for.

for a middle

Explain the mechanics: the minimum-three-tokens parse, the WARN default and how -i inverts it, and the fact that an active rule marked IGNORE is switched off rather than merely reclassified. Name the five accepted words.

for a senior

Talk about keeping the file honest over time -- regenerating it after a rule-set upgrade, diffing for new ids, and using the fourth column so the reason travels into the build log with the finding.

for a principal

Own the question of where this file lives and who may edit it: one shared copy behind a URL, or one per service. Each answer trades consistency against a team's ability to accept a finding it understands.

## What the file is for ZAP's packaged scan scripts do not decide on their own which findings should stop a build. They sort every finding into a bucket by **rule**, and this file is where you say which bucket each rule gets. It is where an unattended run records a human judgment about a specific rule. Three options reference it: - **`-c <file>`** -- read the file from disk (inside the container, from the mounted working directory). - **`-u <url>`** -- fetch exactly the same format over HTTP, so several pipelines can share one governed copy. - **`-g <file>`** -- *write* a starting file instead of reading one, listing every rule the run knows about with the verdict `WARN`. ## The line format, exactly The parser is deliberately blunt. It skips blank lines and lines starting with `#`, and it counts tabs: a line with fewer than two tabs is rejected with an error naming the line, so a file edited in a tool that helpfully converts tabs to spaces fails loudly rather than quietly. | column | contents | notes | |---|---|---| | 1 | the numeric scan-rule id | on a verdict line, one id -- not a list and not a wildcard | | 2 | the verdict | one of `PASS`, `IGNORE`, `INFO`, `WARN`, `FAIL` -- or `OUTOFSCOPE`, which changes what the line means | | 3 | a free-text note | the generator writes the rule's name here in brackets; it is decoration | | 4 | your own message | optional; printed beside that rule's findings in the run output | Two things about column one are worth pinning down, because the file has a second kind of line (an out-of-scope line) where the rules differ: - On a **verdict** line, column one is a single id. The comma-separated list and the `*` wildcard are parsed only on the out-of-scope branch, so a verdict line that uses either matches no rule at all and quietly does nothing. - Worse, on `zap-baseline.py`'s automation-framework path the plan builder converts each verdict line's id with an integer conversion, so a `*` or a comma list there is not a wildcard -- it is an error. ## The verdicts and what each one buys you - **`FAIL`** -- this rule's findings go in the failing bucket, and the run exits `1` when it alerts. - **`WARN`** -- the warning bucket; the run exits `2` unless `-I` was supplied. - **`INFO`** -- printed, counted separately, never gates. - **`IGNORE`** -- the quietest non-gating verdict. On the full and API scans it does more than reclassify: an **active** rule marked `IGNORE` is turned off in the policy before the scan starts and never runs, which is why those scripts advertise it as a way to shorten a scan. A **passive** rule marked `IGNORE` still runs and still alerts; only its findings are re-bucketed. - **`PASS`** -- accepted by the parser but not a bucket. The same ordered list of level names serves two jobs: it validates this column *and* it backs the `-l` display-threshold option. There is no code path that sorts findings into a passing bucket from this file, so a rule marked `PASS` is not "guaranteed to pass"; use `IGNORE` when you mean that. ## The default is WARN, and that matters Everything the file omits is treated as `WARN`. Combined with `-g` writing every rule at `WARN`, this makes the out-of-the-box behaviour "any finding at all fails the stage with code `2`". That is a sensible default for a tool you have just adopted and a bad one for a pipeline nobody is watching, which is the whole reason the file exists. The `-i` flag inverts the default so unmentioned rules land in the informational bucket instead. That makes a run gate only on what you explicitly wrote down -- a deliberate, and reversible, narrowing. ## A working shape 1. Run once with `-g` to get the full list of rules at `WARN`. 2. Commit that file and edit it: move the rules you genuinely want blocking to `FAIL`, move the ones you have assessed and accepted to `IGNORE`, and leave the rest at `WARN` so new findings still surface. 3. Add a fourth column on the lines you changed, saying **why** -- it is printed next to the finding, so the next person reading the build log sees the reasoning without opening the file. 4. Re-run `-g` after a rule-set upgrade and diff it against your copy: rules that appear in the new file and not in yours are the ones that just started defaulting to `WARN`. That last step is the one teams skip. The file is keyed on rule ids, and a rule set that grows adds ids your file has never seen, all of which arrive at the default.

  • What happens to a rule that is not mentioned in the file?
    It defaults to `WARN`, so it lands in the warning bucket and the run exits `2` if it alerts. The `-i` flag changes that default to `INFO`, which makes the run gate only on rules you wrote down explicitly. Either way, nothing is silently dropped.
  • Why does the parser reject a file that looks correct?
    It counts tab characters and needs at least two per line. An editor that converts tabs to spaces, or a copy-paste through a web page, produces a file that looks right and fails to load -- the script reports the offending line and the run ends on `3`.
  • Can one file be shared across several pipelines?
    Yes -- `-u` takes a URL and parses the identical format, so a governed copy can live in one place and be fetched by every run. The trade-off is that the scan now depends on that endpoint being reachable, and a fetch failure ends the run.

saying these in an interview costs you the question

  • Thinks the file is space-separated or comma-separated
  • Believes an unlisted rule is ignored by default
  • Says column one accepts a rule name rather than its id
  • Assumes PASS is the verdict for never blocking
  • Thinks -g writes the file with sensible verdicts already chosen