JustAppSec

Thinking Like an Attacker

Switching perspectives — how attackers find weaknesses and what that means for your code.

0:00

Developers build features. Attackers break assumptions. The difference is not skill — it is perspective. This lesson teaches you to look at your own code the way an attacker would, so you can find weaknesses before they do.

The attacker's mindset

Attackers do not read your code top to bottom. They ask questions:

  1. Where does data enter the system? Every input is a potential attack surface.
  2. What assumptions does the code make? Every assumption is a potential bypass.
  3. Where are the trust boundaries? Every boundary is a potential escalation point.
  4. What happens when things go wrong? Error handling often reveals or enables vulnerabilities.
  5. What was forgotten? The endpoint nobody remembers, the admin tool with no auth.

Thinking in attack graphs

A defender thinks: "The user logs in, views their dashboard, updates their profile."

An attacker thinks: "What if I skip the login? What if I view someone else's dashboard? What if I update someone else's profile? What if I update fields that should not be updatable?"

Every feature has a happy path and dozens of unhappy paths. Attackers explore the unhappy paths.

Common attacker patterns

Reconnaissance

Before attacking, gather information:

TechniqueWhat it reveals
View page source, JavaScript filesAPI endpoints, internal paths, framework version
Check /robots.txt, /sitemap.xmlHidden pages, admin panels
Read error messagesStack traces, database type, internal IPs
Check HTTP headersServer software, framework, security headers present/missing
Browse the API docsAll endpoints including ones the UI does not use
Search GitHub for the company nameLeaked credentials, internal documentation, old code
DNS enumerationSubdomains, staging environments, internal tools

What this means for you: Assume attackers know your tech stack, your API surface, and your endpoint structure. Security through obscurity does not work.

Parameter manipulation

Attackers modify every parameter they can see:

# Normal request
GET /api/orders/12345
Authorization: Bearer <user_token>

# Attacker tries another user's order
GET /api/orders/12346
Authorization: Bearer <user_token>

# Attacker tries admin endpoint
GET /api/admin/orders
Authorization: Bearer <user_token>

# Attacker manipulates query parameters
GET /api/orders?userId=admin&status=all
Authorization: Bearer <user_token>

What this means for you: Authorise every request based on the authenticated user's permissions, not just whether a valid token is present. Never trust client-supplied IDs without ownership checks.

Privilege escalation

Attackers look for ways to gain more access than they should have:

TypeExample
VerticalRegular user gains admin access
HorizontalUser A accesses User B's data
ContextFree-tier user accesses premium features

Common escalation vectors:

  • Changing a role parameter in a request body
  • Modifying a JWT payload (if the signature is not verified)
  • Accessing admin API endpoints directly (they rely on UI hiding instead of server-side checks)
  • Exploiting race conditions during permission checks

Chaining vulnerabilities

Individual low-severity issues combine into critical exploits:

Low: Username enumeration on login (different error for "user not found" vs "wrong password")
  +
Low: No rate limiting on password reset
  +
Medium: Password reset token is predictable (timestamp-based)
  =
Critical: Account takeover of any user

Attackers chain findings. A "low" severity issue is only low in isolation.

Attack surface mapping

Identify all entry points

For every application, enumerate:

Network entry points:

  • Public web endpoints
  • API endpoints (REST, GraphQL, gRPC, WebSocket)
  • Admin panels
  • Health check / monitoring endpoints
  • Webhook receivers
  • File upload endpoints

Data entry points:

  • Form fields
  • URL parameters and path segments
  • HTTP headers (Host, Referer, X-Forwarded-For)
  • Cookies
  • File uploads (name, content, MIME type)
  • API request bodies

Indirect entry points:

  • Email content processed by the application
  • Data imported from third-party integrations
  • Messages from queues or event streams
  • DNS records (for applications that process them)
  • CI/CD pipeline inputs (PR titles, branch names, commit messages)

Prioritise by risk

Not all entry points are equal. Focus on:

  1. Unauthenticated endpoints — accessible to anyone on the internet
  2. Endpoints that process untrusted input — file uploads, search, user-generated content
  3. Endpoints that access sensitive data — PII, financial data, credentials
  4. Endpoints with elevated privileges — admin functions, user management
  5. Forgotten or deprecated endpoints — old API versions, debug endpoints

Assumption hunting

Every vulnerability is a broken assumption. Train yourself to spot them:

AssumptionReality
"Users will only submit the form fields we show them"Attackers craft arbitrary HTTP requests
"The client-side validation prevents bad input"Client-side validation is trivially bypassed
"Only admins can access /admin routes"Unless the server checks, anyone can try
"The user ID comes from the session, so it's trusted"Unless the endpoint also accepts a userId parameter in the body
"Nobody will guess that URL"Predictable IDs, directory brute-forcing
"We don't process XML, so XXE doesn't apply"A library dependency might parse XML internally
"The file upload only accepts images"MIME type and extension checks are easily faked
"Rate limiting prevents brute force"Distributed attacks from thousands of IPs

Exercise: Question your current project

For every feature you are building or have built, ask:

  1. What input does this accept? Can I send unexpected values?
  2. Who should have access? Is that enforced on the server?
  3. What happens if I send this request twice? A hundred times? A million times?
  4. What happens if I modify the ID, the role, the amount, the email?
  5. What happens if I skip step 2 and go directly to step 3?
  6. What data does the error message reveal?

The STRIDE model for developers

STRIDE is a threat classification that maps well to attacker thinking:

ThreatQuestion to ask
SpoofingCan I pretend to be someone else?
TamperingCan I modify data I should not be able to?
RepudiationCan I do something and deny it happened?
Information disclosureCan I access data I should not see?
Denial of serviceCan I make the system unavailable?
Elevation of privilegeCan I gain access beyond my authorisation?

For every endpoint, walk through each letter. If the answer to any question is "maybe," you have found something to investigate.

Practical exercises

1. Browser DevTools exploration

Open your application in Chrome DevTools:

  • Network tab: Watch every request. Note endpoints, parameters, headers, response data.
  • Application tab: Check cookies, localStorage, sessionStorage for tokens and sensitive data.
  • Console: Look for JavaScript errors that reveal internal details.
  • Sources: Read client-side JavaScript for hardcoded secrets, API keys, internal endpoints.

2. Intercept and modify requests

Use your browser's DevTools or a proxy (Burp Suite, OWASP ZAP) to:

  1. Capture a normal request
  2. Change the user ID to another user's ID
  3. Change the role from "user" to "admin"
  4. Remove the authorisation header entirely
  5. Add unexpected fields to the JSON body

Observe what the server accepts and rejects.

3. Map your own application

Draw a diagram of your application's entry points. For each one, list:

  • Authentication required? (Yes / No)
  • Authorisation checked? (Role, ownership, none)
  • Input validated? (Schema, type, range)
  • Sensitive data in response? (PII, credentials, internal details)

The gaps in this diagram are where attackers will look first.

From attacker thinking to secure coding

The goal is not to become an attacker. It is to develop an intuition for where things break:

  • When writing a new endpoint, ask "What would I try if I wanted to abuse this?"
  • When reviewing a pull request, look for missing authorisation checks, not just code style
  • When designing a feature, consider the unhappy paths, not just the happy path
  • When something feels "probably fine," that is exactly where vulnerabilities hide

Summary

Attackers think in entry points, assumptions, and chains. They enumerate everything, manipulate every parameter, and escalate from low-value to high-value access. To defend effectively, apply the same thinking to your own code: map your attack surface, hunt for broken assumptions, and walk through STRIDE for every endpoint. The best time to think like an attacker is while you are still writing the code.


This training content is AI-assisted and reviewed by our team, but issues may be missed and best practices evolve rapidly. Send corrections to [email protected].