Broken Access Control in Hanami with Dynamodb
Broken Access Control in Hanami with Dynamodb — how this specific combination creates or exposes the vulnerability
Broken Access Control occurs when authorization checks are missing or bypassed, allowing one user to act on another user's resources. In a Hanami web application using Amazon DynamoDB as the persistence layer, this risk is amplified if object-level permissions are enforced only in the application layer and not validated against the data model.
Hanami encourages explicit domain modeling, but developers sometimes map DynamoDB tables directly to aggregates without scoping queries by the current user. For example, a PostRepository that loads items by ID without confirming ownership can be exploited via IDOR (Insecure Direct Object References). An attacker can iterate over known IDs or guess UUIDs to access posts belonging to other users.
DynamoDB’s attribute-based access control (ABAC) via IAM policies can mitigate this, but only if policies are tightly scoped to the requester’s identity. If the Hanami app assumes the backend enforces permissions and the DynamoDB policy is permissive, the unauthenticated attack surface increases. The scanner checks for missing authorization at the endpoint and data-layer boundaries, flagging endpoints that accept user-supplied identifiers without verifying they belong to the requesting user.
Real-world attack patterns include changing numeric IDs in query parameters, manipulating JWT-sub claims, or reusing session tokens across tenants. The middlebrick LLM/AI Security checks also probe for endpoints that expose model outputs containing sensitive data, which can occur if error messages from DynamoDB are not sanitized.
Using the OpenAPI/Swagger spec analysis, middlebrick cross-references path parameters and request body schemas with runtime behavior. If an endpoint accepts post_id without a matching scope filter (e.g., user_id = :user_id), it will surface as a BOLA/IDOR finding with severity High and remediation guidance to enforce ownership checks.
Dynamodb-Specific Remediation in Hanami — concrete code fixes
To secure Hanami with DynamoDB, enforce ownership checks at the repository level and scope IAM policies to the authenticated user. Below are concrete, working examples that align with DynamoDB best practices and Hanami’s domain-driven design.
1. Scoped query in a Hanami repository
Always include the user identifier in the query key condition. This ensures DynamoDB returns only items the user is allowed to access.
require "dynamodb"
class PostRepository
def initialize(table_name = "posts")
@client = Aws::DynamoDB::Client.new
@table = table_name
end
# Fetch a post only if it belongs to the current user
def find_by_id_for_user(post_id, user_id)
resp = @client.get_item(
table_name: @table,
key: {
pk: { s: "USER##{user_id}" },
sk: { s: "POST##{post_id}" }
}
)
item = resp.item
return nil if item.empty?
# Map DynamoDB attribute values to domain entity
Post.new(id: item["sk"].s.split("##").last,
title: item["title"].s,
body: item["body"].s,
author_id: item["user_id"].s)
end
end
2. IAM policy scoped to user-specific partition keys
Define a policy that restricts each user to their own partition key. This complements application-level checks and reduces the impact of misconfigured endpoints.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"dynamodb:GetItem",
"dynamodb:Query"
],
"Resource": "arn:aws:dynamodb:us-east-1:123456789012:table/posts",
"Condition": {
"ForAllValues:StringEquals": {
"dynamodb:LeadingKeys": ["${cognito-identity.amazonaws.com:sub}"]
}
}
}
]
}
3. Hanami endpoint with explicit ownership validation
In the operation class, ensure the current user context is used to scope the repository call. Avoid exposing raw IDs in responses that could be leveraged for horizontal escalation.
class Web::Posts::Show
include Hanami::Action
def handle_request(params)
user_id = current_user.id
post_id = params[:id]
post = PostRepository.new.find_by_id_for_user(post_id, user_id)
if post
Response::Ok.new(post)
else
Response::NotFound.new({ error: "Post not found or access denied" })
end
end
end
4. Use DynamoDB condition expressions for additional safety
When updating or deleting, add a condition that the user_id attribute matches the authenticated user. This prevents race conditions where permissions change between read and write.
@client.update_item(
table_name: @table,
key: { pk: { s: "USER##{user_id}" }, sk: { s: "POST##{post_id}" } },
update_expression: "SET #title = :title",
condition_expression: "user_id = :uid",
expression_attribute_names: { "#title" => "title" },
expression_attribute_values: {
":title" => { s: new_title },
":uid" => { s: user_id }
}
)
By combining scoped repository methods, tightly scoped IAM policies, and condition expressions, the risk of Broken Access Control in Hanami with DynamoDB is significantly reduced. middlebrick validates these controls through its 12 security checks, including BOLA/IDOR and Property Authorization, to ensure sensitive data exposure and privilege escalation are flagged early.