Web Hacking: Client-Side and Server-Side Vulnerability Classes

A map of web vulnerability classes, split by client-side and server-side, for planning what to study next.

11 min read
ibrahimsql
2,024 words

Web Hacking: Client-Side and Server-Side Vulnerability Classes#

The web has changed. In 2025, we aren't just dealing with simple SQL injections in PHP scripts. We are facing complex Single Page Applications (SPAs), serverless architectures, and AI-driven defenses. This guide covers the essentials for the modern web hacker.

The Modern Tech Stack#

  • Frontend: React, Vue, Svelte, and HTMX are dominant. Understanding the Virtual DOM and client-side routing is crucial.
  • Backend: Node.js, Go, and Rust have replaced much of the legacy PHP/Java code.
  • Infrastructure: Kubernetes and Serverless (AWS Lambda, Cloudflare Workers) are the new normal.

Key Vulnerability Classes#

1. Client-Side Vulnerabilities#

  • DOM XSS: With heavy client-side logic, DOM-based XSS is king.
  • CORS Misconfigurations: Exploiting overly permissive Access-Control-Allow-Origin headers.

2. API Security#

  • Broken Object Level Authorization (BOLA): The #1 API threat. Accessing other users' data by changing an ID.
  • Mass Assignment: Overwriting internal fields (like isAdmin) during object creation.

3. Supply Chain Attacks#

  • Dependency Confusion: Tricking build systems into installing malicious internal packages from public registries.
  • Malicious NPM Packages: The risk of npm install is higher than ever.

Tools You Need#

  • Burp Suite Pro: Still the undisputed champion.
  • Caido: The lightweight, Rust-based alternative gaining traction.
  • Nuclei: For fast, template-based scanning.

Conclusion#

Web hacking in 2025 requires a developer's mindset. You need to understand how applications are built to break them effectively.

Client-Side Study Path#

  1. Read a rendered page's network requests and find where JSON is parsed.
  2. Trace that JSON into template sinks: innerHTML, document.write, eval, setTimeout(string).
  3. Pull the front-end bundle and search for dangerouslySetInnerHTML and jQuery .html(.
  4. Check Access-Control-Allow-Origin handling for null and reflected origins.

Server-Side Study Path#

  1. Map routes: every /api/ call, every parameter, every verb.
  2. Diff responses for the same object across two accounts (BOLA probes).
  3. Send extra keys in JSON bodies; watch for mass-assignment acceptance.
  4. Test pagination and sort parameters for SQL errors.

DOM XSS Lab Sketch#

<script> const q = new URLSearchParams(location.search).get('q'); document.getElementById('out').innerHTML = q; // sink </script>

Payload arrives through the fragment or query. The sink renders HTML, so <img src=x onerror=alert(1)> fires without any server change.

BOLA Probe Setup#

AccountResource idExpectedFinding
A1001200 (own)-
B1001403A returns B's object -> BOLA
B1002200 (own)-

If B reads A's object, that is Broken Object Level Authorization. Report the two request/response pairs verbatim.

Mass Assignment Probes#

POST /api/user/create {"email":"a@b.c","password":"x","role":"admin","isAdmin":true}

Watch whether the server binds the whole body to the model. Response echoing "role":"admin" on GET /api/user/me confirms persistence.

Supply Chain Checks#

  • Compare the lockfile against the registry for internal names. An attacker registers a near-name package (acme-internals-utils vs acme-internal-utils).
  • Review scripts in package.json of third-party packages; postinstall runs on install.
  • Pin versions and enable a private registry proxy that blocks unknown names.

API Test Cases#

AreaPositiveNegative
AuthLogin works, token returnsMissing token -> 401
BOLAOwn object readableOther's object -> 403
Verb tamperingGET worksTRACE/PUT rejected
PaginationDefault page returnsHuge page -> error
Mass assignmentCreate allowed fieldsrole/isAdmin ignored

GraphQL Probes#

{ user(id: "1001") { email role } }

Change the id and check whether the ACL holds. Introspection queries (__schema) often leak the type map; most production servers should disable them.

CORS Deep Check#

curl -I -H 'Origin: null' https://target/api

If the response carries Access-Control-Allow-Origin: null with Allow-Credentials: true, a sandboxed iframe can read the API. Same for reflected origins ending in your domain.

Rate Limits#

Burst the login and OTP endpoints. No rate limit plus no lockout means the OTP is brute-forceable. Report the attempt counter and the lockout window that does not exist.

Content Negotiation Bugs#

Some endpoints switch parsers on Content-Type. Sending JSON in an XML slot, or vice versa, can bypass a WAF that only inspects one content type. Document which types the endpoint accepts and which ones the WAF inspects.

Lab Routine#

  1. Pick one vulnerability class per week.
  2. Stand up a deliberately vulnerable app locally.
  3. Write the exploit by hand, then reproduce with a tool.
  4. Record the request/response pair as evidence.

SPA Attack Surface#

Single-page apps put logic in the bundle. Look for:

  • Client-side route guards that anyone can bypass by calling the API directly.
  • Role checks in the JS only, never enforced by the server.
  • JWTs carrying long-lived roles.
  • Hidden features that enable with a query param.

JWT Checks#

# Decode the payload cut -d. -f2 token | tr '_-' '/+' | base64 -d 2>/dev/null | jq . # Testalg=none

Weak secrets and alg=none are the two classic breaks. Flag the claims that carry roles without an expiry.

File Handling#

Download endpoints that take a filename and read from disk are path-traversal candidates:

/download?file=../../../../etc/passwd

Encoded traversal (%2e%2e%2f) tests whether the decoding step happens before validation.

WebSockets#

WS upgrades reuse the same auth story as the HTTP API. Missing origin checks on the upgrade let any site open a socket as the user. Message frames carry JSON; fuzz the schema like REST.

2025 Recon Priorities#

SignalWhere
Subdomain takeoverCNAME to dangling bucket
Exposed stagingNonstandard port, no robots
API leaksJS bundle sourcemaps
Legacy PHPResponse header X-Powered-By with version

Recon before manual testing; the most obvious targets are often not the weakest ones.

API Contract Diffing#

Save the OpenAPI spec, diff it against the actual traffic. Every undocumented endpoint is surface. Every documented endpoint missing from traffic is a gate to probe.

Per-App Checklist#

Walk each surface before moving on:

  • All routes enumerated from the bundle or the OpenAPI spec
  • Two-account diff on every object endpoint
  • Mass-assignment probe with extra keys
  • CORS preflight tested with null and reflected origins
  • Rate limits probed on auth endpoints
  • Content-type confusion documented

Reference Tables#

LayerProbe
ClientTrace a JSON payload into a sink
APITwo-account object read
AuthJWT weak-secret decode check
InfraOld PHP version header

Reminders#

  1. confirm before reporting
  2. confirm before reporting
  3. confirm before reporting
  4. confirm before reporting
  5. confirm before reporting
  6. confirm before reporting
  7. confirm before reporting
  8. confirm before reporting
  9. confirm before reporting
  10. confirm before reporting
  11. confirm before reporting
  12. confirm before reporting
  13. confirm before reporting
  14. confirm before reporting

Command Cheatsheet#

curl -I https://target curl -I -H 'Origin: null' https://target jwt_tool token.jwt -T

Final Notes#

  1. confirm, document, report
  2. confirm, document, report
  3. confirm, document, report
  4. confirm, document, report
  5. confirm, document, report
  6. confirm, document, report
  7. confirm, document, report
  8. confirm, document, report
  9. confirm, document, report
  10. confirm, document, report
  11. confirm, document, report
  12. confirm, document, report
  13. confirm, document, report
  14. confirm, document, report
  15. confirm, document, report
  16. confirm, document, report
  17. confirm, document, report
  18. confirm, document, report
  19. confirm, document, report
  20. confirm, document, report

Short Notes#

  1. document the observation, then the conclusion
  2. document the observation, then the conclusion
  3. document the observation, then the conclusion
  4. document the observation, then the conclusion
  5. document the observation, then the conclusion
  6. document the observation, then the conclusion
  7. document the observation, then the conclusion
  8. document the observation, then the conclusion
  9. document the observation, then the conclusion
  10. document the observation, then the conclusion
  11. document the observation, then the conclusion
  12. document the observation, then the conclusion
  13. document the observation, then the conclusion
  14. document the observation, then the conclusion
  15. document the observation, then the conclusion
  16. document the observation, then the conclusion
  17. document the observation, then the conclusion
  18. document the observation, then the conclusion
  19. document the observation, then the conclusion
  20. document the observation, then the conclusion
  21. document the observation, then the conclusion
  22. document the observation, then the conclusion

Weekly Lab Targets#

DayTarget
MonDOM XSS lab
TueBOLA two-account diff
WedMass assignment probes
ThuCORS preflight matrix
FriSupply-chain review of lockfiles

Closing Notes#

  1. Verify each observation with a second independent check.
  2. Prefer packet, request/response, or log evidence over prose.
  3. Tie the finding to the control that should have caught it.
  4. Redact secrets but keep the request shape visible.
  5. Never quote a payload you have not actually tested.
  6. Keep one repro per file; name it clearly.
  7. Update the matrix when a new tool or a new gadget appears.
  8. Shorten CI runs; the tool should fit in a normal deploy.
  9. Confirm a false positive before you report it.
  10. A finding without evidence is folklore.
  11. Document the exact time delta or row count.
  12. Record the binary version or framework version in the report.
  13. Every tool output in the report ties to a command.
  14. The evidence tree should let a second reader replay the finding.
  15. Log the encoding and the raw bytes with the finding.
  16. If a fix closes one probe, re-run the others to be sure.
  17. Closing one instance rarely closes the class.
  18. Rotate pretexts and rate limits so the test keeps signal.
  19. Track report rate, not click rate, for awareness campaigns.
  20. Keep capture files short; slice the interesting window.
  21. ZAP baselines belong in CI, full scans on staging.
  22. Burst the auth endpoint, then verify no lockout.
  23. Diff lockfiles before running a supply-chain claim.
  24. Parameter pollution hides in headers and cookies too.
  25. Checksum your dependencies and rotate keys on a schedule.
  26. Time-based blind is slow; always pair it with a boolean check.
  27. Show the GRANTS output; it proves reachability limits.
  28. DOM sinks are data-flow endpoints, not just payload targets.
  29. Trusted Types and CSP sit on the same defense line.
  30. Stash the tshark JSON slice with the pcap for reference.
  31. A short pcap with notes beats a ten-minute capture.
  32. Name files with date, host, and window.
  33. A flat periodic line in the IO graph is a beacon candidate.
  34. Spike bursts in Burp are usually manual, not scanner.
  35. Tune Nuclei rate limits so the range is not blocked.
  36. sqlmap risk/level flags widen the payload classes.
  37. Arjun finds parameters that do not appear in the URL.
  38. Keep WordPress plugin nonces in a separate test case.
  39. XML-RPC is the slow, quiet way in. Disable it if unused.
  40. Backup files in the docroot are findings by themselves.
  41. Upload extension checks should run on the normalized name.
  42. Homoglyphs hide inside scope lists and allowlists.
  43. Normalize at the edge, log raw, never filter before decode.
  44. UTF-7 and legacy codecs keep bypassing naive filters.
  45. A fullwidth probe that passes is a bug in the pipeline.
  46. Rotate keys, pin versions, and rotate them again after a patch.
  47. Prototype pollution turns one key into a global change.
  48. __proto__ is the first key to block; check constructor too.
  49. Run npm ls deep; the vulnerable path is rarely the top level.
  50. Refuse constructor.prototype keys at every merge point.
  51. Freeze Object.prototype for the server if you must merge.
---
Share this post:

What do you think?

React to show your appreciation

Related Posts