HIGH bola idorloopbackcockroachdb

Bola Idor in Loopback with Cockroachdb

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

Broken Object Level Authorization (BOLA) in a LoopBack application backed by CockroachDB occurs when an API exposes a record identifier (typically a UUID or integer) and does not enforce ownership or scope checks before returning or modifying that record. In this stack, an endpoint such as /api/users/{id} might accept an {id} supplied by the client, issue a CockroachDB SQL query, and return the row if it exists, without verifying that the authenticated subject (user or client) is permitted to access that specific row.

With CockroachDB, a distributed SQL database, the risk is not about the database being unable to enforce constraints, but about the application layer omitting tenant or ownership filters. For example, a query like SELECT * FROM users WHERE id = $1 keyed off a path parameter {id} returns a row even when the authenticated user belongs to a different tenant or organization. Because CockroachDB supports complex schemas and secondary indexes, an attacker can iterate IDs rapidly and observe whether rows exist and whether field values differ across what should be isolated tenants.

LoopBack’s model binding and remote hooks can inadvertently enable BOLA when developer-defined relations or ACLs are incomplete. If a model has a scope such as tenant_id but the access controls do not consistently apply that scope at the datasource or repository level, the API may leak data across tenant boundaries. Attack patterns include changing numeric IDs in sequential order (IDOR), manipulating foreign keys to escalate access (for example, switching a project_id to another project the user does not own), or reusing a token issued to one team to query another team’s datasets stored in the same CockroachDB cluster.

Real-world indicators of BOLA in this environment include endpoints that return 200 with another user’s data when supplied with a different identifier, lack of row-level security predicates in SQL, and absence of per-request ownership checks. Because CockroachDB preserves ACID semantics across distributed nodes, an attacker who discovers a missing authorization check may read or alter records that should be isolated by tenant, role, or consent scope. This becomes critical in multi-tenant deployments where a single CockroachDB instance hosts schemas for many organizations, and LoopBack datasources connect without per-request tenant qualification.

To detect this class of issue, scanners run unauthenticated or low-privilege authenticated probes that iterate identifiers, inspect response differences, and analyze schema metadata from the CockroachDB system tables or OpenAPI descriptions. Findings highlight endpoints where identifiers are directly user-controlled and where queries do not bind tenant or ownership filters. Remediation guidance focuses on enforcing server-side scope checks, applying model-level ACLs that include tenant context, and validating that every CockroachDB query includes a predicate that ties data access to the requesting subject.

Cockroachdb-Specific Remediation in Loopback — concrete code fixes

Remediation requires ensuring that every query against CockroachDB includes a tenant or ownership predicate tied to the authenticated subject. Below are concrete LoopBack examples using a MySQL-compatible datasource (which works with CockroachDB) that demonstrate secure patterns.

1. Scope-bound repository or datasource query

Instead of relying on default Model.findById, explicitly include the tenant_id in the where clause and use the current user’s context.

const {repository} = require('loopback-datasource-juggler');

// In a custom repository or remote method
async findByIdForUser(id, userId, tenantId) {
  const result = await this.dataSource.query(
    'SELECT * FROM users WHERE id = $1 AND tenant_id = $2 AND user_id = $3',
    [id, tenantId, userId]
  );
  if (!result.length) {
    const err = new Error('Not found');
    err.statusCode = 404;
    throw err;
  }
  return result[0];
}

2. Model hook to enforce scope

Attach a remote hook in your model definition that appends tenant and ownership filters automatically so all datasource operations respect the scope.

module.exports = function(User) {
  User.observe('access', function hookCtx(ctx, next) {
    const {tenantId, currentUserId} = ctx.options && ctx.options.context || {};
    if (!tenantId || !currentUserId) {
      return next(new Error('Missing tenant or user context'));
    }
    const where = Object.assign({}, ctx.where);
    where.AND = [
      {tenant_id: tenantId},
      {user_id: currentUserId}
    ];
    ctx.where = where;
    next();
  });
};

3. Remote method with explicit ownership check

In your model’s JSON configuration or JavaScript definition, define a remote method that validates ownership before executing SQL through the CockroachDB connector.

User.prototype.getProfile = function(id, options, cb) {
  const userId = options && options.accessToken && options.accessToken.userId;
  const tenantId = options && options.tenantId;
  if (!userId || !tenantId) {
    return cb(new Error('Unauthorized'));
  }
  User.dataSource.query(
    'SELECT * FROM users WHERE id = $1 AND tenant_id = $2 AND user_id = $3',
    [id, tenantId, userId],
    (err, rows) => {
      if (err) return cb(err);
      cb(null, rows[0] || {error: 'Not found'});
    }
  );
};
User.remoteMethod('getProfile', {
  accepts: [{arg: 'id', type: 'string', required: true}],
  returns: {arg: 'profile', type: 'object'},
  http: {path: '/profile', verb: 'get'}
});

4. Use model settings to scope by tenant

Define a common filter that automatically scopes queries. This works well when your datasource routes to a CockroachDB schema per tenant or uses shared tables with tenant_id columns.

{
  "name": "User",
  "base": "PersistedModel",
  "options": {
    "validateUpsert": true
  },
  "properties": {
    "id": {"type": "string", "id": true},
    "tenant_id": {"type": "string"},
    "email": {"type": "string"}
  },
  "acls": [
    {
      "principalType": "ROLE",
      "principalId": "$everyone",
      "permission": "DENY"
    }
  ]
}

Combine these model settings with repository-level scoping so that every generated SQL includes tenant_id = ?. In CockroachDB, ensure the tenant_id column is indexed to maintain performance while enforcing strict row-level isolation.

5. Contextual datasource routing

For multi-tenant deployments, configure datasource routing in LoopBack to select the correct CockroachDB node or schema based on the request context, and ensure the routing logic is applied before any query executes.

app.datasource('cockroach').setSchemaForRequest = function(req, cb) {
  const tenantId = req.headers['x-tenant-id'];
  if (!tenantId) return cb(new Error('Missing tenant'));
  // route to the appropriate CockroachDB tenant schema or node
  this.schema(tenantId, cb);
};

These patterns ensure that BOLA is mitigated by tying every read and write to both the record identifier and the authenticated subject’s tenant and user context, making it impossible to access another tenant’s rows even when the identifier is known.

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 does middleBrick detect BOLA when scanning CockroachDB-backed APIs?
middleBrick tests unauthenticated and low-privilege authenticated endpoints that accept user-supplied identifiers, then checks whether queries include tenant or ownership predicates. It compares the inferred schema from CockroachDB system metadata with runtime responses to identify missing scope checks.
Can middleBrick’s LLM/AI Security checks help identify prompt injection risks in APIs that feed into AI features backed by CockroachDB?
Yes. middleBrick includes active prompt injection probes and system prompt leakage detection that are applicable regardless of the backend database. These checks are independent of CockroachDB and focus on the API’s behavior when interacting with LLM endpoints.