OWASP ZAP in plain words: what it is and 10 checks you will meet in every first scan
What OWASP ZAP is, what its baseline scan does (and does not), ten typical findings explained without jargon, and what runs on every ClassKasa change.
Tomasz Żyłka · 5 min read
Before you connect anything to a bank, it is reasonable to ask whether somebody tried to break it first. One way to try, politely and with a robot, is a free scanner called ZAP.
This is what ZAP is, what it checks, and why a scary-looking yellow warning is often just a missing sentence in a web page.
What ZAP is
ZAP (Zed Attack Proxy) is a free, open-source security scanner from the OWASP community. OWASP is the nonprofit that also publishes the famous "Top 10" list of web security risks. Its home is zaproxy.org.
ZAP sits between a browser and a website and looks at what goes back and forth. You can use it by hand, or you can let it run unattended in a build pipeline.
The baseline scan, and what it does not do
The pipeline version is the baseline scan. According to ZAP's own documentation, it crawls the target for a short time (a minute by default) and then runs only passive checks. Passive means it reads the responses the app already sends and complains about what it sees. It does not fire attacks at your forms.
That makes it safe to run on every change. It also means it is a smoke detector, not a burglar. A clean baseline does not say "unbreakable". It says "the obvious things in the responses look sane".
Ten findings you will meet in almost every first scan
You will not see the same ten in every app, but these show up so often that they are a good tour.
- Content Security Policy (CSP) header not set. The page does not tell the browser which scripts it may run. A CSP is a seat-belt against injected scripts.
- Missing anti-clickjacking header. Without it, another site can show yours inside an invisible frame and trick people into clicking. The fix is a frame rule in the headers.
- X-Content-Type-Options header missing. The browser may "guess" what a file is and run something it should not. One header (
nosniff) switches the guessing off. - Strict-Transport-Security header not set. Without HSTS, a browser can be tricked into starting on plain HTTP once. With it, the browser insists on HTTPS.
- Cookie without the HttpOnly flag. A script on the page can read that cookie. Session cookies should be off-limits to scripts.
- Cookie without the Secure flag. The cookie may travel over plain HTTP. It should only ever ride on HTTPS.
- Cookie without a SameSite attribute. The cookie may be sent along with requests started by other sites. SameSite narrows that down.
- Server leaks version information. A response header announces exactly which server software and version runs. Not a hole by itself, but a free hint for someone shopping for known bugs.
- Absence of anti-CSRF tokens. A form that changes something does not carry a secret token proving the request came from your own page. It is a reminder to check how the app stops forged requests.
- Cross-domain misconfiguration. The app's cross-origin rules are wider than they need to be, for example "any site may read this". Often harmless for public files, a problem for private data.
Notice what these have in common: most are one-line fixes in a header or a cookie setting. That is the good news. The bad news is that the unglamorous one-liners are exactly what attackers like to find missing.
Warning, fail, ignore
ZAP's baseline reads a rules file where every check can be set to IGNORE, WARN or FAIL. FAIL is the setting that treats a finding as a failure. Choosing which findings may stop a release is a decision about priorities, not a feature of the scanner, so it is worth knowing which setting your project actually uses.
What runs on every ClassKasa change
ClassKasa runs the ZAP baseline on every pull request that changes code, and it blocks the build on new findings.
Next to ZAP, the other scans block the build as well: Semgrep code analysis, npm audit for critical library vulnerabilities, OSV-Scanner for new known vulnerabilities, Gitleaks for leaked secrets in the full history, and TruffleHog for live, verified secrets. Every week Dependabot opens grouped pull requests with the dependency updates it found. Patch updates and security updates merge automatically once the required checks pass; major updates always wait for a person. A weekly routine consolidates what is still open into one pull request and works on it until every blocking check passes. And 49 automated test files try to read other classes' data and must be told "not found".
There is one more piece of history (the full write-up is here). In May 2026 an authorized pentest led to 8 fixes in releases v3.27.0 and v3.27.1 (both 2026-05-29), 3 of them rated High. Afterwards every attack was run again: the fixes held, and 3 more places with the same kind of bug were found and closed, each with a test that failed first and passes now.
The full list, kept in sync with what really runs, is on our security page. It also says what we do not claim: none of this is a certificate.
Why this matters when a bank is involved
When a treasurer connects a class bank account, the bank password is entered on the bank's own page and never in ClassKasa, and the access is read-only. Everything about that connection is spelled out, with sources, on the security page.
Next time you meet a yellow ZAP warning, do not panic. Read the sentence. More often than not it is asking for one more line in a header.