Tools · Web testing tools · 13 / 23
Reading a ZAP alert as a claim
An alert names a rule, a URL, a risk, a confidence, and an evidence snippet. On Harbor Ledger you read those fields as a claim about one response, then you open that response and see whether the claim is true.
The fields on one alert
Open the Alerts tab after the baseline and select a single row. The fields you want on paper are the rule name, the URL, the method, the risk, the confidence, the parameter if one is named, and the evidence. Description and solution text below that are the rule author’s generic advice. They are often right about the class of problem and vague about your app. Your note has to add the Harbor Ledger specifics they cannot know.
A useful first row on this lab is a missing header on a page you understand, such as the invoice list. Header alerts are good teachers because the claim is checkable with your eyes: either the response contains the header or it does not. You are not asked to interpret a stack of guesses.
The history entry is the evidence
From the alert, jump to the message in History, or find it by method and URL. Read the status line first. A claim about a document that came back as 404 is a claim about your error page, which may still be a real header bug, and it is a different page from the invoice list. Then read the response headers from top to bottom, not only the one in the snippet.
On Harbor Ledger’s HTML responses you should be able to see Content-Type and the Set-Cookie line for the lab session, with HttpOnly and SameSite. The absence of Content-Security-Policy is the alert. The presence of HttpOnly is a neighboring fact the alert did not congratulate you for. Write both. A reading of an alert that only copies the red field misses the headers you already got right.
Rule: Content Security Policy (CSP) Header Not Set URL: http://127.0.0.1:3000/invoices Method: GET Risk (tool default): Medium Confidence: High Evidence: no Content-Security-Policy response header History agrees: yes Also observed: Set-Cookie includes HttpOnly and SameSite=Lax Change in the lab app: send a Content-Security-Policy on HTML responses
Confirm the change with one new request
If you add the header in the lab app, reload /invoices through the proxy and read the new response. The header should now be present, with a policy you can explain. Re-running the entire baseline is optional and noisy. One request is the confirmation. The alert row from the old report will still say the header was missing, because the report is a snapshot. Your note has the before and the after.
Leave the generic solution text in the tool. In your note, the change is one sentence a future you can implement: which responses, which header, which value. That sentence is the work. The risk color was only the sorting key that put this row on your screen.
Worked case: two alerts, two notes
From the baseline report, choose the CSP alert on /invoices and one other alert on a lab URL, preferably something informational such as a missing X-Content-Type-Options on /health. Fill the field list for each. Open both history entries. For each, write “History agrees: yes” or “History agrees: no,” plus one sentence of what you saw. If History does not agree, the later lesson on skepticism is the one you are already doing, and you should mark the row as not confirmed.
Stop after two. A baseline can produce many rows that are the same missing header on many URLs. Collapsing those into “HTML responses from this origin omit this header” is a better note than twenty identical screenshots. You can say how many URLs you sampled and that the rest are the same claim.
Diagram
From an alert row to the response it cites
- Name
The rule name says what ZAP thinks it saw, such as a missing content security policy.
- Where
The URL and the method say which response to open. Risk and confidence say how sure the rule is, by default.
- Evidence
The snippet is the header or the byte the rule pointed at. It can be incomplete.
- History
You open that URL in History and read the status line and the headers yourself.
A header alert, checked against the response
alerts · CSP header not set
Rule: Content Security Policy (CSP) Header Not Set URL: http://127.0.0.1:3000/invoices Risk: Medium (the rule’s default) Confidence: High Evidence: response has no Content-Security-Policy header
This row is a claim. It does not show the rest of the headers. It does not say who is signed in.
- The rule looked for one header and did not find it.
- Medium is the rule’s default rating, not your impact write-up.
- The next screen is the history entry for this URL.
history · GET /invoices
GET /invoices HTTP/1.1 Host: 127.0.0.1:3000 Cookie: session=lab-session-avery
HTTP/1.1 200 OK Content-Type: text/html Cache-Control: no-store Set-Cookie: session=lab-session-avery; HttpOnly; SameSite=Lax (no Content-Security-Policy header)
- The claim matches: the CSP header is absent.
- The cookie flags are a separate fact, visible here and not in the alert title.
- The fix, in an app you own, is to send the header. The alert already did its job.
Rule: URL: Method: Risk (tool default): Confidence: Evidence snippet: What History actually shows: What you would change in the lab app:
Check yourself
1. An alert says “CSP Header Not Set” on http://127.0.0.1:3000/invoices with high confidence. What does high confidence mean here?
2. The evidence snippet is one line. Where do you read the rest of the headers?
3. You confirm the CSP header is missing, and you own the lab app. What is the end of this exercise?