HIGH bola idorspring bootdynamodb

Bola Idor in Spring Boot with Dynamodb

Bola Idor in Spring Boot with Dynamodb — how this combination creates or exposes the vulnerability

Broken Object Level Authorization (BOLA) occurs when an API exposes one user’s resource by allowing direct manipulation of an object identifier (ID) provided by the client. In a Spring Boot application using Amazon DynamoDB, this typically arises because the data layer uses user-supplied IDs (e.g., a noteId) to construct DynamoDB key expressions without verifying that the resource belongs to the requesting user.

DynamoDB stores items in tables with a primary key composed of a partition key (and optionally a sort key). A common pattern is to use a composite key like PK = USER#<user_id> and SK = NOTE#<note_id>. If the application extracts noteId from the request (for example, from a path variable) and builds a Key with only the noteId portion (e.g., NOTE#123), it omits the partition key that encodes the owning user. Without enforcing the user-context, an attacker can change the noteId to access another user’s note, because DynamoDB will return the item if the key exists, regardless of ownership.

Spring Boot applications often use the AWS SDK for Java v2 with a higher-level abstraction such as Spring Data DynamoDB. If the repository or service layer constructs DynamoDB queries using only the client-supplied ID and does not append the user-specific partition key, the authorization boundary collapses. For example, a method like findById(String noteId) may internally run a GetItem using Key.builder().partitionValue(noteId).build(). If noteId is user-controlled and lacks the USER# context, the lookup can retrieve any item in the table that matches the noteId fragment, enabling horizontal privilege escalation across users.

Additionally, if the API exposes nested or derived identifiers (e.g., using a short numeric ID that is globally unique but not user-scoped), BOLA becomes easier to exploit. An attacker can iterate through plausible IDs and observe differences in responses (existence, data content) to map accessible resources. Even with DynamoDB’s per-request IAM permissions, the application’s authorization logic must enforce ownership; otherwise, the unauthenticated or low-privilege role can still read or modify other users’ items if the key structure does not embed the user context.

Real-world attack patterns mirror OWASP API Top 10 A01:2023 broken object level authorization. In DynamoDB, this can intersect with improper use of indexes or secondary global indexes if those indexes expose alternate key paths that do not include the user partition key. For instance, a GSI on a non-user attribute without including the user ID in the key schema can allow an attacker to query across partitions if the application trusts the GSI’s results without re-verifying ownership against the authenticated user’s identity.

To summarize, the combination of Spring Boot, DynamoDB, and BOLA arises when the service layer builds DynamoDB keys from user-supplied IDs without ensuring the authenticated user’s identity is part of the key expression. This creates a direct path for horizontal privilege escalation, where one user can access or manipulate another user’s resources simply by changing the ID in the request.

Dynamodb-Specific Remediation in Spring Boot — concrete code fixes

Remediation centers on ensuring every DynamoDB operation includes the user’s partition key as part of the key expression and validating ownership before performing any GetItem, Query, or DeleteItem. Below are concrete patterns and code examples for Spring Boot applications using the AWS SDK for Java v2.

1. Use a composite primary key with user context

Design your DynamoDB table so that the partition key encodes the user identity (e.g., USER#<user_id>). The sort key can hold the resource type and local ID (e.g., NOTE#<local_id>). This structure ensures that queries are naturally scoped to a user.

2. Service-layer key construction with ownership check

Never build a DynamoDB key from user-supplied IDs alone. Combine the authenticated user’s ID with the user-supplied local identifier. Here is a safe pattern using the AWS SDK for Java v2:

import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.GetItemRequest;
import software.amazon.awssdk.services.dynamodb.model.GetItemResponse;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;

@Service
public class NoteService {

    private final DynamoDbClient ddb;
    private final String tableName = "AppTable";

    public NoteService(DynamoDbClient ddb) {
        this.ddb = ddb;
    }

    // Safe: combines user context with user-supplied localId
    public Map getNoteForUser(String userId, String localNoteId) {
        String partitionKey = "USER#" + userId;
        String sortKey = "NOTE#" + localNoteId;

        GetItemRequest req = GetItemRequest.builder()
            .tableName(tableName)
            .key(Map.of(
                "PK", AttributeValue.builder().s(partitionKey).build(),
                "SK", AttributeValue.builder().s(sortKey).build()
            ))
            .build();

        GetItemResponse resp = ddb.getItem(req);
        return resp.item();
    }
}

Compare this to an unsafe version that uses only the localNoteId as the key, which would expose BOLA.

3. Repository method with Spring Data DynamoDB

If using Spring Data DynamoDB, ensure your entity uses @DynamoDBPartitionKey and @DynamoDBSortKey annotations, and that repository queries include the user context.

import org.springframework.data.annotation.Id;
import org.springframework.data.domain.Persistable;

@DynamoDbBean
public class Note implements Persistable {

    @Id
    private String id; // composite key handled manually or via derived fields

    @DynamoDBPartitionKey
    private String pk; // e.g., USER#userId

    @DynamoDBSortKey
    private String sk; // e.g., NOTE#localId

    // getters/setters
}

public interface NoteRepository extends ReactiveCrudRepository {

    @Query("PK = :pk AND SK = :sk")
    Mono findByPkAndSk(@Param("pk") String pk, @Param("sk") String sk);
}

// Service usage
@Service
public class SafeNoteRepository {

    private final NoteRepository noteRepo;
    private final UserProvider userProvider; // provides authenticated user ID

    public Mono getNoteForCurrentUser(String localNoteId) {
        String userId = userProvider.currentUserId();
        String pk = "USER#" + userId;
        String sk = "NOTE#" + localNoteId;
        return noteRepo.findByPkAndSk(pk, sk);
    }
}

4. Avoid global secondary indexes that bypass user context

If you rely on GSIs, ensure the GSI key schema includes the user partition or that queries on the GSI are filtered by the user ID in the application layer. Prefer querying the main table with the full composite key when possible.

5. Validate IDs before constructing keys

Use path or query parameter validation to ensure IDs are in the expected format and optionally check against a user-scoped index before performing sensitive operations.

6. General defensive practices

  • Always treat user-supplied IDs as references, not as authoritative keys.
  • Log key expressions for auditability, but avoid logging raw sensitive data.
  • Use IAM policies that restrict actions to items where the partition key matches the user’s identity (e.g., condition expressions with dynamodb:LeadingKeys).

By embedding the authenticated user’s identity into the DynamoDB key expression and validating ownership at the service layer, you effectively mitigate BOLA for DynamoDB-backed Spring Boot APIs.

Related CWEs: bolaAuthorization

CWE IDNameSeverity
CWE-250Execution with Unnecessary Privileges HIGH
CWE-639Insecure Direct Object Reference CRITICAL
CWE-732Incorrect Permission Assignment HIGH

Frequently Asked Questions

How can I test if my Spring Boot + DynamoDB API is vulnerable to BOLA?
Use an API security scanner that supports DynamoDB and BOLA checks, or manually attempt to access resources using another user's ID while authenticated as a different user. Observe whether the item is returned or operations succeed across user boundaries.
Does using IAM policies alone prevent BOLA in DynamoDB?
IAM policies can restrict which keys a role may access when used with condition keys like dynamodb:LeadingKeys, but they do not replace application-level ownership checks. A defense-in-depth approach that includes both IAM and explicit user-context in key construction is recommended.