HIGH OWASP API TOP 10

Owasp Api Top 10: Auth Bypass

Authentication Bypass — Threat Profile

Severity
CRITICAL
OWASP API Top 10
API2
MITRE CWE
CWE-287

How OWASP API Top 10 Manifests in Auth Bypass

Auth Bypass vulnerabilities directly map to OWASP API Security Top 10’s API1:2023 Broken Object Level Authorization (BOLA) and API5:2023 Broken Function Level Authorization (BFLA). These flaws occur when API endpoints fail to properly validate user permissions before granting access to resources or functions. Unlike traditional web apps, APIs often expose direct object references (e.g., /api/users/123/profile) or function endpoints (e.g., /api/admin/deleteUser) without contextual authorization checks, making them prime targets for automated scanning.

In practice, Auth Bypass manifests in several specific patterns:

  • IDOR via parameter manipulation: Changing a user ID in a request like GET /api/orders/ORDER_ID to access another user’s order without ownership verification.
  • Privilege escalation through HTTP verb tampering: Sending a PUT or DELETE to an endpoint that only intended GET (e.g., PUT /api/user/42 to modify another user’s profile).
  • Missing role checks on sensitive functions: An endpoint like POST /api/system/reset accessible without validating the caller’s role is admin.
  • Token manipulation: Altering JWT sub or role claims and re-signing with a weak secret or none (alg:none) to impersonate privileged users.
These issues are especially prevalent in microservices architectures where service-to-service communication relies on forwarded tokens without re-validation, or in APIs that assume frontend enforcement is sufficient. Real-world examples include CVE-2020-13942 (Apache DolphinScheduler) where missing authorization on workflow APIs allowed unauthenticated users to execute arbitrary commands, and CVE-2021-22205 (GitLab) where an Auth Bypass in the API allowed issue creation without authentication due to a misconfigured regex constraint.

OWASP API Top 10 emphasizes that authorization must be enforced on the server side for every request, using centralized policies or middleware that checks the authenticated identity against the requested resource and action. Relying on obfuscation, client-side checks, or single-point validation at login is insufficient.

Auth Bypass-Specific Detection

Detecting Auth Bypass requires black-box testing that simulates unauthorized access attempts across user contexts and privilege levels. middleBrick performs this by scanning the unauthenticated attack surface and testing for authorization gaps without credentials. It does not rely on source code or agents; instead, it sends crafted requests to discover if access controls can be circumvented.

Specifically for Auth Bypass, middleBrick executes checks aligned with OWASP API1 and API5:

  • BOLA/IDOR testing: It enumerates predictable identifiers (e.g., numeric IDs, UUIDs) in parameters and paths, attempting to access resources belonging to other users. For example, if GET /api/invoices/1001 returns data for user A, it tries 1002, 1003 to see if user B’s invoice is exposed.
  • BFLA/Privilege Escalation testing: It probes HTTP methods on endpoints (e.g., sending DELETE to a read-only endpoint) and tests access to administrative paths like /api/admin/ or /api/system/ without authentication.
  • Property Authorization testing: It checks if sensitive fields (e.g., isAdmin, salary) can be modified via PATCH or POST when they should be read-only or restricted.
  • LLM/AI Security probing: For AI endpoints, it tests if prompt injection can bypass role-based restrictions in agentic systems (e.g., forcing a tool call to delete data despite user role).
Each test is performed unauthenticated, meaning middleBrick does not log in first—it evaluates what an attacker could achieve from the outside. Findings include the exact request that bypassed authorization, the sensitive data or function exposed, and severity based on impact (e.g., data exposure vs. remote code execution). For instance, if a scanner discovers that GET /api/user/me?role=admin returns elevated privileges without validation, it flags this as a high-severity BFLA finding with remediation guidance to enforce server-side role checks.

This approach mirrors real attacker behavior: no credentials needed, no internal access, just probing the exposed API surface. It complements white-box testing by catching misconfigurations that code reviews might miss, such as deprecated endpoints still active or incorrect middleware ordering.

Auth Bypass-Specific Remediation

Fixing Auth Bypass requires implementing proper authorization checks at the point of access, not relying on network-level controls or authentication alone. The fix must verify that the authenticated user (or service) has permission to perform the requested action on the specific resource, using the API’s native frameworks and libraries.

Below are language-specific, syntactically correct examples demonstrating server-side authorization enforcement:

Language/FrameworkVulnerable CodeFixed Code
Node.js (Express)
app.get('/api/users/:id/orders', (req, res) => {
  const userId = req.params.id;
  // Missing: check if req.auth.userId === userId or user has role
  db.query('SELECT * FROM orders WHERE user_id = ?', [userId], (err, results) => {
    res.json(results);
  });
});
app.get('/api/users/:id/orders', (req, res) => {
  const requestedUserId = parseInt(req.params.id, 10);
  const authUserId = req.auth?.userId;
  const authUserRole = req.auth?.role;

  // Authorization: user can only access their own orders unless admin
  if (authUserId !== requestedUserId && authUserRole !== 'admin') {
    return res.status(403).json({ error: 'Forbidden' });
  }

  db.query('SELECT * FROM orders WHERE user_id = ?', [requestedUserId], (err, results) => {
    if (err) return res.status(500).json({ error: 'Database error' });
    res.json(results);
  });
});
Python (Flask)
@app.route('/api/admin/users', methods=['DELETE'])
def delete_user():
  user_id = request.args.get('id')
  # Missing: verify caller is admin
  db.execute('DELETE FROM users WHERE id = ?', (user_id,))
  return '', 204
@app.route('/api/admin/users', methods=['DELETE'])
def delete_user():
  auth_user = get_current_user()  # From token/session
  if not auth_user or auth_user.role != 'admin':
    return jsonify({'error': 'Forbidden'}), 403

  user_id = request.args.get('id')
  if not user_id:
    return jsonify({'error': 'Missing user ID'}), 400

  db.execute('DELETE FROM users WHERE id = ?', (user_id,))
  return '', 204
Java (Spring Boot)
@DeleteMapping("/api/documents/{id}")
public ResponseEntity deleteDocument(@PathVariable String id) {
  // Missing: check ownership or role
  documentRepository.deleteById(id);
  return ResponseEntity.noContent().build();
}
@DeleteMapping("/api/documents/{id}")
@PreAuthorize("#authentication.principal.id == #document.ownerId or hasRole('ADMIN')")
public ResponseEntity deleteDocument(@PathVariable String id, @AuthenticationPrincipal UserDetails userDetails) {
  Document document = documentRepository.findById(id)
    .orElseThrow(() -> new ResourceNotFoundException('Document not found'));

  // Additional check: ensure user owns document unless admin
  if (!document.getOwnerId().equals(userDetails.getId()) && 
      !userDetails.getAuthorities().contains(new SimpleGrantedAuthority('ROLE_ADMIN'))) {
    return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
  }

  documentRepository.deleteById(id);
  return ResponseEntity.noContent().build();
}
Go (Gin)
r.GET("/api/profile/:userID", func(c *gin.Context) {
  userID := c.Param("userID")
  // Missing: verify token subject matches userID
  var profile Profile
  db.Where("user_id = ?", userID).First(&profile)
  c.JSON(http.StatusOK, profile)
})
r.GET("/api/profile/:userID", func(c *gin.Context) {
  requestedID := c.Param("userID")
  authUserID, exists := c.Get("user_id")  // From middleware
  if !exists {
    c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
    return
  }

  // Authorization: user can only view own profile
  if authUserID.(string) != requestedID {
    c.JSON(http.StatusForbidden, gin.H{"error": "Forbidden"})
    return
  }

  var profile Profile
  if err := db.Where("user_id = ?", requestedID).First(&profile).Error; err != nil {
    c.JSON(http.StatusNotFound, gin.H{"error": "Not found"})
    return
  }
  c.JSON(http.StatusOK, profile)
})

Key remediation principles:

  • Always perform authorization checks server-side after authentication.
  • Use role-based access control (RBAC) or attribute-based access control (ABAC) for fine-grained policies.
  • Leverage framework features: Spring’s @PreAuthorize, Express middleware, Flask decorators, or Gin middleware.
  • Never trust client-provided roles or IDs; validate against the authenticated session or token.
  • For APIs serving multiple clients (web, mobile, third-party), enforce authorization at the API gateway or service layer consistently.
These fixes ensure that even if an attacker guesses or manipulates identifiers, they cannot access unauthorized resources or functions without proper permissions.

Frequently Asked Questions

How does middleBrick differentiate between an authentication failure and an authorization bypass?
middleBrick treats these as distinct issues. Authentication failures (e.g., missing/invalid token) are checked separately under its Authentication scan. Auth Bypass is identified only when a request with valid (or no) credentials accesses a resource or function it should not be permitted to use—such as accessing another user’s data via parameter tampering or invoking an admin endpoint without the required role. The scanner confirms access was granted despite lacking authorization, not due to missing authentication.
Can fixing Auth Bypass break legitimate API functionality if not implemented carefully?
Yes, overly restrictive authorization can block valid use cases. For example, a healthcare API might need to allow a nurse to view a patient’s record only if they are assigned to that patient’s care team—not just based on role. Remediation should align with business logic: use contextual checks (e.g., verifying a doctor-patient relationship in the database) alongside role checks. Test fixes with both positive (authorized) and negative (unauthorized) scenarios to ensure legitimate access remains intact while blocking bypass attempts.