HIGH bola idorhapicockroachdb

Bola Idor in Hapi with Cockroachdb

Bola Idor in Hapi with Cockroachdb — how this specific combination creates or exposes the vulnerability

Broken Object Level Authorization (BOLA) occurs when an API exposes one user’s data through predictable identifiers without verifying ownership. In a Hapi application backed by CockroachDB, this typically arises when route parameters such as userId or resourceId are used directly in SQL statements without contextual authorization checks. Because CockroachDB is compatible with PostgreSQL wire protocol, developers often use pg-style parameterized queries; however, parameterization alone does not enforce ownership boundaries.

Consider a route /api/users/{userId}/profile. If the handler builds a query like SELECT * FROM profiles WHERE id = $1 and binds userId from the request, an attacker can change the ID to another valid UUID and access unrelated profiles. The presence of CockroachDB does not mitigate this; it only provides a distributed SQL surface. Without an additional authorization layer that ties the authenticated subject to the requested resource, the unauthenticated or low-privilege actor can enumerate IDs and exfiltrate data across tenant boundaries. This is a classic BOLA/IDOR pattern mapped to OWASP API Top 10 A1: Broken Object Level Authorization.

In practice, BOLA becomes more severe when schema design leaks implicit relationships. For example, if the profiles table includes a organization_id column and the application trusts a URL-supplied organization slug, an attacker can swap the slug to traverse organizations. CockroachDB’s secondary indexes and strong consistency can make enumeration fast and predictable, increasing the risk of mass assignment or scraping. Since BOLA is about authorization mismatch rather than injection, input validation and encryption do not prevent it; the fix must enforce that every data access includes a tenant or ownership predicate tied to the caller’s identity.

Real-world attack patterns include ID incrementation, UUID enumeration, and predictable resource keys. These map to CWE-639 and CWE-287. The scanner checks such as BOLA/IDOR in middleBrick run parallel checks across the unauthenticated surface, and when a route accepts a referenceable identifier without verifying the requesting user’s rights, a finding is generated with severity high and remediation guidance to add contextual authorization.

Cockroachdb-Specific Remediation in Hapi — concrete code fixes

Remediation centers on ensuring every SQL statement includes an authorization predicate that ties data access to the authenticated subject or tenant. Do not rely on route-level ID validation alone; enforce ownership at the query level. Below are concrete, working examples using @hapi/hapi and the CockroachDB-compatible pg client.

1. Parameterized query with tenant context

Always bind both the resource identifier and the tenant or user identifier, and include the tenant in the WHERE clause.

const Hapi = require('@hapi/hapi');
const { Pool } = require('pg');

const pool = new Pool({
  connectionString: process.env.DATABASE_URL,
});

const init = async () => {
  const server = Hapi.server({ port: 4000, host: 'localhost' });

  server.route({
    method: 'GET',
    path: '/api/users/{userId}/profile',
    options: {
      validate: {
        params: Joi.object({
          userId: Joi.string().guid(),
        }),
      },
      handler: async (request, h) =>
        handleUserProfile(request, h),
    },
  });

  await server.start();
  console.log('Server running on %s', server.info.uri);
};

const handleUserProfile = async (request, h) =>
{
  const { userId } = request.params;
  const authenticatedUserId = request.auth.credentials.userId; // from session or JWT

  const query = `
    SELECT id, display_name, email
    FROM profiles
    WHERE id = $1 AND user_id = $2
    LIMIT 1;
  `;
  const values = [userId, authenticatedUserId];

  const { rows } = await pool.query(query, values);
  if (rows.length === 0) {
    return h.response({ error: 'Not found' }).code(404);
  }
  return rows[0];
};

2. Organization-scoped access with JOIN

When resources are scoped by organization, include the organization identifier in the query, even if it is derivable from the resource.

server.route({
  method: 'GET',
  path: '/api/organizations/{orgSlug}/projects/{projectId}',
  options: {
    validate: {
      params: Joi.object({
        orgSlug: Joi.string().alphanum(),
        projectId: Joi.string().guid(),
      }),
    },
    handler: async (request, h) =>
      handleProject(request, h),
  },
});

const handleProject = async (request, h) =>
{
  const { orgSlug, projectId } = request.params;
  const userId = request.auth.credentials.userId;

  const query = `
    SELECT p.id, p.name, p.config
    FROM projects p
    JOIN organizations o ON p.organization_id = o.id
    WHERE o.slug = $1 AND p.id = $2 AND o.member_user_ids @> $3::uuid[]
    LIMIT 1;
  `;
  const values = [orgSlug, projectId, [userId]]; // use array containment for simplicity

  const { rows } = await pool.query(query, values);
  if (rows.length === 0) {
    return h.response({ error: 'Forbidden' }).code(403);
  }
  return rows[0];
};

3. Centralized authorization helper

To avoid repetition, encapsulate checks in a service that enforces ownership before returning data.

const profileService = {
  async getProfileByUserId(requestedUserId, requestingUserId) {
    const query = 'SELECT id, display_name FROM profiles WHERE id = $1 AND user_id = $2';
    const { rows } = await pool.query(query, [requestedUserId, requestingUserId]);
    return rows[0] || null;
  },
};

// In handler
const profile = await profileService.getProfileByUserId(userId, authenticatedUserId);
if (!profile) {
  return h.response({ error: 'Unauthorized' }).code(403);
}

Operational guidance

  • Use role-based access control (RBAC) or attribute-based access control (ABAC) policies encoded in your application logic; do not expose raw identifiers without context.
  • Audit logs should record attempted accesses with both resource and subject identifiers to detect enumeration patterns.
  • middleBrick scans can surface BOLA findings; remediation guidance will point to adding contextual predicates and ownership checks.

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

Why does parameterization alone not prevent BOLA in Hapi with CockroachDB?
Parameterization prevents SQL injection but does not enforce ownership. If the query omits a tenant or user predicate, an attacker can substitute any valid ID and retrieve data they should not see.
Can middleBrick detect BOLA even when the endpoint returns 200 with different data shapes?
Yes. middleBrick runs parallel checks including BOLA/IDOR that compare authorization context with returned data patterns; findings include severity and remediation guidance.