Authentication tells an application who is making a request. It does not automatically determine what that user is allowed to do.

Imagine an order management application where customers can cancel their own orders. A customer is authenticated, opens an order, and requests its cancellation. The application verifies the session and processes the request.

Now imagine that the same customer can change the order identifier and cancel an order belonging to someone else.

The user is authenticated. The order exists. The cancellation operation is valid for that order's current status. Yet the application performs an action the user has no authority to perform.

This is the core of Broken Object Level Authorization (BOLA), commonly associated with Insecure Direct Object Reference (IDOR). The application identifies the requested object but fails to enforce whether the current actor is authorized to access or modify it.

In this breakdown, we reproduce the issue in a controlled AgenticEnclave lab, examine the root cause, and compare the vulnerable behavior with an implementation that enforces authorization before changing the order.

An object identifier tells the application what to operate on. It does not grant permission to operate on it.

The Scenario

The lab contains an order cancellation workflow with two implementation modes: vulnerable and hardened. An authenticated user can inspect orders and interact with an Orders Agent.

Each order has an identifier and an owner. The security boundary is straightforward: a customer may cancel an eligible order they own, but must not be able to cancel another customer's order.

The application must enforce that boundary even when a request is initiated through an agent-enabled workflow. An agent's involvement does not remove the need for authorization checks in the underlying application.

AgenticEnclave SEC-01 lab showing the authenticated user and orders with their owner identifiers
The lab context: the authenticated user's identity and the owner identifiers associated with the available orders.

The important detail is the relationship between the authenticated user and the order owner. A valid session alone is not enough to authorize a cancellation.

How the Vulnerability Works

The vulnerable implementation allows the cancellation operation to proceed without adequately verifying that the authenticated actor is authorized to cancel the requested order.

At a high level, the attack follows this sequence:

Authenticated user
        |
        v
Select an order
        |
        v
Request cancellation
        |
        v
Application identifies the order
        |
        v
Ownership authorization is not enforced
        |
        v
Another customer's order is cancelled

The problem is not that the attacker bypasses authentication. The attacker operates within an authenticated session. The authorization decision for the requested object is what fails.

This distinction matters because an application can have functioning login, session management, and role checks while still exposing individual objects to unauthorized operations.

The vulnerable implementation

The following code checks whether the order belongs to the current lab and whether it exists. However, it does not verify whether the authenticated actor is authorized to cancel that particular order.

VulnerableCancelOrderUseCase code showing lab isolation checks but no authorization check against the order owner
The vulnerable use case verifies lab isolation and order existence, but does not check whether the authenticated actor is authorized to cancel the order.

Reproducing the vulnerable behavior

In the controlled SEC-01 lab, the vulnerable mode allows an authenticated user to trigger cancellation of an order owned by another user.

The reproduction uses the lab's own orders and test identities. It demonstrates the authorization failure without targeting an external application or a real customer's data.

AgenticEnclave vulnerable mode showing an order owned by another user being cancelled
Vulnerable mode: the cancellation succeeds even though the authenticated user does not own the order.

The evidence is the mismatch between the authenticated user's identity and the order's owner, combined with the successful state change.

The operation should have been rejected before the order was modified. Instead, the application allows the request to cross an authorization boundary.

Root Cause: Missing Object-Level Authorization

The root cause is a missing or insufficient authorization check tied to the specific object being modified.

Checking whether a user is logged in answers one question: Who is making this request?

It does not answer the next question: Is this actor allowed to cancel this particular order?

An object identifier, whether sequential, random, or otherwise difficult to guess, must not be treated as an authorization mechanism. Making identifiers harder to enumerate may reduce one avenue of discovery, but it does not replace server-side access control.

The same principle applies when an operation is initiated by an AI agent. The application must not assume that an action is authorized simply because it came through an agent, a trusted service, or a valid conversation.

The authorization decision must account for the actor, the requested permission, and the resource on which the action will be performed.

Hardening the Cancellation Workflow

The hardened implementation checks authorization before cancelling or saving the order. It retrieves the requested order, verifies that the order exists, evaluates the actor's permission against the order owner, and only then performs the state change.

The relevant authorization decision is made in the CancelOrderUseCase, using an explicit AuthorizationPolicy.

CancelOrderUseCase code checking the actor's CANCEL_ORDER permission against the order owner before cancellation
The authorization policy receives the actor, the CANCEL_ORDER permission, and the order owner's identifier. The order is cancelled only after authorization succeeds.

The critical part of the implementation is the ownership information passed into the policy:

if not self._authorization_policy.is_allowed(
    actor=actor,
    permission=Permission.CANCEL_ORDER,
    resource_owner_id=order.customer_id,
):
    raise AuthorizationDenied(
        f"Actor {actor.user_id} is not authorized to cancel "
        f"order {order.id}."
    )

order.cancel()
self._order_repository.save(order)

The policy evaluates whether the actor has permission to perform the requested operation on a resource owned by the specified customer. If authorization fails, the use case raises AuthorizationDenied.

Crucially, the authorization check occurs before order.cancel() and before the repository saves the changed order.

This keeps the security decision inside the application operation itself rather than relying exclusively on the user interface or on the caller to behave correctly.

What happens when authorization fails?

The API rejects the unauthorized operation with HTTP 403 Forbidden. The order remains pending because the cancellation has not been performed.

The important behavior is not simply returning an error. The application must prevent the unauthorized state change.

Verifying the Fix

A hardening change should be demonstrated against the same unauthorized action that exposed the vulnerability. Comparing the vulnerable and hardened implementations makes the security property observable.

AgenticEnclave hardened mode rejecting an unauthorized order cancellation with HTTP 403 while the order remains pending
Hardened mode: the unauthorized cancellation is rejected with HTTP 403, and the order remains pending.

The comparison establishes three important observations:

  • In vulnerable mode, an authenticated user can cancel an order owned by another user.
  • In hardened mode, the same unauthorized operation is rejected with HTTP 403.
  • The order remains pending after the rejected operation.

The implementation also has unit tests covering the relevant behavior:

  • An order owner can cancel their own order.
  • A user cannot cancel an order owned by another user, and the order remains pending.
  • An agent without cancellation permission cannot cancel an order.
  • A missing order raises an entity-not-found error.
  • A shipped order cannot be cancelled.

These checks cover both authorization and business rules. The application must reject unauthorized actors while still allowing permitted operations and enforcing the order's valid state transitions.

What Can Go Wrong?

Broken object-level authorization can turn an otherwise legitimate application operation into a way to manipulate another user's data.

Depending on the operation and the application's business context, the consequences can include:

  • Unauthorized cancellation or modification of orders.
  • Disruption of customer transactions and business workflows.
  • Financial or operational losses.
  • Unauthorized access to information associated with other customers' records.
  • Loss of customer trust and potential compliance consequences.

These are potential consequences of the vulnerability class, not claims that every impact was demonstrated in this lab. The reproduction specifically demonstrates unauthorized order cancellation.

In an AI-enabled application, the same underlying weakness can become relevant when an agent is able to invoke operations against application resources. An agent may make an incorrect decision, interpret a request improperly, or be manipulated into attempting an action. Regardless of how the request originates, the application must enforce authorization.

Engineering Lessons

Authentication and authorization solve different problems

A valid identity does not grant unrestricted access to every object. Authorization must be evaluated for the requested action and resource.

Enforce access control where the operation is executed

Hiding buttons, filtering the user interface, or relying on the caller to supply a permitted identifier does not protect the underlying operation. The application must enforce the decision on the server side.

Treat agents as callers, not as authorization authorities

An AI agent can help interpret a request and select an operation. It should not replace the application's authorization policy. The operation must evaluate whether the actor is permitted to affect the target resource.

Verify the state, not just the response

An error response alone is insufficient evidence that the operation was safely rejected. Verification should also establish that the protected resource was not modified.

Keep authorization separate from business rules

Ownership and permission checks determine whether an actor may perform an operation. Business rules determine whether the operation is valid in the resource's current state. A secure implementation needs both.

The Takeaway

The vulnerable and hardened implementations perform the same business operation: order cancellation. The difference is whether the application verifies that the actor is authorized to perform it on the requested order.

In the vulnerable implementation, that boundary is missing. In the hardened implementation, an authorization policy evaluates the actor's permission against the resource owner before the order can be changed.

A secure operation does not just know which resource to modify. It verifies that the actor is allowed to modify it.

This is the central lesson of BOLA/IDOR: object-level authorization must be an enforced property of the application, not an assumption made by the client, the API caller, or an AI agent.

References and Lab

Reproduce the behavior in the controlled lab, compare the vulnerable and hardened modes, and inspect the authorization check in the implementation.