Security Testing Fundamentals

Security testing checks that a system protects its data and functions from misuse: only the right people can see information (confidentiality), nobody can change it without permission or without trace (integrity), and the service stays usable for those entitled to it (availability). Where a functional test asks "does the feature work for a valid user?", a security test asks "what happens when someone who should not be able to do this tries?".

In a payroll portal, a functional test confirms that an employee can download her own salary slip. Security tests confirm that she cannot download a colleague's slip by changing the id in the URL, that the bank account she updates is really hers when payroll runs, and that the portal stays up on payday under a flood of failed logins. ISTQB treats security testing as a type of non-functional testing, judged against the quality characteristic that ISO/IEC 25010 calls security.

Why it matters

A functional defect usually costs one user one task. A security defect can expose every user's data at once, and the attacker who finds it does not file a bug report. The cost arrives later, as a breach, a regulatory fine, lost customers and an emergency fix under pressure, and it is usually far higher than the cost of the test that would have found the weakness.

For a tester, security is where the ordinary habits pay most: thinking in negative cases, reading a requirement for what it forbids, questioning what the system assumes. Many security defects are ordinary defects, a missing check, a wrong default, a verbose error message, that a tester who knows what to look for finds without special tools. This lesson gives the vocabulary and the ground rules; the following lessons start with the OWASP Top 10 and then take the main areas, authentication, sessions, access control, injection and more, one at a time.

What security protects: confidentiality, integrity, availability

Security requirements are easier to test once you name which of three properties each one protects. Confidentiality: information is visible only to those authorised to see it. Integrity: data and functions change only through authorised actors and authorised paths, and changes can be traced. Availability: the service is there, with acceptable performance, when legitimate users need it. Security people call these the CIA triad. ISO/IEC 25010:2023 lists confidentiality and integrity among the sub-characteristics of security, next to non-repudiation, accountability, authenticity and resistance (staying in operation while under attack), and files availability under reliability, which is why availability tests often sit with the performance work.

Each property suggests its own test questions, and the expected result of a security test is often that nothing happens: the request is refused, the data is unchanged, the service keeps serving.

  • Confidentiality: can a logged-out visitor, another employee or a lower role read the salary slip? Does the slip leak through a URL, a log, a cache or an error message?
  • Integrity: can the bank account be changed without re-authentication, by a tampered request or by a replayed one? Is every change recorded with who and when?
  • Availability: what happens to the login page under a burst of failed attempts, or when a 50 MB file is sent to the "query my slip" form? Does one user's abuse slow everyone down?

Threats, vulnerabilities, attacks and risk

Five words carry most security conversations, and testers mix them up. An asset is something worth protecting: salary data, the payroll run, the company's reputation. A threat is a potential cause of harm to an asset, usually named with its actor: a disgruntled employee, a criminal group, an automated bot, an honest administrator making a mistake. A vulnerability is a weakness a threat could use: a missing authorisation check, an outdated library, a password reset link that never expires, a backup left in a public folder. An attack is an attempt to use a vulnerability against an asset, and an exploit is the technique or code that does it. Risk combines how likely a successful attack is with how much damage it would do, the same likelihood-and-impact reasoning as in risk-based testing.

The division of labour follows. Testers cannot remove threats; the bots exist whether or not the portal is weak. Testers find vulnerabilities before an attacker does and report them with enough evidence for the team to judge the risk. A short note like the one below, written when a feature starts, turns a vague worry into test conditions:

Asset:          Salary slips (PDF)
Threat:         An employee reads a colleague's slip
Vulnerability:  Slip URL uses a guessable id and no ownership check
Test condition: GET another user's slip id with my session -> 403 or 404, no slip

Asset:          Bank account number for salary
Threat:         Attacker with a stolen session redirects a salary
Vulnerability:  Change saved without re-authentication or notice
Test condition: Change the account -> re-auth prompt, notice sent, audit record

Asset:          Employee accounts
Threat:         A bot tries leaked passwords
Vulnerability:  No rate limit; error text reveals whether a username exists
Test condition: Burst of failures -> lockout or delay; same message for any user

Try it: Test Scenario Generator Try it: Negative Test Generator

Four ways to look: SAST, DAST, vulnerability scanning and penetration testing

Security testing uses several approaches that look at the system from different sides. Each finds weaknesses the others miss, so mature teams combine them, and a tester should know which one found what.

  • Static application security testing (SAST) analyses source or compiled code without running it, like a reviewer reading every line. It finds code-level weaknesses early, a SQL query built by string concatenation, a hard-coded secret, and points to the file and line. It runs in the developer's editor (IDE) and the CI pipeline, often reports findings that turn out to be false positives, and cannot see runtime configuration or how components are deployed.
  • Dynamic application security testing (DAST) tests the running application from outside, as a user or attacker would, sending requests and inspecting responses. The name usually refers to automated tools that crawl the application and send attack-like requests, but the principle is the same when a tester does it by hand. It finds what is actually exposed: a missing security header, a session cookie without HttpOnly, an input that reflects script, an endpoint that answers without a token. It needs a deployed test environment and test accounts, misses code it cannot reach, and cannot say which line to fix. Most of what a QA tester does by hand in a browser or an API client is dynamic testing in this sense.
  • Vulnerability scanning checks what is installed and exposed, servers, frameworks, libraries, open ports, TLS settings, against known vulnerabilities and common misconfigurations. Known vulnerabilities are published with CVE (Common Vulnerabilities and Exposures) identifiers, such as CVE-2021-44228 for the Log4j flaw called Log4Shell; software composition analysis (SCA) does the same matching for an application's dependencies. Scanning is fast, broad and repeatable, a good pipeline gate, but it knows only weaknesses that are already known and nothing about your business logic.
  • Penetration testing is a human-led, authorised simulation of an attack within an agreed scope and time. The tester chains findings, a verbose error plus a weak password policy, to show what an attacker could actually reach. NIST SP 800-115 describes it in four phases: planning, discovery, attack and reporting. It gives the strongest evidence and the deepest coverage of one system at one moment, costs the most, and so is often scheduled before a major release or once a year.
SAST reads the code, DAST probes the running application, vulnerability scanning matches components against known weaknesses, and a penetration test chains weaknesses by hand under written authorisation.

SASTstatic · code

Static application security testing

Looks at:
Source or compiled code, without running it
Needs:
The code and a rule set for its language
Typical finding:
SQL built by string concatenation in file X, line 112
Limits:
Runtime configuration and deployment; many false positives
When and who:
IDE and CI, on every commit; developers own the findings

DASTdynamic · running app

Dynamic application security testing

Looks at:
The running application, from outside, as an attacker would
Needs:
A deployed test environment and test accounts
Typical finding:
Session cookie without HttpOnly; endpoint answers without a token
Limits:
Code it cannot reach; cannot name the line to fix
When and who:
Each deployment to the test environment; QA testers and DAST tools

Vulnerability scanningautomated · known weaknesses

Matches components against known weaknesses

Looks at:
Installed servers, frameworks, libraries, ports and TLS settings
Needs:
Network access or the dependency list, and a current weakness database
Typical finding:
Framework version with a published CVE; TLS 1.0 still enabled
Limits:
Business logic, and weaknesses no database lists yet
When and who:
Pipeline gate and scheduled runs; platform or security team

Penetration testhuman-led · authorised

An authorised attack simulation that chains weaknesses

Looks at:
The whole system within the agreed scope, as a skilled attacker would
Needs:
Written authorisation, a scope, a time window and an expert
Typical finding:
Verbose error plus weak password policy leads to the HR admin role
Limits:
Anything outside the scope, and anything added after the test
When and who:
Before a major release or yearly; a specialist team or vendor

Most of what a QA tester does by hand in a browser or an API client is dynamic testing.

The rule: test only with written authorisation

A security test sends the same requests an attacker would. What separates testing from attacking is permission, not intent: in many countries, accessing a computer system without authorisation is a criminal offence even when nothing is damaged and the aim was to report the weakness. "I was only testing" does not make the access authorised. So the rule is absolute: test only systems you own or have written permission to test, and only within the scope that permission describes.

Written permission in practice is a short rules-of-engagement note agreed before the first request. For your own team's test environment it may be the test plan with its security scope signed off by the product owner; for production, a third-party service or a client's system it is an explicit document. A bug bounty programme's published policy counts as written authorisation, but only for the targets, techniques and conduct it lists.

  • Use test environments and test accounts you created; never make a real customer's data the victim of a test.
  • Use benign payloads that reveal handling without damage: a single quote ' or <b> shows whether input is escaped; nothing needs to be deleted to prove a point.
  • Stop and report when you reach data you should not see, and keep findings in a restricted ticket without screenshots of real personal data. Going further is the penetration tester's job under their own authorisation.
Rules of engagement: payroll portal, release 4.2 security pass
Authorised by:  Head of HR Systems (product owner), 2026-10-04
Targets:        https://payroll-test.example only (test environment)
Out of scope:   production, the payment provider, the SMS gateway, staff laptops
Accounts:       test users EMP-1001, EMP-1002, HR-ADMIN-01 (test data only)
Allowed:        manual checks, header, cookie and auth checks, benign payloads
Not allowed:    denial of service, password guessing across many accounts,
                social engineering, copying any real employee data if encountered
Window:         2026-10-05 to 2026-10-08, 08:00 to 18:00 Riyadh time
Contacts:       QA lead (findings), platform on-call (if something breaks)
Findings:       restricted ticket in the tracker, no screenshots of real data

Worked example: a first security pass on the payroll login

The rules of engagement above are signed; you have the test environment, three test accounts and an afternoon. A first pass does not try to break in. It checks the baseline controls one property at a time and records evidence.

  • Confidentiality: log in as EMP-1001, open your slip, note the URL /slips/48213.pdf, then request /slips/48214.pdf, the slip of your other test account EMP-1002. Expected: 403 or 404 and no slip; record the status, not the content. Repeat without a session: expected 401 or a redirect to the login page.
  • Session and configuration: paste the login response headers into the Cookie Analyzer and the Security Header Analyzer. Expected: the session cookie carries Secure, HttpOnly and a SameSite value, and Strict-Transport-Security, Content-Security-Policy, X-Content-Type-Options: nosniff and frame protection (X-Frame-Options or the CSP frame-ancestors directive) are present; together these headers tell the browser to use HTTPS only, limit where scripts may load from, not guess content types and not show the page inside another site's frame. Each missing item is a finding with the exact response attached.
  • Integrity: as EMP-1001, change the bank account. Expected: the portal asks for the password or a one-time code again, notifies the employee and writes an audit record. Then check that nobody else can make this change: send the same change request for EMP-1001's account with EMP-1002's token, from an API client or the API Authentication Tester. Expected: 403 or 404, and EMP-1001's account unchanged when you look again. The tool assumes the token you enter should be accepted, so it flags this rejection as a failure; here the rejection is exactly the result you want, and its rows without a usable token should get 401.
  • Authentication and availability: enter a wrong password for EMP-1002 fifteen times. Expected: lockout or a growing delay after the agreed number of attempts, and the same error text for a wrong password and a non-existent user, so the login does not reveal which usernames exist. Meanwhile EMP-1001 can still log in normally: one account's failures must not lock everyone out.

Try it: Security Header Analyzer Try it: Cookie Analyzer Try it: API Authentication Tester

Common mistakes

  • Treating security as the penetration tester's job alone, so nothing is checked until the yearly test and every finding lands a week before release.
  • Testing only with a valid user and valid data; security defects live on the paths of the wrong user, the missing token and the tampered request.
  • Confusing a threat with a vulnerability: "someone could steal passwords" is a threat and not testable; "the reset link never expires" is a vulnerability and is.
  • Running a scanner, filing its hundred findings unread and calling the product tested; scanner output needs triage and says nothing about business logic.
  • Testing a system, environment or third-party service the written authorisation did not name, because it was reachable.
  • Pasting real personal data or a live session token into a ticket, a chat or an online tool while documenting a finding.

The QA perspective

On a real team security testing starts in refinement: for every story that touches login, roles, money, personal data, uploads or an external integration, ask what the story forbids as well as what it allows, and write that down as negative acceptance criteria. Ask the developers which SAST and dependency scanners run in the pipeline and who triages them; ask the product owner who signs the security scope of the test plan, and when the last penetration test was and what it found.

Record security findings as ordinary defects with two extra fields: the property affected (confidentiality, integrity or availability) and the evidence (the exact request and response, secrets redacted). Rate severity by impact and note how easily the weakness can be reached, since security teams weigh both when they rank findings. Keep the ticket restricted, and after the fix run confirmation testing with the same request, then regression tests on the neighbours the fix may have missed, for example the same check on the API as on the web page.

Practice exercise

Sort a worry list into threats, vulnerabilities and test conditions

Your task

The product owner of the payroll portal sent you the list below after a security awareness session. Decide for each line whether it names a threat, a vulnerability or an asset, write one test condition for every vulnerability with the CIA property it protects, and mark which items you may test yourself in the test environment under the rules of engagement from the lesson and which belong to a scanner or a penetration tester.

Material
1. Hackers could sell our employees' salaries.
2. The PDF export puts the employee number in the file name, and the folder is public.
3. The "forgot password" e-mail link still works after it has been used once.
4. The portal runs a web framework version that is three years old.
5. Payroll data for 1,200 employees.
6. An admin could be tricked into approving a fake bank account change.
7. Error pages print the full stack trace, including the database name.
Steps
  1. Label each line: asset, threat or vulnerability.
  2. Write a test condition with an expected result for every vulnerability.
  3. Tag each test condition with confidentiality, integrity or availability.
  4. Decide: in scope for you, for a scanner, or for a penetration tester.
Show the model answer
Model answer

Line 1 is a threat (actor: criminals, aim: selling data) and line 5 is the asset it targets; neither is testable on its own. Line 6 is also a threat (social engineering against an admin), but it points at a vulnerability you can test: a bank account change that takes effect without a second check.

Line 2, vulnerability, confidentiality: request the export file of another employee number with no session and with a different test user's session; expected 401, 403 or 404 and no file. In scope for you.

Line 3, vulnerability, integrity of the account: use a reset link, then open it again; expected an error and no second reset. In scope for you with a test account.

Line 4, vulnerability if that version has known weaknesses, potentially all three properties: matching the framework version against known vulnerabilities is the scanner's job. Test condition: the dependency scan in the pipeline reports no unresolved known vulnerability above the agreed severity for this framework; you confirm that the scan runs and that its findings have owners.

Line 6, the vulnerability behind the threat, integrity: as HR-ADMIN-01, enter a bank account change for EMP-1002 and check that it stays pending until a second check passes, confirmation by the employee in their own session or by a second approver; expected: the paid account unchanged until then, the employee notified, an audit record written. In scope for you; actually tricking a real admin is social engineering, which the rules of engagement forbid.

Line 7, vulnerability, confidentiality of configuration: trigger an error with an invalid id; expected a generic error page with details only in the server log. In scope for you; whether the stack trace lets an attacker go further is a question for the penetration tester.

Frequently asked questions

Is security testing functional or non-functional?

ISTQB classifies it as non-functional testing, assessing the security characteristic of ISO/IEC 25010. In practice many security tests look exactly like functional negative tests, a request from the wrong user with an expected 403, so the classification changes who plans the test, not how you write it.

Do I need to be a hacker or know how to code?

No. Most security defects a QA tester finds, missing authorisation checks, weak session cookies, verbose errors, missing headers, need an API client, a browser and the habit of trying the forbidden path. Reading code helps with SAST findings; exploitation skills belong to penetration testers.

Can I practise on a public website I do not own?

No, unless it publishes a bug bounty or responsible disclosure policy that explicitly allows it, and then only within that policy. Practise on your own test environment, on deliberately vulnerable training applications you install yourself, or on the Mutqan tools with headers and test-account tokens copied from systems you are authorised to test, never a real user's live token.

What is the difference between a vulnerability scan and a penetration test?

A scan is automated and broad: it matches versions and configurations against known weaknesses and runs on every build. A penetration test is manual, scoped and deep: a person tries to reach something valuable by combining weaknesses, including ones no database lists, and reports what was reached. Teams need both; the scan does not replace the test, and the test does not run every day.

References

Practise with Mutqan tools

Grade HTTP security headers (CSP, HSTS, X-Frame-Options, Referrer-Policy, Permissions-Policy, COOP/CORP) from pasted headers or a public URL.

Validation

Parse Set-Cookie headers and check Secure, HttpOnly, SameSite, Domain, Path, expiry and size best practices.

Validation

Test Bearer, Basic, API-key and custom-header authentication against an endpoint and compare authorised vs unauthorised responses.

API Testing

Generate high-level test scenarios covering functional, negative, security, usability and compatibility angles for a feature.

Test Design

Generate negative test cases for form fields and APIs: empty, null, wrong type, too long, injection, invalid format.

Test Design

Go deeper

Your progress on this topic

Part of the QA Roadmap