Insufficient Logging in Feathersjs with Cockroachdb
Insufficient Logging in Feathersjs with Cockroachdb — how this specific combination creates or exposes the vulnerability
Insufficient logging in a Feathersjs service that uses Cockroachdb can leave critical security events unrecorded, reducing your ability to detect, investigate, and respond to incidents. Feathersjs is a framework that abstracts service logic into services and hooks; if hooks do not explicitly log authentication attempts, data access, mutations, and errors, you lose visibility into who did what and when.
When Feathersjs interacts with Cockroachdb, a distributed SQL database, logging gaps become especially important because Cockroachdb provides strong consistency and geographic distribution. Without logs capturing query metadata, transaction outcomes, and schema-level changes, you cannot reliably trace whether an IDOR (Insecure Direct Object Reference) or BOLA (Broken Level of Access) pattern occurred, or whether a query returned more data than intended.
Consider a typical Feathersjs service defined with the @feathersjs/transport-commons transports and a Cockroachdb adapter. If the service does not log the resolved query conditions, user identity context, or the number of affected rows, an attacker can probe endpoints such as /users/:id and, when the service misbehaves or returns another user’s record, the backend will not generate an auditable event. This makes it difficult to correlate with authentication anomalies, suspicious IPs, or unusual query patterns that could indicate reconnaissance or exploitation.
Real-world attack patterns that exploit insufficient logging include:
- Credential stuffing or brute-force authentication attempts where login failures are not recorded, preventing detection of account takeover campaigns.
- Data exfiltration via IDOR where an attacker iterates over identifiers; without request and response logging, the lateral movement remains invisible.
- Privilege escalation through BFLA (Business Logic Abuse) where a user elevates permissions via an unlogged administrative endpoint; because the action is not captured, there is no evidence for forensic analysis.
Compliance frameworks such as OWASP API Top 10 A03:2023 (Injection) and A07:2021 (Identification and Authentication Failures) emphasize the need for audit trails for authentication and sensitive data operations. In a Feathersjs + Cockroachdb stack, you should ensure that logs include at minimum: timestamp, request identifier, authenticated subject (user ID or principal), endpoint path, HTTP method, query or mutation payload summary, Cockroachdb transaction status (success/retry/abort), affected table and row count, and any validation or authorization failures.
middleBrick scans can surface these logging gaps by analyzing the unauthenticated attack surface and correlating runtime behavior with the OpenAPI spec. It checks whether authentication, authorization, and data exposure controls are observable in logs and whether critical endpoints lack sufficient audit coverage. While middleBrick does not fix the logging implementation, it provides prioritized findings with remediation guidance to help you strengthen observability in your Feathersjs services.
Cockroachdb-Specific Remediation in Feathersjs — concrete code fixes
To address insufficient logging when using Cockroachdb with Feathersjs, instrument your services and hooks to emit structured, actionable logs. Use a logging library such as winston or pino, and ensure every service method logs inputs, outcomes, and errors. Below are concrete code examples that show how to implement this pattern.
1. Configure a structured logger
Set up a logger that includes a request-scoped identifier so you can trace a single transaction across services and database calls.
// src/logger.js
const { createLogger, format, transports } = require('winston');
const { combine, timestamp, printf } = format;
const logFormat = printf(({ level, message, timestamp, requestId, ...meta }) => {
let base = `${timestamp} [req:${requestId}] ${level}`;
if (message) base += ` — ${message}`;
if (Object.keys(meta).length) base += ` ${JSON.stringify(meta)}`;
return base;
});
const logger = createLogger({
level: 'info',
format: combine(
timestamp(),
logFormat
),
transports: [new transports.Console()]
});
module.exports = logger;
2. Wrap Cockroachdb queries with logging in a custom service
Create a Feathersjs service that explicitly logs before and after Cockroachdb operations. This example uses the feathers-objection adapter, which allows you to tap into Knex instances.
// src/services/users/users.service.js
const logger = require('../../logger');
class UsersService {
constructor(options) {
this.options = options;
}
async find(params) {
const { user, query } = params;
const requestId = params.requestId || 'unknown';
logger.info('users.find called', {
requestId,
queryKeys: Object.keys(query).filter(k => k !== '$select' && k !== '$expand'),
authenticatedUserId: user && user.id ? user.id : null,
isAuthenticated: Boolean(user)
});
// this.model is an Objection model backed by Cockroachdb
const rows = await this.model.query().where(query).withGraphFetched('profile');
logger.info('users.find completed', {
requestId,
rowCount: rows.length,
affectedTables: ['users', 'profiles']
});
return rows;
}
async get(id, params) {
const requestId = params.requestId || 'unknown';
logger.info('users.get called', {
requestId,
userId: id,
caller: params.user ? params.user.id : null
});
const row = await this.model.query().findById(id).withGraphFetched('profile');
if (!row) {
logger.warn('users.get not found', { requestId, userId: id });
return null;
}
logger.info('users.get succeeded', { requestId, userId: id });
return row;
}
}
module.exports = function (app) {
const options = {
Model: app.get('knex'), // configured for Cockroachdb
paginate: { default: 25, max: 50 }
};
app.use('/users', new UsersService(options));
};
3. Log in hooks to capture authorization and validation decisions
Hooks are the right place to log authorization checks, especially for BOLA and BFLA patterns. This example logs both allowed and blocked attempts.
// src/hooks/authorization-hook.js
const logger = require('../logger');
module.exports = function authorizationHook(options = {}) {
return async context => {
const { user, method, path } = context.params;
const requestId = context.params.requestId || 'unknown';
const subjectId = user && user.id ? user.id : 'anonymous';
// Example: ensure users can only access their own resource unless admin
if (method === 'get' || method === 'patch') {
const resourceId = context.id || (context.data && context.data.id);
if (String(subjectId) !== String(resourceId) && !user.isAdmin) {
logger.warn('authorization.blocked', {
requestId,
subjectId,
method,
path,
resourceId,
reason: 'insufficient_scope_idor'
});
throw new Error('Forbidden: insufficient scope');
}
logger.info('authorization.allowed', {
requestId,
subjectId,
method,
path,
resourceId
});
}
return context;
};
};
4. Log Cockroachdb transaction outcomes and retries
Cockroachdb may retry transactions due to contention. Log transaction attempts and final outcomes to aid debugging and forensic correlation.
// src/services/orders.service.js with transactional logging
const logger = require('../../logger');
class OrdersService {
constructor(options) {
this.options = options;
}
async create(data, params) {
const requestId = params.requestId || 'unknown';
const user = params.user;
logger.info('orders.create.start', {
requestId,
userId: user ? user.id : null,
amount: data.amount,
currency: data.currency
});
try {
const result = await this.model.query().insert(data);
logger.info('orders.create.committed', {
requestId,
orderId: result.id,
userId: user ? user.id : null
});
return result;
} catch (error) {
logger.error('orders.create.failure', {
requestId,
error: error.message,
code: error.code,
stack: this.options.dev ? error.stack : undefined
});
throw error;
}
}
}
module.exports = function (app) {
const options = {
Model: app.get('knex'),
dev: process.env.NODE_ENV !== 'production'
};
app.use('/orders', new OrdersService(options));
};
These patterns ensure that each interaction with Cockroachdb is recorded with sufficient context for security monitoring and incident response. By combining structured logs with middleBrick’s security checks, you can more easily identify gaps and apply consistent remediation across your Feathersjs services.