Security Testing
Beginner 14 min read Security Testing

Security Testing Fundamentals

Security testing hunts for weaknesses an attacker could exploit before they become incidents. Learn the engagement mindset, the testing layers — recon, scanning, verification, reporting — and how to run your first authorized security pass against a sandboxed target.

security testingthreat modelingreconnaissancerules of engagementauthorizationvulnerability
Introduction

What is this?

Security testing systematically looks for weaknesses in an application that an attacker could abuse to steal data, gain access or disrupt service. It spans threat modeling, reconnaissance, vulnerability scanning, manual probing and verification of fixes. The goal is not to prove the app is safe but to discover and prioritize the risks that actually matter.

Motivation

Why do you need it?

  • Security defects are invisible to functional tests — an endpoint can work perfectly and still be exploitable.
  • The cost of a breach — data loss, fines, reputation damage and remediation — is far higher than fixing the flaw before release.
  • Regulations and certifications (GDPR, PCI-DSS, SOC 2) increasingly require documented evidence of security testing.
  • A proactive test tells you what to fix; an incident tells you what you missed, publicly and under pressure.
  • Developers who run security tests learn how the framework they use is actually attacked, which changes how they write code.
Think about it

Mental model

Imagine

A locksmith auditing an office building

Think of

A security tester

The locksmith checks every door, window and alarm for a way in, using the same tools a burglar would — then reports each weakness so the owner can fix it before a real break-in. A tester does the same for an application, with written permission to try.

Mechanics

How it works

  • Scope the engagement: define the target, the written authorization, the rules of engagement and which data is off-limits.
  • Reconnaissance gathers information about the target — endpoints, tech stack, response headers, exposed files.
  • Vulnerability scanning and manual probing identify candidate weaknesses such as misconfigurations, injection points and auth flaws.
  • Exploitation attempts confirm whether a finding is actually exploitable, using safe, non-destructive payloads in a sandbox.
  • Fixes are verified and the results are written up with severity ratings so the team can prioritize remediation.

The phases of a security testing engagement.

Define scope
Reconnaissance
Scan & probe
Verify exploitability
Report & fix
Reference

Key commands

curl -sI https://sandbox.target.local/

Check the target is reachable and inspect the response headers it exposes.

HTTP/1.1 200 OK
curl -s https://sandbox.target.local/robots.txt

Look for endpoints and paths the site itself lists as disallowed.

curl -s -o /dev/null -w "%{http_code}" https://sandbox.target.local/healthz

Confirm the health endpoint responds before you start probing.

200
openssl s_client -connect sandbox.target.local:443 </dev/null 2>/dev/null | openssl x509 -noout -dates

Check the TLS certificate validity window as part of configuration review.

nmap -sV -p 80,443 sandbox.target.local

Educational service fingerprinting — identify what is listening on the target ports before scanning deeper.

curl -s -i https://sandbox.target.local/login

Inspect the login page response for cookies, security headers and error handling.

HTTP/1.1 200 OK\nSet-Cookie: JSESSIONID=...; HttpOnly; Path=/
Hands-on

Examples

Defense first: an object-level authorization check

Defense first: an object-level authorization check
// A recurring finding is "object-level authorization": any logged-in
// user can read a record by guessing an id. The defense is a server-side
// ownership check on every resource, never a frontend check.
const authorizeOwnerOrAdmin = async (req, res, next) => {
const record = await db.records.findById(req.params.id)
if (!record) return res.status(404).json({ error: "not found" })
if (req.user.role !== "admin" && record.ownerId !== req.user.id) {
return res.status(403).json({ error: "forbidden" })
}
req.record = record
next()
}
app.get("/api/records/:id", requireAuth, authorizeOwnerOrAdmin, (req, res) => {
res.json(req.record)
})

Two middleware functions run in order: requireAuth resolves the session token to a user, and authorizeOwnerOrAdmin loads the record and rejects the request unless the caller owns it or is an admin. Because the check runs on the server against the resolved identity — not against a flag the client can forge — it blocks id-guessing attacks even if the frontend only shows a link to the attacker's own records.

Real world

In production

  • Every release candidate gets a security smoke pass — headers, exposed files and a quick auth check — before it reaches production.
  • Threat modeling in design reviews catches authorization and trust-boundary flaws before any code is written.
  • Automated scans run nightly against staging, while manual testing targets critical flows before major releases.
  • Reported findings feed the backlog with a severity label so they compete for priority exactly like any other defect.
Guidelines

Best practices

  • Get written authorization and a signed scope document before testing anything.
  • Start with reconnaissance and mapping before firing heavy tools at the target.
  • Record every command and response with timestamps so findings are reproducible.
  • Verify exploitability in a sandbox; never run destructive payloads against production.
  • Treat a scanner hit as a lead, not a vulnerability — prove it manually before reporting it.
Watch out

Common mistakes

  • Running scans against systems you do not own or have permission to test.
  • Treating scanner output as a finished list of vulnerabilities without manual verification.
  • Testing only the happy path and skipping authorization and error flows.
  • Stopping at 'it works' after a fix instead of confirming the fix actually blocks the original attack.
Root cause analysis

Common issues

Error
curl: (7) Failed to connect to sandbox.target.local port 443
Root cause

The target is unreachable, or the hostname and port are wrong.

Fix

Confirm the host resolves and the service is running; test with curl -v and the correct port.

Error
HTTP 403 on every request, even the login page
Root cause

A WAF or access-control rule is blocking automated traffic.

Fix

Check the rules of engagement for approved tooling and rates, then retry with delays or an allowed user-agent.

Error
nmap: command not found
Root cause

Nmap is not installed on the machine you are using.

Fix

Install it with your package manager, or use the scanner your organization has pre-approved for testing.

When things break

Debugging tips

  • Keep a timestamped request/response log for every test so any finding can be replayed and reproduced.
  • Test a finding on the exact version and configuration it was discovered on before drawing conclusions.
  • Use a sandbox target such as WebGoat or PortSwigger Academy to validate payloads before they touch anything real.
Interviews

Interview checkpoint

Practice

Hands-on lab

WebGoat Recon & Authorization Smoke Test
30 min · beginner
In progress
Objectives
  • Start an authorized sandbox target (OWASP WebGoat) in Docker
  • Map the attack surface with curl reconnaissance
  • Inspect response headers and exposed paths
  • Demonstrate an object-level authorization flaw and its server-side fix

WebGoat Recon & Authorization Smoke Test

30 min · beginner

0/5 steps
0%
sandbox · Linux sandbox
$
Try these commands
Test yourself

Quick quiz

0/3
1

What is the first phase of a security testing engagement?

2

Scanner output alone proves that a vulnerability is exploitable.

3

Which request pattern does the ownership-check middleware block?

Quick reference

Cheat sheet

Engagement essentials
curl -sI <url>Reachability + header review
curl -s <url>/robots.txtFind disallowed paths
curl -w "%{http_code}" <url>Status code only
openssl s_client -connect <host>:443TLS inspection
nmap -sV <host>Service fingerprinting (sandbox only)
curl -i <url>Full response, headers + body
Go deeper

Official documentation