Get Hacker Buddy

The web application flaws attackers try first

Hacker's handbook • 3 min read

Once an attacker has found your site, they test the application itself. They don't read your code. They send unusual input to every form, parameter, and API endpoint and watch how the site responds. A handful of flaws account for most of what they find, and each one has a well-understood fix.


Injection

Injection happens when input from a visitor ends up being run as part of a command. The classic case is a database query built by gluing text together:

// vulnerable: the id becomes part of the query
db.query("SELECT * FROM users WHERE id = " + req.query.id);

// fixed: the id is passed separately as data
db.query("SELECT * FROM users WHERE id = ?", [req.query.id]);

An attacker tests for it by adding a quote mark or a short piece of query syntax to a parameter and looking for an error or a change in the response. The fix is to use parameterised queries everywhere, so input is always treated as data.


Cross-site scripting

Cross-site scripting, or XSS, is injection into a web page. If your site displays something a visitor typed without escaping it, an attacker can make it display a script, which then runs in other visitors' browsers with their login.

  • How it's tested: a harmless marker such as <script> is submitted to search boxes, profile fields, and URL parameters to see whether it comes back unescaped.
  • How it's fixed: escape output by default, which most modern template systems and frameworks do unless you turn it off. Avoid functions that insert raw HTML.
  • The safety net: a Content-Security-Policy limits what an injected script can do.

Broken access control

This is the most common serious flaw, and the simplest: the server never checks whether this user is allowed to see this record. If your invoice is at /invoices/1042, an attacker asks for /invoices/1041.

  • How it's tested: changing IDs in addresses and API requests, calling admin endpoints as an ordinary user, and repeating requests after signing out.
  • How it's fixed: check permission on the server for every request, against the record being requested. Hiding a button or a link in the interface protects nothing.
  • Watch your API: endpoints used by your own front end are public, whether or not they're documented.

Server-side request forgery

If your application fetches a URL that a visitor supplies, for example to import an image or preview a link, an attacker can supply an internal address instead. Your server then makes the request from inside your network, where it can reach things the internet can't, including the cloud metadata service that hands out credentials.

  • How it's fixed: allow only the hosts you expect, block private and internal address ranges after resolving the name, and don't follow redirects blindly.

Unsafe file uploads

  • The risk: an uploaded file that the server later runs as code, or serves to other visitors as a web page.
  • The fix: check the type by content rather than by name, store uploads outside the web root or on a separate domain, generate your own file names, and limit the size.

Errors that say too much

Attackers learn from your error messages. A stack trace reveals the framework, file paths, and sometimes the query that failed, which tells them exactly which attack to try next. Show visitors a plain message and keep the detail in your logs.


Why testing the live site matters

These flaws live in code, but they're found from the outside, by sending requests to the running site. That's also the only place where everything comes together: your code, its settings, the server in front of it, and the data behind it. A flaw that was fixed in the code but never deployed is still open, and only a test against the live site will tell you so.


Conclusion

Treat every input as hostile, check permission on the server for every request, and say as little as possible when something fails. Then test the live site the way an attacker would, because that's the version that counts.


Up next