August 8, 2026
The Request Changed. The Security Rule Didn’t.
Exploring HTTP Verb Tampering and Broken Access Control

By Akshit Kakani
5 min read
Imagine finding a heavily guarded door.
There is a security guard. There is a lock. There are cameras.
Everything looks secure.
Then you notice something strange.
The guard only checks people who enter through the front door.
So you try the side entrance.
Nobody stops you.
That is essentially what HTTP Verb Tampering can look like in a web application.
An application may correctly restrict a resource when accessed using GET, but behave differently when the same resource is requested using HEAD, POST, PUT, PATCH, or another HTTP method.
The problem isn't necessarily that the lock is broken.
The problem is that different ways of reaching the same resource may not be protected consistently.
This makes HTTP Verb Tampering an interesting technique for penetration testers, bug bounty hunters, and CTF players.
Note:_ The examples below are intended for CTFs, labs, and systems you are explicitly authorized to test._
First, What Is an HTTP Verb?
Whenever your browser communicates with a web server, it sends an HTTP request.
For example:
GET /profile HTTP/1.1
Host: example.comGET /profile HTTP/1.1
Host: example.comGET is the HTTP method, or verb. It tells the server what kind of operation the client wants to perform.
Some of the most common methods are:
- GET: Retrieve a resource.
- POST: Submit data or create something.
- PUT: Replace or update a resource.
- PATCH: Partially modify a resource.
- DELETE: Delete a resource.
- HEAD: Similar to GET, but returns headers without the response body.
- OPTIONS: Ask what communication methods are supported.
- TRACE: Diagnostic method that can return information about the request path. Usually disabled on modern servers.
- CONNECT: Primarily used to establish a tunnel through a proxy.
For example, an API might use:
GET /api/users/123GET /api/users/123to retrieve a user,
PATCH /api/users/123PATCH /api/users/123to modify one of their attributes, and:
DELETE /api/users/123DELETE /api/users/123to remove them.
The important thing is that the same resource can behave differently depending on the HTTP method.
And that's where things can go wrong.
Where Does Verb Tampering Happen?
Imagine a protected endpoint:
/admin/adminThe developer wants authentication to be required.
The intended rule is:
Any request → /admin → Authentication requiredAny request → /admin → Authentication requiredBut a poorly configured security rule might effectively behave like:
GET /admin → Authentication required
POST /admin → Authentication required
Other methods → Not properly checkedGET /admin → Authentication required
POST /admin → Authentication required
Other methods → Not properly checkedNow an attacker can start experimenting with other methods.
For example:
GET /admin HTTP/1.1GET /admin HTTP/1.1might return:
401 Unauthorized401 UnauthorizedBut:
HEAD /admin HTTP/1.1HEAD /admin HTTP/1.1could unexpectedly return:
200 OK200 OKThat doesn't automatically prove a vulnerability.
It tells us something more important:
The application's authorization behaviour changes depending on the HTTP method.
That deserves further investigation.
Why Can This Happen?
Modern web applications rarely have just one component handling a request.
A simplified architecture might look like:
Client
↓
CDN / WAF
↓
Reverse Proxy
↓
Authentication Layer
↓
Application
↓
DatabaseClient
↓
CDN / WAF
↓
Reverse Proxy
↓
Authentication Layer
↓
Application
↓
DatabaseEach layer may have different rules.
For example, a WAF might enforce:
GET /admin → Block
POST /admin → BlockGET /admin → Block
POST /admin → Blockwhile the application itself understands:
HEAD /admin → Same resource as GETHEAD /admin → Same resource as GETIf the WAF and application don't interpret the request consistently, the security control can be bypassed.
This is one of the most interesting parts of verb tampering.
It isn't always about the HTTP method itself.
It's about different components making different assumptions about the same request.
A Few Interesting Scenarios
Scenario 1: GET vs HEAD
Suppose:
GET /secure/flag.txtGET /secure/flag.txtreturns:
401 Unauthorized401 UnauthorizedYou then test:
HEAD /secure/flag.txtHEAD /secure/flag.txtand receive:
200 OK200 OKBecause HEAD does not return the normal response body, you won't suddenly see the contents of flag.txt.
But the different authorization behaviour is still interesting.
You would investigate whether the underlying resource is actually accessible, whether sensitive information appears in headers, and whether another part of the application treats HEAD differently.
The important lesson:
A changed status code is a clue, not proof of exploitation.
Scenario 2: PUT vs PATCH
Imagine an API protects:
PUT /api/users/123PUT /api/users/123with administrator authorization.
But:
PATCH /api/users/123PATCH /api/users/123is handled by a different route and doesn't perform the same authorization check.
If a normal user can then modify a sensitive attribute such as:
{
"role": "administrator"
}{
"role": "administrator"
}you have a genuine authorization problem.
The vulnerability isn't simply "PATCH is allowed."
The problem is:
Two methods modifying the same resource enforce different authorization policies.
Scenario 3: Method Override
Some frameworks support method override mechanisms.
For example:
POST /api/users/123 HTTP/1.1
X-HTTP-Method-Override: DELETEPOST /api/users/123 HTTP/1.1
X-HTTP-Method-Override: DELETEThe request arrives as POST, but the application may interpret it as DELETE.
This can become dangerous if one security layer sees:
POSTPOSTwhile another interprets:
DELETEDELETEAgain, the underlying issue is inconsistent request handling.
Testing It With cURL
You don't need anything fancy to start testing an authorized lab.
Use:
curl -i -X GET http://lab.example/secure/curl -i -X GET http://lab.example/secure/Then test other relevant methods:
curl -i -X HEAD http://lab.example/secure/
curl -i -X OPTIONS http://lab.example/secure/
curl -i -X POST http://lab.example/secure/
curl -i -X PUT http://lab.example/secure/
curl -i -X PATCH http://lab.example/secure/
curl -i -X DELETE http://lab.example/secure/curl -i -X HEAD http://lab.example/secure/
curl -i -X OPTIONS http://lab.example/secure/
curl -i -X POST http://lab.example/secure/
curl -i -X PUT http://lab.example/secure/
curl -i -X PATCH http://lab.example/secure/
curl -i -X DELETE http://lab.example/secure/You're looking for unexpected differences.
Don't just search for:
200 OK200 OKCompare:
- Status codes
- Response headers
- Response length
- Authentication behaviour
- Error messages
- Redirects
- Application state changes
For example:
GET → 403
POST → 403
PUT → 405
PATCH → 200 ← Investigate
DELETE → 403GET → 403
POST → 403
PUT → 405
PATCH → 200 ← Investigate
DELETE → 403That PATCH response is interesting.
But whether it's actually vulnerable depends on what the application allowed you to do.
Testing With Burp Suite
Burp makes this even easier.
Capture a request such as:
GET /admin HTTP/1.1
Host: lab.example
Cookie: session=...GET /admin HTTP/1.1
Host: lab.example
Cookie: session=...Send it to Repeater.
Then change only the HTTP method:
HEAD /admin HTTP/1.1HEAD /admin HTTP/1.1or:
PATCH /admin HTTP/1.1PATCH /admin HTTP/1.1or:
OPTIONS /admin HTTP/1.1OPTIONS /admin HTTP/1.1Compare the responses.
You can also investigate method-override headers if the application supports them.
The key is to change one thing at a time.
Otherwise, when the application behaves differently, you won't know which change caused it.
How Developers Can Prevent It
The most important principle is simple:
Protect the resource, not just individual HTTP methods.
Instead of thinking:
Protect GET /admin
Protect POST /adminProtect GET /admin
Protect POST /adminthink:
/admin
↓
Authentication
↓
Authorization
↓
Method-specific permission/admin
↓
Authentication
↓
Authorization
↓
Method-specific permissionFor an API, permissions might look like:
ResourceMethodPermission/usersGETuser.read/usersPOSTuser.create/users/123PATCHuser.update/users/123DELETEuser.delete
Also:
- Reject unsupported methods where appropriate.
- Keep authorization consistent across GET, POST, PUT, PATCH, DELETE, etc.
- Review reverse-proxy, WAF, and application behaviour together.
- Understand whether method-override functionality is enabled.
- Don't rely on the HTTP method alone as an authorization control.
The Bigger Lesson
HTTP Verb Tampering looks deceptively simple.
You change:
GETGETto:
HEADHEADand see what happens.
But the real lesson goes much deeper.
Modern applications contain multiple layers, and every layer can make assumptions about a request.
WAF
↓
Proxy
↓
Authentication
↓
Application
↓
APIWAF
↓
Proxy
↓
Authentication
↓
Application
↓
APIIf one layer says:
"This request is harmless."
while another says:
"This request modifies a protected resource."
you have a security problem waiting to happen.
That's why good security testing isn't simply about sending random requests until something returns `200 OK.
It's about finding inconsistencies between what the application thinks you are doing and what you are actually allowed to do.
Sometimes, finding that inconsistency requires changing only one word.
GET /adminGET /adminbecomes:
PATCH /adminPATCH /adminor:
HEAD /adminHEAD /adminAnd suddenly, that heavily guarded door has a side entrance nobody remembered to lock.