OSWA common mistakes
OSWA · Understand the traps and how to avoid them.
Running directory brute-force tools with default wordlists and default extensions, then declaring the target fully enumerated after the first pass returns only 200s for the base page. The candidate never discovers backup files, hidden parameters, or alternate vhosts.
Default wordlists are tuned for generic CMS layouts and miss application-specific naming (e.g., /api/v2/internal, .bak, .old, .swp, .git). Candidates also stop at status-code filtering without inspecting response length or content differences, so soft-404s mask real hits.
What to do instead
Layer enumeration: run a general wordlist, then a technology-specific one after fingerprinting the stack, add extensions based on observed server-side languages, and filter by response size and word count rather than status code alone. Manually check for .git/, .env, backup archives, and source maps. Fuzz parameters on every discovered endpoint with a parameter-name wordlist and compare baseline versus injected response bodies. Record every discovered path in notes as you go.
Treating a reflected XSS finding as complete after the alert(1) popup fires, without demonstrating session-token impact, without checking CSP, and without testing whether the payload survives different contexts (attribute, JavaScript string, URL, JSON).
Candidates optimize for the fastest visible proof and stop. They also reuse one payload across contexts, so a payload that works in an HTML body fails inside an href or a script block and they wrongly conclude the parameter is safe.
What to do instead
For each injection point, identify the exact output context by inspecting the surrounding markup, then choose a context-appropriate payload (breaking out of quotes, closing tags, or using template-literal syntax). Verify whether HttpOnly is set on the session cookie, whether CSP blocks inline script, and whether a same-site or httpOnly bypass exists. Test at least one payload that demonstrates real impact, such as reading a non-HttpOnly cookie or a DOM value, and note any encoding or filtering that must be bypassed.
Testing CSRF by replaying a request in a proxy with the token header removed, seeing it succeed, and reporting a vulnerability without checking whether the session cookie is SameSite=Lax or Strict, or whether the endpoint actually changes state for a victim.
Proxy replays are same-origin and carry cookies automatically, which hides the cross-site delivery problem. Candidates forget that SameSite defaults now block the classic cross-site form POST, and they test a GET that only reads data.
What to do instead
Confirm the endpoint performs a state-changing action tied to the victim's account. Then check the Set-Cookie attributes for SameSite and Secure. If SameSite=Lax, target top-level GET navigations; if Strict, look for client-side gadget chains or subdomain-based same-site delivery. Build an actual cross-origin proof (a hosted HTML form or a fetch with credentials) and confirm the change persists on the victim account, rather than relying on a proxy replay.
Detecting SQL injection with a single quote and then stopping at the error message, or jumping straight to sqlmap with default settings on a production-like target and getting blocked or missing the injection point entirely.
Candidates confuse an error with exploitability and do not determine the injection type (union, boolean, time-based, stacked) or the DBMS. Default tool settings use aggressive payloads that trip WAFs and can corrupt data on UPDATE/DELETE contexts.
What to do instead
Confirm the injection with paired true/false conditions and a controlled time delay, then determine column count and DBMS version manually before automating. Use sqlmap with --technique and --risk/--level tuned to what you already proved, --dbms set, and --batch for reproducibility. Test every parameter including cookies, JSON bodies, and headers. Avoid stacked queries on write endpoints unless the goal requires them.
Reporting SSRF after the server fetches an external collaborator URL, without testing whether internal addresses, cloud metadata endpoints, non-HTTP schemes, or redirects are reachable, and without checking whether the response body is returned to the attacker.
An out-of-band callback proves the request was made but not that it is useful. Candidates also assume localhost is blocked without testing alternate representations (127.0.0.1, [::1], 0.0.0.0, decimal/octal encodings, DNS rebinding hostnames) and forget that many SSRF sinks are blind.
What to do instead
Classify the SSRF as full-response or blind by observing whether fetched content appears in the reply. Enumerate bypasses systematically: loopback variants, IPv6, decimal and octal IPs, redirects from an attacker-controlled host, and DNS names resolving to internal ranges. Test non-HTTP schemes (file, gopher, dict) where the client library allows them. For blind SSRF, use a collaborator to confirm and then attempt internal port scanning by timing or error differences.
Testing XXE only with a file:// entity in an XML body that the parser silently ignores, and never testing whether the endpoint accepts XML at all, whether external entities are enabled, or whether the response reflects entity content.
Modern parsers disable external entities by default, so a null result is read as 'no XXE' rather than 'wrong parser or wrong content type'. Candidates also miss that the same endpoint may accept XML via a Content-Type swap, a SOAP action, an SVG upload, or a DOCX/XLSX file.
What to do instead
First confirm the endpoint parses XML by sending malformed XML and observing a parser error. Then test in-band entity expansion with a known file, and if no reflection, switch to out-of-band via an external DTD hosted on a collaborator to confirm entity resolution. Test parameter entities and error-based exfiltration when direct reflection is unavailable. Check alternate entry points: file uploads (SVG, Office documents), SOAP endpoints, and any XML-configured integration.
Concluding CORS is safe because the Access-Control-Allow-Origin header is present but not wildcard, without checking whether the origin is reflected dynamically and whether Access-Control-Allow-Credentials is true.
Candidates check only the static response to their own origin, missing that the server echoes whatever Origin is sent. They also forget that wildcard plus credentials is invalid, so the dangerous case is reflected origin plus credentials, often gated by a weak regex or null-origin allowance.
What to do instead
Send requests with several crafted Origin values, including an attacker domain, a subdomain of the target, a null origin, and a suffix-match attempt (target.com.attacker.com), and compare the returned Allow-Origin and Allow-Credentials headers. If reflection occurs with credentials, build a cross-origin fetch that reads a sensitive authenticated endpoint and confirm the data is accessible. Note any preflight behavior for non-simple requests.
Testing SSTI by injecting a single arithmetic expression and, when it evaluates, immediately claiming remote code execution without identifying the template engine, the sandbox, or a working object-access path.
Arithmetic evaluation proves template evaluation but not exploitability; many engines evaluate math inside a sandbox that blocks object traversal. Candidates also use one engine's payload syntax across engines and get false negatives on Jinja2, Twig, Freemarker, or Velocity.
What to do instead
Fingerprint the engine with engine-specific probes (e.g., distinct syntax for Jinja2/Twig versus Freemarker/Velocity) and observe which evaluates. Then progress from arithmetic to string operations to object access, using the engine's documented object graph to reach a command-execution primitive. Test whether the sandbox blocks the path and look for bypasses. Confirm execution with a benign command and document the exact payload chain.
Spending the entire session on one promising vulnerability and leaving other domains untested, so the report covers deep exploitation of a single finding but misses simpler high-impact issues elsewhere.
Candidates anchor on the first interesting signal and chase it, especially when a payload chain is close to working. Time management is rarely rehearsed, and the exam rewards coverage across domains rather than depth on one.
What to do instead
Before deep exploitation, do a fast structured sweep of every domain against every identified input and endpoint, recording a one-line status per test. Then rank findings by likely impact and allocate remaining time proportionally, reserving a fixed block for reporting. Set a hard time-box per finding and move on when it expires, returning only if time remains.
Writing the final report as a list of payloads and screenshots without stating the affected endpoint, the preconditions, the reproduction steps from a clean session, and the concrete impact, so the finding cannot be reproduced by a reviewer.
Candidates treat the report as an afterthought and assume the reviewer shares their context. They omit the request/response pair, the exact parameter, and the state required (authenticated role, header, content type), which makes the finding unverifiable.
What to do instead
For each finding, record: affected URL and parameter, required authentication and role, the exact request with headers and body, the observed response, and a step-by-step reproduction from a fresh session. State impact in terms of what an attacker gains. Include the remediation. Write notes during testing, not after, so the request/response pairs are captured verbatim.