Security Testing
Verify that a system protects data, maintains functionality as intended, and resists unauthorised access, disclosure, or modification. A significant portion of security bugs can be found by functional testers — without specialist tools.
1 The Hook
An Auckland online retailer launches a customer order-history page. Every functional test passes: you log in, you see your own orders, you can’t see the page when logged out. The order page URL is /orders/1001. Sign-off given.
One curious tester — not a security specialist, just someone thinking like an attacker — changes the URL to /orders/1002. Another customer’s order appears: their name, delivery address, and what they bought. No special tools, no exploit kit, just editing a number in the address bar. Because the page checked “are you logged in?” but never “is this order actually yours?”, every customer’s personal information was one keystroke away from anyone with an account. Under NZ law that exposure is a notifiable privacy breach, and it would have shipped because the happy-path tests all went green.
This is the core shift in security testing: functional testing asks “does it do what it’s supposed to?” Security testing asks “what happens when I deliberately try to make it do something it’s not supposed to?” The most damaging defects are invisible to anyone who only walks the intended path — and a large share of them can be found defensively, by a tester with a browser and a habit of asking “what if I change this?”
2 The Rule
Security testing is asking what happens when you behave as an attacker would — so don’t only test the intended path. Probe access control, input handling, error messages and sessions by deliberately misusing them, because the worst defects only appear off the happy path.
3 The Analogy
Walking the perimeter of a building, not just the front door.
A building owner who only ever tests the front door — key works, door opens — learns nothing about whether the place is secure. A diligent caretaker walks the whole perimeter: jiggling the side gate, checking the fire exit hasn’t been propped open, seeing if the ground-floor windows latch, noticing the spare key under the mat. They’re not breaking in; they’re finding the ways someone else could, so the gaps get fixed before anyone with bad intent arrives.
Security testing is that perimeter walk. You’re not attacking the system for real — you’re defensively checking the side doors (changed an ID), the propped-open fire exit (a session still valid after logout), and the key under the mat (a verbose error message leaking file paths), so they’re closed before release.
What it is
Security testing evaluates whether a system protects its data and functionality against threats. It covers confidentiality (only authorised users see data), integrity (data isn’t altered without authorisation), and availability (the system stays up under attack).
Security testing is a spectrum. At one end, functional testers check basic things like whether admin URLs require login and whether error messages reveal stack traces. At the other end, specialist penetration testers (pentesters) use advanced tools and techniques to probe for deeper vulnerabilities. Most teams need both — and functional testers can find a surprising number of critical bugs before a pentester ever arrives.
The distinction that matters: security testing is not just about what the application is supposed to do. It’s about what happens when you deliberately try to make it do something it’s not supposed to. Thinking like an attacker is the core skill.
When to use it
- Before any release involving user data, authentication, or personal information
- Before releasing payment functionality (PCI-DSS requirements apply)
- When new endpoints are added that accept user-supplied input
- When authentication or session management code is changed
- In NZ, whenever a system stores or processes personal information — Privacy Act 2020 requires “reasonable security safeguards”
OWASP Top 10
The Open Web Application Security Project (OWASP) maintains a list of the ten most critical web application security risks. Understanding these helps you think like an attacker and know what to look for.
| # | Risk | What it means in practice |
|---|---|---|
| A01 | Broken Access Control | User A can view or modify User B’s data. Example: changing ?orderId=1001 to ?orderId=1002 shows another NZ customer’s order. The most common critical vulnerability in production systems. |
| A02 | Cryptographic Failures | Sensitive data is inadequately protected. Passwords stored in plain text; credit card numbers logged; pages served over HTTP instead of HTTPS; weak TLS configuration. |
| A03 | Injection | User-supplied data is interpreted as code. SQL injection via a search box; XSS (cross-site scripting) where a review field stores <script>alert(1)</script> and it executes when another user views it. |
| A04 | Insecure Design | Fundamental design flaws. Example: a “forgot password” flow that emails the user their actual password (meaning it was never hashed); no rate limiting on a login endpoint. |
| A05 | Security Misconfiguration | Default credentials left enabled (admin/admin); verbose error messages that show stack traces with file paths; directory listing enabled on a web server; debug mode left on in production. |
| A06 | Vulnerable Components | Using outdated libraries with known CVEs (Common Vulnerabilities and Exposures). A critical vulnerability in an npm package or Java library can compromise the entire application. |
| A07 | Auth and Session Failures | Session tokens that never expire; tokens that remain valid after logout; weak password requirements; no multi-factor authentication on high-value accounts. |
| A08 | Software Integrity Failures | No verification of third-party scripts loaded from CDNs; a compromised npm package silently published under the same name; no code signing for auto-update mechanisms. |
| A09 | Logging & Monitoring Failures | No audit trail for admin actions (who deleted that customer record?); failed login attempts not logged; no alerting when abnormal access patterns occur. |
| A10 | SSRF | Server-Side Request Forgery. The server fetches URLs supplied by users — allowing an attacker to make the server request internal resources (AWS metadata endpoints, internal APIs) that should never be publicly accessible. |
NZ context: Privacy Act 2020
In New Zealand, the Privacy Act 2020 requires organisations to have reasonable security safeguards to protect personal information. Unlike its predecessor, the 2020 Act introduced mandatory breach notification: if a privacy breach occurs and is likely to cause serious harm to affected individuals, the organisation must notify both the Privacy Commissioner and the affected individuals as soon as practicable.
The Privacy Commissioner has the power to investigate complaints, issue compliance notices, and refer cases to the Human Rights Review Tribunal. Penalties of up to NZD$10,000 per offence can apply.
What this means for testers: if you discover a vulnerability during testing — especially one that could expose personal information — treat it as a high-priority defect and ensure it is tracked, addressed, and verified before release. Document your finding clearly: what data was accessible, under what conditions, and what the potential harm is.
What functional testers can check
You don’t need Burp Suite or specialist training to find these bugs. A browser and some curiosity is sufficient:
| Check | How to do it | What a bug looks like |
|---|---|---|
| IDOR (Insecure Direct Object Reference) | Find a URL with an ID (e.g. /orders/1001). Log in as a different user. Try /orders/1001 — can you see the first user’s order? |
Any response other than 403 Forbidden is a critical bug |
| HTTPS everywhere | Try loading http:// versions of all pages. Check for mixed content warnings in browser DevTools. |
Any page that loads over HTTP, or loads resources (scripts, images) over HTTP on an HTTPS page |
| Verbose error messages | Submit malformed data; try accessing non-existent URLs; trigger server errors. Check the response body. | Stack traces, file paths (/var/www/html/app.php), database table names in error messages |
| Session expiry after logout | Log in. Copy a session cookie or auth token. Log out. Try using the copied token to make a request. | A 200 response after logout means the session was not invalidated server-side |
| Session expiry after inactivity | Log in. Leave the session idle for 30 minutes. Try to perform an action. | Session still valid after a long period of inactivity |
| XSS in input fields | Submit <script>alert(1)</script> in text fields (name, address, review, search). Save and view the result in a browser. |
An alert box appears, or the script tag appears unescaped in the HTML source |
| Unauthenticated admin access | Copy an admin URL (e.g. /admin/users). Open a private/incognito window and paste it without logging in. |
Page loads instead of redirecting to the login page |
Common bugs
- IDOR — changing
?customerId=123to?customerId=124returns another customer’s personal data. Extremely common and often critical. - Verbose error messages — a 500 response that includes a Java stack trace or internal file paths; attackers use this to understand the system architecture
- No rate limiting on login — allows an attacker to try thousands of password combinations (brute force) without being blocked
- Missing CSRF tokens — state-changing forms (change email, change password, transfer money) without CSRF tokens can be triggered by malicious sites if a victim is already logged in
- Password stored in plain text — detectable if “forgot password” sends you your actual password rather than a reset link
- Auth token in URL — tokens in query parameters (
?token=abc123) are logged by web servers, proxies, and browser history, leaking credentials
Tools
- OWASP ZAP (free) — automated scanner that crawls your application and identifies common vulnerabilities; good starting point for teams without a dedicated pentester
- Burp Suite Community (free) — intercepting proxy that lets you inspect and modify requests/responses; used by professional pentesters and advanced testers
- Browser DevTools — built into every browser; use the Network tab to inspect requests/responses, the Application tab to view cookies and storage, and the Console to spot JavaScript errors
Tips
Think like an attacker. As a functional tester, you can find a significant portion of security bugs without specialised tools — just by thinking like an attacker. What would happen if I changed this ID? What if I remove the auth header? What if I submit a script tag? What if I try to access this admin URL when logged out? These questions cost nothing and catch critical issues.
- Raise security bugs as high priority — a bug that exposes personal data is more critical than a bug that breaks a feature. Make sure your defect severity model reflects this.
- Don’t just test happy paths — the most dangerous bugs are found when you deliberately behave as a malicious user would
- Check error messages carefully — they frequently reveal internal implementation details that are useful to an attacker and should never be exposed to end users
- Include security testing in your Definition of Done — at minimum, the functional-tester security checklist above should be completed before any user story is marked done
4 Now You Try
Three graded exercises — spot, fix, then build. Everything here is defensive: you’re finding gaps in your own system so they’re closed before release. Write your answer, run it for AI feedback, then compare to the model answer.
During testing of a NZ council portal you observe four things: (a) changing /rates/4501 to /rates/4502 shows another ratepayer’s account; (b) the “forgot password” email contains your actual password; (c) a 500 error page prints a full stack trace with server file paths; (d) your session cookie still works after you log out. For each, name the OWASP Top 10 category it maps to and why it matters for a system holding personal information.
Show model answer
OWASP mapping: (a) Changing /rates/4501 to /rates/4502 shows another account → A01 Broken Access Control (an IDOR). The system checks you're logged in but not that the record is yours. It exposes other ratepayers' personal information — under the Privacy Act 2020 that's a notifiable breach risk. Fix: enforce per-record ownership checks server-side; return 403. (b) "Forgot password" emails your actual password → A02 Cryptographic Failures (and arguably A04 Insecure Design). If the system can email your password, it isn't hashed — so a database leak exposes every password. Fix: store passwords hashed (e.g. bcrypt/argon2) and send a one-time reset link, never the password. (c) Stack trace with file paths in a 500 page → A05 Security Misconfiguration. Verbose errors hand an attacker the system's internal structure (paths, frameworks, table names). Fix: show a generic error to users; log the detail server-side only; disable debug mode in production. (d) Session still valid after logout → A07 Identification and Authentication Failures. Logout must invalidate the session server-side, not just clear it client-side. Fix: destroy/revoke the session token on logout so a copied token stops working.
A developer describes a NZ banking app’s login below. It has three security weaknesses that a defensive tester should raise. Identify each and state the fix.
“There’s no limit on login attempts. After login we put the session token in the URL like
?token=abc123 so it’s easy to pass around. Failed logins say ‘wrong password’ if the email exists and ‘no such user’ if it doesn’t.”
Identify the weaknesses and give the fix for each:
Show model answer
Three weaknesses (all A07 Auth/Session, with an A02 element):
1. No rate limiting on login — allows unlimited password guessing (brute force / credential stuffing).
Fix: rate-limit and lock out after repeated failures; add CAPTCHA and/or MFA on a banking app.
2. Session token in the URL (?token=abc123) — tokens in URLs are logged by servers, proxies, and browser history, and leak via the Referer header, so credentials are exposed.
Fix: put the session token in a secure, HttpOnly, SameSite cookie — never in the URL.
3. Different messages for "wrong password" vs "no such user" — user enumeration: an attacker can discover which emails are registered.
Fix: return a single generic message ("email or password is incorrect") regardless of which part failed.
A senior would add: enforce MFA on a high-value banking account and confirm tokens are invalidated on logout and expire on inactivity.
A NZ government service handling personal information is about to release a new authenticated “view my submissions” feature. The NZISM expects reasonable security controls and the Privacy Act requires safeguarding personal information. Design a defensive security checklist a functional tester can run with just a browser — cover access control, transport security, error handling, sessions, and input handling. For each item, give the check and what a bug looks like.
Show model answer
Defensive functional-tester security checklist (browser only): 1. Access control (IDOR) — Check: log in as User A, then request User B's submission by changing an ID in the URL or request. Bug: any response other than 403/blocked — User B's data is returned. 2. Transport security (HTTPS) — Check: try the http:// version of pages and watch DevTools for mixed content. Bug: a page loads over HTTP, or an HTTPS page pulls scripts/images over HTTP. 3. Error handling — Check: submit malformed input and hit non-existent URLs; read the response body. Bug: stack traces, server file paths, framework versions, or database table names exposed to the user. 4. Sessions — Check: log in, copy the session token/cookie, log out, then reuse it; also leave a session idle. Bug: the copied token still works after logout, or the session never expires on inactivity. 5. Input handling (XSS) — Check: enter into name/address/search fields, save, then view the result. Bug: the alert fires, or the tag appears unescaped in the page source. These are all defensive checks on your own system. A senior would also fold this list into the Definition of Done and raise any finding that exposes personal information as a high-priority, Privacy-Act-relevant defect.
Self-Check
Click each question to reveal the answer.
Q1: What is the fundamental difference between functional testing and security testing?
Functional testing asks “does the system do what it’s supposed to?” Security testing asks “what happens when I deliberately try to make it do something it’s not supposed to?” The mindset shift — thinking like an attacker while staying defensive — is the core skill, because the worst defects only appear off the intended path.
Q2: What is an IDOR, how do you test for it defensively, and which OWASP category is it?
An Insecure Direct Object Reference lets a user reach another user’s record by changing an identifier (e.g. /orders/1001 → /orders/1002). Test it by logging in as one user and requesting another user’s data by ID — you should get a 403, not the data. It maps to A01 Broken Access Control, the most common critical web vulnerability.
Q3: Why are verbose error messages a security problem, and what should happen instead?
Stack traces, file paths, framework versions, and database table names in an error response hand an attacker a map of the system’s internals. Users should see a generic error message, the detail should be logged server-side only, and debug mode must be off in production. This is A05 Security Misconfiguration.
Q4: How can you tell, defensively, that passwords are not being hashed?
If the “forgot password” flow emails you your actual password, the system must be storing it in a recoverable form rather than a one-way hash — so a database leak would expose every password. A correct design sends a one-time reset link and stores passwords hashed. This relates to A02 Cryptographic Failures.
Q5: In the NZ context, why should a security finding that exposes personal information be treated as high priority?
The Privacy Act 2020 requires reasonable security safeguards and mandatory notification of breaches likely to cause serious harm, and frameworks like the NZISM expect appropriate controls on systems handling personal or official information. So a vulnerability exposing personal data is both a technical defect and a legal exposure — document it clearly (what data, conditions, potential harm), fix it, and verify before release.
Related techniques
Practice this technique: Try Test Lead Practice 03 — Security surface.
NZ context — Privacy Act 2020 and security obligations
The New Zealand Privacy Act 2020 (effective December 2020) replaced the 1993 Act and introduced mandatory breach notification. Under the Act, organisations must notify the Privacy Commissioner and affected individuals of a privacy breach that causes or is likely to cause serious harm — within 72 hours is best practice (the Act requires “as soon as practicable”).
Key testing implications:
- Data at rest — is personal information (name, DOB, IRD number, bank account) encrypted in the database?
- Data in transit — is all PII transmitted over HTTPS?
- Right to access and correction — can users view and correct their personal data?
- Data minimisation — is the system collecting only what it needs?
- Retention — does the system delete data when it’s no longer needed?
For security testing in a NZ context, OWASP Top 10 remains the technical baseline, but compliance with the Privacy Act adds the legal requirement. A SQL injection vulnerability that exposes customer records is both a technical security failure AND a Privacy Act breach notifiable to the Privacy Commissioner.
Testers working on NZ government or health systems also need to be aware of the Health Information Privacy Code 2020, which has stricter rules for health data.