SQL injection, XSS, and CSRF are often discussed together, but they work differently. In SQL injection, data interferes with the structure of an SQL query. In XSS, untrusted content becomes executable code in the browser. In CSRF, the browser sends an unwanted action with the user's credentials attached automatically.
QA engineers need to distinguish the failure point and the expected protection. Entering the same string in every field and seeing no obvious error does not prove security. Work in an agreed test environment with test accounts and minimal, safe examples that test a specific hypothesis.
SQL injection: data becomes part of a query
The risk arises when SQL is constructed by unsafely incorporating untrusted input. That input may come from search, filters, a sort parameter, an import, or a previously stored value. Testing only the login form is insufficient.
Parameterized queries are the primary protection for values: input is passed as data, separately from the SQL structure. Column names and sort directions, where query parameters are generally inapplicable, require a controlled selection from allowed values. An ORM alone does not guarantee security: raw SQL built through concatenation retains the risk. Database account privileges should match the required operations.
Testing SQL handling without false conclusions
Start with valid data containing apostrophes and other allowed characters, such as the surname O'Connor. A correct system should save and find that record as specified, without SQL errors or an altered search scope. Rejecting all apostrophes is not automatically good protection; it may break legitimate data.
Then work with a developer to trace the parameter to the query and check parameterization. One successful example confirms only its own behavior, rather than the absence of all SQL injection. If you suspect a problem, record the request, error, and test dataset. Perform further checks using agreed methods without retrieving other people's data.
XSS: where data is used matters
User text may appear immediately after submission, after storage, or through the client-side DOM. Test these paths separately. A single comment might appear in a detail view, search, a notification, and an administration panel. Safe rendering in one place proves nothing about the others.
Protection depends on context: HTML text, attributes, URLs, and JavaScript require different rules. Automatic template escaping helps, but dangerous APIs and bypasses can reintroduce risk. If the product permits limited HTML, use an appropriate sanitizer with allowed constructs. CSP adds a protection layer but does not replace correct output handling.
Checking how a marker is displayed
Use a unique, safe string such as QA <marker> & “check” in a plain-text comment field. Save it, reopen the record as another test user, and check every supported view. The string should remain text; parts of it should not unexpectedly become DOM elements or change the page structure.
Inspect the rendered DOM and data path alongside the visual appearance. A missing part of the string may indicate a display bug but does not necessarily prove XSS. If execution confirmation is needed, use a separate, agreed, harmless test that does not affect real sessions or external systems.
CSRF: an unwanted action on behalf of a user
CSRF is relevant when the browser sends credentials automatically, such as a session cookie, and the server cannot distinguish an expected action from an imposed one. The user may be correctly authenticated; the issue concerns the request's origin and validation.
Typical protections include the intended CSRF token mechanism, Origin/Referer validation, and SameSite settings as an additional layer. The specific scheme depends on the architecture. Cross-site and cross-origin are different concepts, so a trusted neighboring subdomain needs separate analysis. POST alone provides no protection, and HttpOnly addresses a different problem. A CORS setting alone also does not block every way of sending a cross-site request.
Testing protection for state changes
Choose a noncritical setting on a test account. First perform the permitted request and record the result. Then test a missing, corrupted, and incorrectly bound CSRF token if the chosen scheme requires one. Also reproduce the request from another controlled origin while preserving the intended browser conditions.
Inspect the resulting state as well as the response: a rejected request must not change the setting. Check that GET does not change state and that an alternative endpoint or body format cannot bypass protection. APIs that transmit credentials differently may have a different risk model; the absence of a CSRF token alone does not prove a vulnerability.
Practical example: a user profile
A test profile contains a surname, public description, and language setting. Create initial values and save a snapshot of the expected state.
- →Save O'Connor: the full surname is stored, search finds the correct record, and the response exposes no SQL diagnostics.
- →Save a safe text marker in the description: it is displayed safely in the profile, list, and administration view.
- →Attempt to change the language while violating the chosen CSRF protection: the server rejects the operation, and reading the setting again shows the original language.
- →Repeat the legitimate actions: protection allows normal editing and preserves the expected values.
This is a minimal regression check of specific protection mechanisms. The measurable outcome is three expected data results and no side effect from the rejected operation. It does not replace investigating every input and data-use location.
Common mistakes and retesting
Avoid grouping these classes under the single description “input is not validated.” SQLi requires separating code and data on the server, XSS requires safe use within browser contexts, and CSRF requires protecting actions with regard to credentials and request origin. Client-side validation replaces none of these boundaries.
After a fix, check neighboring fields, subsequent reads, imported data, and other endpoints for the same action. Keep an allowed scenario alongside the rejected one: security should prevent unwanted behavior while preserving normal use.
Key takeaways for QA engineers
Identify the mechanism and trust boundary first, choose a safe check, and observe the actual state. Absence of an error does not prove protection. The most useful report shows a specific data or action path, the expected control, and a reproducible result on test data.