Educational Content: This article is written for educational purposes to help developers and cybersecurity students understand software concepts. Always follow ethical guidelines and applicable laws.
Every professional penetration tester, bug bounty hunter, and security researcher I know has Burp Suite open on their laptop right now, or used it within the last 24 hours. It's been around since 2003 and shows no signs of being replaced because it's genuinely the best tool for what it does: letting you see and manipulate every HTTP request your browser sends and every response it receives. Understanding Burp Suite isn't really about learning to attack things — it's about understanding what your web application looks like from the outside, which is a perspective that fundamentally changes how you write backend code.
This post walks through Burp Suite's core components, what attackers use each one for, and what each use case implies about things you should be verifying in your own applications. After reading this, you should have a clear enough picture to download Burp Community Edition and spend a productive afternoon testing your own apps.
What Burp Suite Is and How It Works
At its core, Burp Suite is an intercepting proxy. It runs on your machine, you configure your browser to route traffic through it (127.0.0.1:8080), and from that point every HTTP and HTTPS request your browser sends passes through Burp before reaching the server. You can read it, modify it, block it, or forward it. Every response from the server passes back through Burp before reaching your browser. You can read that too.
For HTTPS to work, Burp generates its own CA certificate and you install it as a trusted root in your browser or system. This is the same mechanism that corporate network proxies use for SSL inspection. Once installed, Burp can decrypt, read, and re-encrypt HTTPS traffic transparently — which is exactly the capability attackers use when traffic interception is part of their methodology.
The Community Edition is free. It includes the Proxy, Repeater, Intruder (with throttling), Decoder, Comparer, Sequencer, and passive scanning. The Professional version adds automated active scanning, more powerful Intruder without throttling, and the BApp Store for extensions. Most of what we're covering here is available in the free version, which tells you something about how accessible web application testing has become.
The Proxy: Reading and Modifying Everything
The Proxy tab is where every session begins. Every request flows through it before reaching the server, visible in full — method, URL, headers, cookies, body — and modifiable before forwarding. The Intercept mode pauses requests for manual review; when disabled, requests flow through while still being logged to the HTTP History.
The HTTP History is particularly useful for security review. Browse through your own application normally — log in, view pages, submit forms, make purchases, change account settings. Every request gets logged. Review the history afterward and you have a complete map of every HTTP interaction the application makes, including requests you might not have thought about consciously.
What this means in practice for developers: any security control implemented in the browser — JavaScript validation, hidden form field values, price or quantity parameters sent in request bodies, role flags in cookies — can be read and modified by anyone running Burp. Consider this checkout example:
POST /checkout HTTP/1.1
Host: shop.example.com
Content-Type: application/x-www-form-urlencoded
item_id=42&quantity=1&price=2999&discount_code=NONE&user_id=1001
An attacker intercepts this in Burp, changes price=2999 to price=1, and forwards it. If the backend recalculates the total from the submitted price rather than looking it up from the database, they've bought something for one cent. This class of vulnerability is extraordinarily common — I've seen it in shopping carts, subscription systems, and API-driven storefronts built in the past year.
<?php
// Wrong: trusting the price from the request
$item_id = (int)$_POST['item_id'];
$quantity = (int)$_POST['quantity'];
$price = (float)$_POST['price']; // never trust this
$total = $price * $quantity;
processPayment($total);
// Correct: always recalculate from the database
$item_id = filter_input(INPUT_POST, 'item_id', FILTER_VALIDATE_INT);
$quantity = filter_input(INPUT_POST, 'quantity', FILTER_VALIDATE_INT);
if (!$item_id || !$quantity || $quantity <= 0 || $quantity > 100) {
http_response_code(400);
exit;
}
$stmt = $db->prepare("SELECT price, stock FROM products WHERE id = ? AND active = 1");
$stmt->execute([$item_id]);
$product = $stmt->fetch();
if (!$product || $product['stock'] < $quantity) {
http_response_code(400);
exit;
}
$total = $product['price'] * $quantity; // calculated server-side, not trusted from client
processPayment($total);
Repeater: Manual Testing and Request Modification
Repeater is the tool that most developers should become familiar with for self-testing. You capture a request in the Proxy, send it to Repeater with a right-click, and can now modify any part of it and resend it as many times as you want. The response appears alongside the request, and you can compare responses from different modifications side by side.
This is how manual SQL injection testing works in practice. A tester takes a request that includes a user-controlled parameter and systematically probes it:
GET /api/product?id=42 HTTP/1.1 → Normal response: product data
GET /api/product?id=42' HTTP/1.1 → SQL error? Different response?
GET /api/product?id=42 OR 1=1 HTTP/1.1 → Returns all products?
GET /api/product?id=42; SLEEP(5)-- HTTP/1.1 → Does the response take 5 seconds?
Each variation tests a different injection hypothesis. A SQL error message confirms the parameter reaches a database query without sanitization. A 5-second delay on SLEEP(5) confirms time-based blind injection. Any response variation compared to the baseline indicates something interesting is happening with that input.
Repeater is also how IDOR (Insecure Direct Object Reference) vulnerabilities get discovered. An authenticated user captures a request for their own resource, then changes the ID:
GET /api/invoice?id=1042 → returns my invoice
GET /api/invoice?id=1043 → returns someone else's invoice?
If the response for id=1043 returns another user's invoice data, the endpoint checks authentication (are you logged in?) but not authorization (is this invoice yours?). This is one of the most common findings in bug bounty programs because it's invisible in normal testing — you only see it when you try accessing resources that aren't yours.
<?php
// Vulnerable: checks authentication, not authorization
$invoice_id = (int)$_GET['id'];
$stmt = $db->prepare("SELECT * FROM invoices WHERE id = ?");
$stmt->execute([$invoice_id]);
$invoice = $stmt->fetch();
if ($invoice) echo json_encode($invoice); // returns any invoice to any authenticated user
// Correct: both authentication AND authorization
$invoice_id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT);
if (!$invoice_id) {
http_response_code(400);
exit;
}
$stmt = $db->prepare("SELECT * FROM invoices WHERE id = ? AND user_id = ?");
$stmt->execute([$invoice_id, $_SESSION['user_id']]);
$invoice = $stmt->fetch();
if (!$invoice) {
http_response_code(404); // not 403 - don't confirm it exists
exit;
}
echo json_encode($invoice);
Intruder: Automated Fuzzing and Brute Force
Intruder takes a captured request, lets you mark specific positions as "payload positions," and fires a list of payloads through those positions automatically, logging each response. It's the tool used for brute force attacks, credential stuffing, parameter fuzzing, and endpoint discovery.
A login form with no rate limiting is trivial to attack with Intruder: mark the password field as the payload position, load a common password list, start the attack. Intruder sends thousands of requests and flags any that return a different response than "invalid credentials" — a redirect, a different response code, a different body length. No sophisticated exploitation needed.
This is precisely why rate limiting on authentication endpoints is non-negotiable. Even a simple threshold — lock out an IP for 60 seconds after 10 failed attempts — makes Intruder effectively useless at any reasonable speed. The Community Edition's built-in throttling (1 request/second) makes brute force slow, but Pro removes that limit, and attackers aren't using the Community Edition.
Intruder is also used for directory and endpoint discovery — fuzzing URL paths against a wordlist:
GET /FUZZ HTTP/1.1 → trying: admin, administrator, dashboard, api, v2, backup...
GET /api/FUZZ HTTP/1.1 → trying: users, orders, payments, admin, internal, debug...
Hidden endpoints found this way are often missing authentication or have weaker authorization than the documented API. "Hidden" and "protected" are not synonyms. Anything reachable via HTTP is discoverable with sufficient fuzzing.
Decoder: Understanding Token and Cookie Formats
The Decoder tab converts between encoding formats — Base64, URL encoding, HTML entities, hex, and more. Simple in concept, significant in practice. A common use: paste a session token or cookie value into Decoder, apply Base64 decode, and read what's inside.
If a session token decodes to something like {"user_id":1001,"role":"user","expires":1743811200}, that application has a catastrophic session design. An attacker changes "role":"user" to "role":"admin", re-encodes it, and replaces their session cookie. If the backend trusts the token value without verifying a signature, they're now an admin.
This isn't hypothetical — it's how several high-profile session vulnerabilities have been exploited. The correct session design is an opaque random token (a cryptographically random string) that maps to session data stored server-side. The token is meaningless on its own and cannot be modified to change what the session contains.
<?php
// Wrong: session data in the token (even "signed" versions of this have issues)
$token = base64_encode(json_encode(['user_id' => $id, 'role' => 'user']));
// Correct: opaque token, all data server-side
session_start();
session_regenerate_id(true); // prevents session fixation
$_SESSION['user_id'] = $user_id;
$_SESSION['role'] = 'user';
// PHP manages the session ID — users never see the underlying data
A Practical Self-Testing Routine
Here's a structured way to use Burp Community Edition to test your own applications before shipping:
1. Map your attack surface. Set up the proxy and browse your entire application — every page, every feature, every form submission. Let Burp capture everything in HTTP History. You now have a complete inventory of every request your application makes.
2. Identify all user-controlled parameters. Review the HTTP history and categorize every parameter your application accepts: GET parameters, POST body fields, cookies, custom headers, JSON body fields. Every one of these is a potential injection point.
3. Test authentication boundaries. For every authenticated request you've captured, try sending it without the session cookie. Try with a corrupted or truncated session cookie. Try accessing resources belonging to a test account while authenticated as a different test account (IDOR testing). Try accessing admin-only pages with a regular user session.
4. Test SQL injection points. Send any request with database parameters to Repeater. Try adding a single quote (') to string parameters. Try 1 AND 1=1 vs 1 AND 1=2 on numeric parameters. Try 1; SLEEP(5) and watch the response time. Any response variation from your baseline requires investigation.
5. Check for reflected output without encoding. Find any parameter whose value appears in the response body. Try putting <script>alert(1)</script> as the value. If it appears unencoded in the response HTML, you have a reflected XSS vulnerability.
6. Review response headers. Look for: missing Content-Security-Policy, missing X-Frame-Options, Server headers revealing software versions, X-Powered-By headers revealing PHP version, verbose error messages in error responses.
The Developer Takeaway
The most important mindset shift that comes from actually running Burp against your own application: every piece of data in an HTTP request is user-supplied and can be modified. It doesn't matter that the value came from a dropdown. It doesn't matter that JavaScript validates the form before submission. It doesn't matter that the parameter is in a cookie. Every value that your server receives and trusts is a value that an attacker can set to anything they want using a proxy.
Backend security means designing your server code to assume that every input value could be adversarial, then validating, type-checking, and authorizing explicitly before using it. Not because you don't trust your users — but because you can't verify that a request actually came from your UI rather than from someone sitting with Burp between their browser and your server.
Download Burp Community. Set up the proxy. Browse through your own app for an afternoon. You'll find at least one thing worth fixing — and more importantly, you'll start seeing your code differently when you're writing it.
— Skand K.