How I Exploited 3 Broken Access Control Bugs by Removing One Simple Header + Video

Listen to this Post

Featured Image

Introduction:

A recent bug bounty discovery by Khaled Zeyad highlights a critical and often overlooked vulnerability class: Broken Access Control (BAC), specifically Privilege Escalation. While many applications focus heavily on robust authentication (verifying who you are), they frequently fail at authorization (verifying what you are allowed to do). This case study reveals how a simple oversight in validating a backend header (HMAC) versus a session cookie led to a complete bypass of role-based permissions.

Learning Objectives:

  • Understand the critical difference between authentication and authorization in web applications.
  • Learn a systematic, layer-by-layer approach to testing for Privilege Escalation vulnerabilities.
  • Identify how improper validation of multiple security mechanisms (e.g., Cookies and HMAC headers) can lead to BAC.

You Should Know:

  1. The Discovery: Testing Privileged Requests with Layered Security
    The core of this finding lies in an application that used two separate security mechanisms to authorize a privileged admin request: a session `Cookie` (identifying the user) and an `HMAC` header (likely for request integrity or secondary authorization). The initial tests by the researcher followed a logical path of trying to authenticate as one role and authorize as another, which correctly resulted in `401 Unauthorized` errors. This indicated the server was validating both pieces of information against each other.

However, the breakthrough came with “Try 5.” By sending a request with a low-privilege (Viewer) `Cookie` but completely removing the `HMAC` header, the server returned a 200 OK. This suggests a fallback or logic flaw where the presence of the `Cookie` was sufficient for identification, and the absence of the `HMAC` header caused the server to skip the secondary authorization check, defaulting to the privileges of the user in the cookie. This is a classic example of “failing open” and a flawed assumption in the security logic.

  1. Simulating the Attack: A Step-by-Step Guide with cURL
    To understand how this exploit works, we can simulate the logic using command-line tools like cURL. Assume an internal API endpoint, /admin/enterprise/settings, which requires both a valid session and a specific HMAC header for server-to-server or privileged validation.

Prerequisite: You have captured a valid `Cookie` for a low-privilege “Viewer” user and a valid `Cookie` for an “Admin” user. You also know that a successful admin request requires an `X-HMAC-Signature:

` header.

<h2 style="color: yellow;">Step 1: Establish the Baseline (Attempt 1-4)</h2>

These commands simulate the failed attempts, showing the server correctly validating both mechanisms.
[bash]
 Attempt 1: Viewer Cookie + Admin HMAC (Mismatch) -> Expect 401
curl -X GET https://api.target.com/admin/enterprise/settings \
-H "Cookie: session=VIEWER_SESSION_ID" \
-H "X-HMAC-Signature: ADMIN_HMAC_HASH" \
-I

Attempt 2: Admin Cookie + Viewer HMAC (Mismatch) -> Expect 401
curl -X GET https://api.target.com/admin/enterprise/settings \
-H "Cookie: session=ADMIN_SESSION_ID" \
-H "X-HMAC-Signature: VIEWER_HMAC_HASH" \
-I

Attempt 3: Viewer Cookie + Viewer HMAC (Valid for Viewer, but not Admin) -> Expect 401
curl -X GET https://api.target.com/admin/enterprise/settings \
-H "Cookie: session=VIEWER_SESSION_ID" \
-H "X-HMAC-Signature: VIEWER_HMAC_HASH" \
-I

Attempt 4: No Cookie + Viewer HMAC (No Session) -> Expect 401
curl -X GET https://api.target.com/admin/enterprise/settings \
-H "X-HMAC-Signature: VIEWER_HMAC_HASH" \
-I

Step 2: The Privilege Escalation (Attempt 5)

This is the exploit. We send the low-privilege session cookie but omit the HMAC header entirely.

 Attempt 5: Viewer Cookie + NO HMAC Header -> Expect 200 OK
curl -X GET https://api.target.com/admin/enterprise/settings \
-H "Cookie: session=VIEWER_SESSION_ID" \
-v

If successful, the response will contain data intended only for administrators, proving that the backend failed to enforce role-based permissions when one of the security layers was removed. The server likely checked for the HMAC, didn’t find it, and simply defaulted to the permissions granted by the session cookie, which in this case was a user with enterprise-level access but viewer-level permissions.

3. Manual Exploitation with Browser DevTools

You can also attempt this manually to understand the client-side impact:
1. Log in to the target application with a low-privilege user (Viewer).
2. Open Developer Tools (F12) and go to the Network tab.
3. Perform an action that you know requires admin privileges.
4. Find the corresponding network request, right-click it, and select “Edit and Resend.”
5. In the request headers, find the `HMAC` or similar custom security header (e.g., X-Signature, Authorization: HMAC ...).

6. Delete the entire header line.

  1. Click “Send” and observe the response. If you get a successful response (200 OK) with data you shouldn’t see, you’ve found the vulnerability.

4. Code Review: Identifying the Flawed Logic

The vulnerability likely originates in backend middleware or controller logic similar to this pseudo-code example:

Vulnerable Code (Conceptual – Python/Flask):

@app.route('/admin/enterprise/settings')
@login_required  Ensures user is logged in via cookie
def admin_settings():
user = get_current_user_from_cookie(request.cookies)

Flawed Logic: Check HMAC only if it exists
if 'X-HMAC-Signature' in request.headers:
if not validate_hmac(request.headers['X-HMAC-Signature'], user):
return abort(401)  Unauthorized if HMAC is wrong
else:
 HMAC is present and valid, proceed with admin check
if user.role == 'Admin':
return admin_data()
else:
return abort(403)  Forbidden
else:
 VULNERABILITY: HMAC is missing, so we skip the check entirely!
 The code incorrectly assumes that if there's no HMAC, it's not an admin request,
 but it still returns data based on the user's cookie privileges.
 If the user has enterprise-level access (even as a viewer), this might return data.
return admin_data()  < THIS IS THE BUG

The correct logic would be to deny any request to an admin endpoint that lacks the required secondary authentication, regardless of the user’s role in the session cookie.

5. Mitigation: Enforcing Proper Authorization

To fix this, the server must validate all security layers for privileged actions. The “remove and observe” technique used by the researcher is a powerful testament to why defense in depth must be consistent.

Secure Code (Conceptual – Python/Flask):

@app.route('/admin/enterprise/settings')
@login_required
def admin_settings():
user = get_current_user_from_cookie(request.cookies)

Mandatory: HMAC header MUST be present AND valid
if 'X-HMAC-Signature' not in request.headers:
return abort(401)  Unauthorized - Missing required security layer

if not validate_hmac(request.headers['X-HMAC-Signature'], user):
return abort(401)  Unauthorized - Invalid HMAC

Now, and only now, check role-based permissions
if user.role != 'Admin':
return abort(403)  Forbidden - User is not an admin

return admin_data()

6. Beyond the Bug: Implications for API Security

This specific instance highlights a broader issue in API security, particularly in microservices architectures. The `HMAC` header likely served as a form of inter-service authentication or a secondary token. By removing it, the researcher essentially downgraded the request from a highly privileged, server-validated request to a standard user request, but the backend API (the “Wallet” service, in this context) failed to re-validate the user’s permissions against the action. This is a direct violation of the “never trust the client” principle and underscores the need for every service to perform its own authorization checks, regardless of how the request is routed.

What Undercode Say:

  • Key Takeaway 1: Never assume that the absence of a security header makes a request less privileged. In broken implementations, it can actually increase privileges by bypassing secondary checks. Always test by systematically removing headers.
  • Key Takeaway 2: Authentication is not authorization. A valid session cookie only proves identity. The application must explicitly verify that the identified user has the permission to perform the requested action on the specific resource, every single time, regardless of other headers present.

This discovery is a perfect example of how creative thinking in bug hunting—specifically, the “what if I remove this?” approach—can uncover critical flaws that automated scanners would miss. It reinforces that while developers focus on building layers of security, testers must focus on finding the cracks between those layers. The fix is straightforward: mandate all security controls for privileged endpoints and never fail open.

Prediction:

As applications continue to adopt microservices and serverless architectures, we will see a rise in these “layer confusion” vulnerabilities. The complexity of managing authentication contexts (cookies, JWTs, API keys, HMACs) across multiple services will lead to more logic flaws where one service trusts another implicitly. The future of exploitation will move away from brute-forcing credentials and toward confusing the trust relationships and state between these distributed components.

▶️ Related Video (82% Match):

🎯Let’s Practice For Free:

IT/Security Reporter URL:

Reported By: Khaled Zeyad – Hackers Feeds
Extra Hub: Undercode MoN
Basic Verification: Pass ✅

🔐JOIN OUR CYBER WORLD [ CVE News • HackMonitor • UndercodeNews ]

💬 Whatsapp | 💬 Telegram

📢 Follow UndercodeTesting & Stay Tuned:

𝕏 formerly Twitter 🐦 | @ Threads | 🔗 Linkedin | 🦋BlueSky