Authentication answers the question "who are you?" Authorization answers "what can you do?" Getting authentication right while getting authorization wrong is one of the most common and damaging patterns in application security. The user is legitimately logged in, their identity is verified, and yet they can access another customer's invoices, modify another user's profile, or promote themselves to admin.
Broken access control has been the number one vulnerability category in the OWASP Top 10 since 2021. It is everywhere because authorization logic is inherently application-specific. There is no generic library that understands your business rules. Every authorization decision is a custom implementation, and every custom implementation is an opportunity for a mistake.
Insecure Direct Object References (IDOR)
IDOR is the most common authorization vulnerability. It occurs when an application exposes internal object references (database IDs, filenames, account numbers) in requests and does not verify that the authenticated user has permission to access the referenced object.
The classic example: GET /api/invoices/12345 returns invoice 12345. Change it to GET /api/invoices/12346 and you see someone else's invoice. The application checks that you are authenticated but never checks that invoice 12346 belongs to you.
IDOR appears in:
- API endpoints with sequential or predictable IDs
- File downloads where the filename is passed as a parameter
- Account management endpoints that accept user IDs
- Reporting endpoints that accept date ranges or account filters
Prevention:
- Validate object ownership on every request, not just on the initial page load
- Use indirect references (UUIDs or hashed IDs) instead of sequential database IDs -- this adds a layer of obscurity but is not sufficient alone
- Implement authorization checks at the data access layer, not just the controller
- Use parameterized queries that include the user's account ID as a filter condition
Horizontal Privilege Escalation
Horizontal privilege escalation occurs when a user accesses resources belonging to another user at the same privilege level. It is essentially IDOR applied broadly. A regular user accesses another regular user's data.
The impact depends on the application. In a healthcare system, it means accessing another patient's medical records. In a financial application, it means viewing another customer's transactions. In a SaaS platform, it means reading another tenant's data.
Common patterns:
- Changing the
tenant_idparameter in multi-tenant applications - Modifying the
user_idin profile or settings endpoints - Accessing shared resources (files, documents, projects) without membership verification
- Exploiting search or listing endpoints that return results across tenants
Prevention:
- Enforce tenant isolation at the database query level
- Use row-level security in your database where supported
- Include the authenticated user's tenant ID in all queries automatically via middleware
- Test every API endpoint with two accounts at the same privilege level
Vertical Privilege Escalation
Vertical privilege escalation occurs when a user gains access to functionality reserved for higher-privileged roles. A regular user accesses admin endpoints. A viewer modifies content. A free-tier user accesses premium features.
This happens when authorization checks are incomplete or inconsistent:
- Admin endpoints are protected by client-side UI hiding but not server-side checks
- Role checks exist on some endpoints but not others in the same feature
- Middleware applies role checks only to certain HTTP methods (GET is checked but POST is not)
- Old API versions lack authorization checks that were added to newer versions
Prevention:
- Implement role-based access control (RBAC) or attribute-based access control (ABAC) at the middleware level
- Define permissions declaratively (in configuration or decorators) rather than imperatively (in business logic)
- Default to deny -- all endpoints require explicit permission grants
- Audit all endpoints to ensure consistent authorization enforcement
Missing Function-Level Access Control
Beyond data access, applications must control access to functions. Creating, modifying, and deleting resources often require different permissions than viewing them. Bulk operations, exports, and administrative functions need additional authorization checks.
A read-only user should not be able to POST to create resources, PUT to modify them, or DELETE to remove them. But applications frequently check authorization only on GET requests and leave mutating operations unprotected.
Prevention:
- Map permissions to HTTP methods explicitly
- Use middleware that enforces method-level authorization
- Test each endpoint with each HTTP method using each role
- Include function-level permissions in your access control matrix
Mass Assignment and Parameter Pollution
Mass assignment occurs when an application automatically binds request parameters to internal object properties. An attacker includes unexpected parameters like role=admin or is_premium=true in a request, and the application blindly assigns them.
Parameter pollution is related: sending the same parameter multiple times with different values to exploit inconsistent parsing between frontend and backend components.
Prevention:
- Use allowlists (not blocklists) for bindable parameters
- Define explicit DTOs (Data Transfer Objects) for each endpoint
- Never bind request parameters directly to database models
- Validate that no unexpected parameters are present in requests
Insecure API Endpoints
Modern applications expose dozens or hundreds of API endpoints. Each one is a potential authorization failure. Common patterns include:
- GraphQL introspection exposing internal types and fields without authorization
- REST API versioning where old versions lack authorization checks
- Internal APIs accidentally exposed through misconfigured reverse proxies
- Webhook endpoints that accept unauthenticated requests
- Health check and debug endpoints that leak sensitive information
Prevention:
- Maintain an inventory of all API endpoints and their required permissions
- Disable GraphQL introspection in production
- Decommission old API versions or ensure they have equivalent authorization
- Segment internal APIs on separate network interfaces
- Authenticate webhook requests using signatures or shared secrets
Authorization in Microservices
Microservice architectures introduce additional authorization complexity. When a request passes through multiple services, each service must make authorization decisions, but not all services have the same context.
Challenges:
- The API gateway validates the JWT, but downstream services trust internal traffic without verification
- Service-to-service communication uses a shared service account with broad permissions
- Authorization context (user role, tenant) is lost as requests propagate between services
- Each service implements its own authorization logic, leading to inconsistencies
Prevention:
- Propagate authorization context (user identity, roles, tenant) through all service calls
- Validate authorization at each service boundary, not just at the edge
- Use service mesh policies to enforce communication patterns
- Implement centralized policy evaluation (Open Policy Agent, for example)
Testing Authorization
Authorization testing requires systematic coverage. For each endpoint, you need to test:
- Unauthenticated access -- Does it require login?
- Cross-user access -- Can user A access user B's resources?
- Cross-role access -- Can a regular user access admin endpoints?
- Cross-tenant access -- Can tenant A access tenant B's data?
- Method-level access -- Does a read-only user fail on POST, PUT, DELETE?
Manual testing with tools like Burp Suite's Autorize extension can automate much of this. For API-heavy applications, building a custom authorization test suite that exercises every endpoint with every role is worth the investment.
Automation tips:
- Build an endpoint inventory from API documentation or route configuration
- Create test accounts for each role in your system
- Script requests to each endpoint with each role and verify response codes
- Include authorization tests in your CI/CD pipeline
How Safeguard.sh Helps
Safeguard.sh helps prevent authorization vulnerabilities by continuously scanning your application's dependency tree for libraries with known access control flaws. When a framework or authentication library has a CVE related to authorization bypass, Safeguard.sh flags it in your SBOM and alerts your team. By providing visibility into the security posture of every component in your stack, Safeguard.sh ensures that authorization weaknesses in third-party code are caught before they compound with your own application logic.