Bola Idor in Rocket with Bearer Tokens
Bola Idor in Rocket with Bearer Tokens — how this specific combination creates or exposes the vulnerability
Broken Object Level Authorization (BOLA) occurs when an API lacks proper authorization checks such that one object can be accessed or manipulated simply by changing its identifier. In Rocket, a common pattern is to protect routes with Bearer Tokens in the Authorization header and then use a resource ID (e.g., a numeric or UUID) to fetch or update a record. If the endpoint validates the presence of a valid token but does not verify that the token’s subject owns or is permitted to act on the requested object, BOLA is introduced.
Consider a Rocket endpoint designed to retrieve a user profile by ID:
use rocket::{get, routes};
use rocket::http::Status;
use rocket::request::{self, FromRequest};
use rocket::Request;
struct AuthToken(String);
#[rocket::async_trait]
impl<'r> FromRequest<'r> for AuthToken {
type Error = ();
async fn from_request(req: &Request<'_>) -> request::Outcome<AuthToken, Self::Error> {
// Simplified: extract Bearer token from header
match req.headers().get_one("Authorization").map(|s| s.strip_prefix("Bearer ")) {
Some(Some(token)) if !token.is_empty() => request::Outcome::Success(AuthToken(token.to_string())),
_ => request::Outcome::Error((Status::Unauthorized, ())),
}
}
}
#[get("/profile/<id>")]
async fn get_profile(id: i64, token: AuthToken) -> Result {
// BOLA risk: no check that token belongs to id
Ok(format!("Profile data for {id}"))
}
#[rocket::main]
async fn main() {
rocket::build().mount("/", routes![get_profile]).launch().await.unwrap();
}
In this example, any authenticated user with a valid Bearer Token can request /profile/123 and receive data for any id without ownership verification. This maps directly to the OWASP API Top 10 A1: Broken Object Level Authorization and is a common finding in unauthenticated or limited-scope scans run by tools like middleBrick, which tests the unauthenticated attack surface and reports BOLA/IDOR as a standalone check. Even with Bearer Tokens present, if the server does not enforce scope- or ownership-based authorization, horizontal privilege escalation is possible: User A can read or modify User B’s resources simply by iterating IDs.
Rocket’s strong type system and request guards encourage explicit handling, but authorization logic must be added explicitly. An attacker can probe endpoints with predictable IDs (e.g., sequential integers or UUIDs) while supplying different Bearer Tokens. If responses differ between authenticated and unauthorized attempts, information exposure may occur. middleBrick’s BOLA/IDOR check aligns with this by correlating runtime behavior against spec definitions and highlighting endpoints where object-level constraints are missing, regardless of whether Bearer Tokens are required.
Additional risk amplifies when tokens have broad scopes or when IDs are exposed in URLs, logs, or error messages. For example, an endpoint that accepts a token and an organization ID must ensure the token is a member of that organization; otherwise, horizontal escalation across organizations becomes feasible. The presence of Bearer Tokens does not mitigate BOLA; it only authenticates identity. Authorization must be enforced per object, typically by binding the token’s subject (e.g., user ID or roles) to the requested resource and validating this binding on each request.
Bearer Tokens-Specific Remediation in Rocket — concrete code fixes
To remediate BOLA in Rocket while using Bearer Tokens, ensure that every endpoint that accesses a specific object validates that the authenticated principal has permission to operate on that object. This typically involves decoding the token’s subject, comparing it to the requested resource owner, and enforcing scoping rules before proceeding.
Below is a concrete, safe implementation using Rocket guards and a simple claims structure. The token is validated, ownership is checked, and the request proceeds only if the user matches the resource:
use rocket::{get, routes, State};
use rocket::http::Status;
use rocket::request::{self, FromRequest};
use rocket::Request;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Deserialize, Serialize)]
struct Claims {
sub: i64, // subject: user ID
// other claims like roles, scopes can be added
}
struct AuthenticatedUser {
claims: Claims,
}
#[rocket::async_trait]
impl<'r> FromRequest<'r> for AuthenticatedUser {
type Error = ();
async fn from_request(req: &Request<'_>) -> request::Outcome<AuthenticatedUser, Self::Error> {
// Extract Bearer token (simplified)
let header = match req.headers().get_one("Authorization") {
Some(h) if h.starts_with("Bearer ") => &h[7..],
_ => return request::Outcome::Error((Status::Unauthorized, ())),
};
// In practice, validate signature and expiry via a JWT library
// Here we mock decoding to Claims
let claims = decode_claims(header).map_err(|_| ())?;
request::Outcome::Success(AuthenticatedUser { claims })
}
}
fn decode_claims(token: &str) -> Result<Claims, &'static str> {
// Replace with real JWT validation; this is illustrative
if token.is_empty() {
return Err("invalid token");
}
// Mock: assume sub is encoded somehow; use a proper JWT library in production
Ok(Claims { sub: 42 }) // Example static subject
}
#[get("/profile/<id>")]
async fn get_profile(user: AuthenticatedUser, id: i64, db: &State<Db>) -> Result<String, Status> {
// BOLA mitigation: ensure user can only access their own profile
if user.claims.sub != id {
return Err(Status::Forbidden);
}
// Fetch from db; ensure row-level security on the database as well
db.get_profile(id).map_err(|_| Status::NotFound)?;
Ok(format!("Profile for user {id}"))
}
// Example usage in main
#[rocket::main]
async fn main() {
let db = Db::default();
rocket::build()
.manage(db)
.mount("/", routes![get_profile])
.launch()
.await
.unwrap();
}
// Dummy DB for illustration
struct Db;
impl Db {
fn get_profile(&self, id: i64) -> Result<(), ()> {
// Real implementation would query with parameterized statements
if id > 0 { Ok(()) } else { Err(()) }
}
}
This pattern binds the Bearer Token’s subject to the requested ID and returns 403 when they do not match. For endpoints that act on collections or require role-based access, integrate a permissions layer and ensure that scope claims (if present) authorize the operation. middleBrick’s Pro plan supports continuous monitoring and CI/CD integration via the GitHub Action, which can automatically fail builds if risk scores exceed a defined threshold, helping to catch regressions introduced by changes in authorization logic.
When using the CLI to scan your Rocket API, run middlebrick scan <url> to obtain a report that includes BOLA findings and remediation guidance. The MCP Server allows you to trigger such scans directly from compatible AI coding assistants within your development environment, streamlining security checks during implementation.
Related CWEs: bolaAuthorization
| CWE ID | Name | Severity |
|---|---|---|
| CWE-250 | Execution with Unnecessary Privileges | HIGH |
| CWE-639 | Insecure Direct Object Reference | CRITICAL |
| CWE-732 | Incorrect Permission Assignment | HIGH |
Frequently Asked Questions
Does using Bearer Tokens alone prevent BOLA in Rocket APIs?
How can I test for BOLA with Bearer Tokens in Rocket during development?
middlebrick scan <url>) which tests unauthenticated attack surfaces and includes BOLA/IDOR checks. The Pro plan’s continuous monitoring can also alert you to changes in risk scores that may indicate introduced authorization gaps.