HIGH insecure direct object referencefiberapi keys

Insecure Direct Object Reference in Fiber with Api Keys

Insecure Direct Object Reference in Fiber with Api Keys — how this specific combination creates or exposes the vulnerability

Insecure Direct Object Reference (BOLA/IDOR) occurs when an API exposes internal object references (e.g., database IDs, filenames) without verifying that the authenticated context is allowed to access the specific resource. In Fiber, this commonly arises when route parameters are used directly to look up resources, and access control is implemented only at a coarse level (e.g., requiring an API key for the endpoint) rather than at the object level.

Consider a Fiber-based service that uses API keys for route-level authentication but does not enforce ownership or authorization checks on the resource identifier. For example, an endpoint like /users/:userID/profile may validate the presence of a valid API key but then directly use the userID from the URL to fetch and return profile data. If the API key belongs to a tenant or user that does not own the requested userID, the API will still return the data, exposing another user’s private information.

Here is a vulnerable Fiber example that illustrates the pattern:

const { Fiber, } = require('fiber');
const app = Fiber();

// Insecure: API key only protects route entry, not object-level access
app.get('/users/:userID/profile', (req, res) => {
  const apiKey = req.get('X-API-Key');
  if (!validateApiKey(apiKey)) {
    return res.status(401).send({ error: 'Unauthorized' });
  }
  // BOLA/IDOR: userID from URL used directly without ownership check
  const profile = getUserProfileById(req.params.userID);
  res.send(profile);
});

function validateApiKey(key) {
  // simplistic example: check against a set of valid keys
  return key === 'valid-key-123';
}

function getUserProfileById(id) {
  // pretend this fetches from a data store
  return { id, name: 'Alice', email: '[email protected]' };
}

In this scenario, any client with a valid API key can enumerate or access any user’s profile by guessing or iterating numeric IDs. The API key provides a gate, but it does not bind the key to the specific resource, so the application fails to enforce that the authenticated subject is allowed to interact with that particular object. This is a classic BOLA/IDOR issue: the reference (userID) is directly exposed and used without contextual authorization.

Another common pattern in Fiber is using API keys to gate write operations (e.g., updating or deleting resources) without ensuring the caller is permitted to act on the specific object. For instance, a DELETE route may authenticate via API key but then delete a record identified only by an ID supplied by the client, allowing an attacker to remove or modify resources they should not touch.

Because middleBrick tests unauthenticated attack surfaces, it flags such endpoints during the BOLA/IDOR check. The scanner detects that the route exposes object references without verifying that the requester’s context (e.g., scope, tenant, or key binding) aligns with the referenced object. Remediation requires coupling API key validation with per-request object-level authorization, ensuring that the identity or scope associated with the key matches the resource being accessed.

Api Keys-Specific Remediation in Fiber — concrete code fixes

To fix BOLA/IDOR in Fiber when using API keys, move from route-level checks to resource-level authorization. This means validating not only that an API key is valid, but also that the key grants access to the specific object identified by route parameters. Below are concrete, safe patterns you can adopt.

1. Bind API key to a principal and check ownership

Store metadata for each API key (e.g., tenant ID or user ID) and ensure that any object access verifies this binding. Avoid using raw user-supplied IDs directly; instead, resolve the object through a query that includes the principal constraint.

const { Fiber } = require('fiber');
const app = Fiber();

// Assume apiKeys is a map of key -> { tenantId }
const apiKeys = {
  'tenantA-key': { tenantId: 'tenantA' },
  'tenantB-key': { tenantId: 'tenantB' },
};

app.get('/documents/:documentID', (req, res) => {
  const apiKey = req.get('X-API-Key');
  const keyMeta = apiKeys[apiKey];
  if (!keyMeta) {
    return res.status(401).send({ error: 'Invalid API key' });
  }
  const documentID = req.params.documentID;
  // Enforce tenant-level constraint at the data access layer
  const document = getDocumentByIdAndTenant(documentID, keyMeta.tenantId);
  if (!document) {
    return res.status(404).send({ error: 'Not found or access denied' });
  }
  res.send(document);
});

function getDocumentByIdAndTenant(id, tenantId) {
  // This function should generate SQL like:
  // SELECT * FROM documents WHERE id = $1 AND tenant_id = $2
  // Return null if no matching row exists
  return { id, tenantId, content: 'secret' };
}

2. Use indirect references or mappings instead of direct IDs

Instead of exposing sequential or guessable IDs, use opaque references (UUIDs) and maintain a server-side mapping that includes access context. This prevents enumeration and ensures that even if a reference is leaked, it cannot be reused across tenants.

const { Fiber } = require('fiber');
const { v4: uuidv4 } = require('uuid');
const app = Fiber();

const mapping = {}; // { opaqueRef: { documentID, tenantId } }

app.post('/documents', (req, res) => {
  const apiKey = req.get('X-API-Key');
  const keyMeta = apiKeys[apiKey];
  if (!keyMeta) {
    return res.status(401).send({ error: 'Invalid API key' });
  }
  const documentID = createDocument(req.body, keyMeta.tenantId);
  const opaqueRef = uuidv4();
  mapping[opaqueRef] = { documentID, tenantId: keyMeta.tenantId };
  res.send({ ref: opaqueRef });
});

app.get('/documents/:ref', (req, res) => {
  const apiKey = req.get('X-API-Key');
  const keyMeta = apiKeys[apiKey];
  if (!keyMeta) {
    return res.status(401).send({ error: 'Invalid API key' });
  }
  const ref = req.params.ref;
  const mappingEntry = mapping[ref];
  if (!mappingEntry || mappingEntry.tenantId !== keyMeta.tenantId) {
    return res.status(404).send({ error: 'Not found or access denied' });
  }
  const document = getDocumentById(mappingEntry.documentID);
  res.send(document);
});

function createDocument(payload, tenantId) {
  // Insert with tenantId and return numeric ID
  return 123;
}

function getDocumentById(id) {
  return { id, content: 'tenant-specific data' };
}

3. Centralize authorization logic

Create a reusable authorization function that checks both API key validity and object ownership. This keeps checks consistent across routes and reduces the risk of missing a BOLA scenario.

const { Fiber } = require('fiber');
const app = Fiber();

function authorizeApiKeyAndResource(apiKey, resourceId, resourceType) {
  const keyMeta = apiKeys[apiKey];
  if (!keyMeta) return { ok: false, error: 'Invalid API key' };
  // Perform a scoped lookup that includes tenant/key binding
  const hasAccess = checkResourceAccess(resourceId, resourceType, keyMeta.tenantId);
  return hasAccess ? { ok: true } : { ok: false, error: 'Access denied' };
}

app.get('/items/:itemID', (req, res) => {
  const apiKey = req.get('X-API-Key');
  const auth = authorizeApiKeyAndResource(apiKey, req.params.itemID, 'item');
  if (!auth.ok) {
    return res.status(403).send({ error: auth.error });
  }
  const item = fetchItemWithAccess(req.params.itemID, apiKey);
  res.send(item);
});

These patterns ensure API keys are not used as a blanket gate but are combined with per-request context checks. By aligning the key’s scope with the resource access, you mitigate BOLA/IDOR and make enumeration or privilege escalation significantly harder.

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

Can API keys alone prevent IDOR in Fiber?
No. API keys typically authenticate the client but do not encode resource ownership. Without per-request checks that bind the key to the specific object (e.g., tenant ID, user ID), an API key alone cannot prevent IDOR.
How does middleBrick help detect these issues?
middleBrick scans unauthenticated endpoints and flags BOLA/IDOR by correlating exposed object references with missing ownership or scope checks. Its OpenAPI/Swagger analysis resolves $ref chains and compares spec definitions with runtime behavior to highlight mismatches.