Api Key Exposure in Feathersjs with Cockroachdb
Api Key Exposure in Feathersjs with Cockroachdb — how this specific combination creates or exposes the vulnerability
FeathersJS is a framework for real-time applications that often exposes REST and WebSocket endpoints without enforcing authentication on service hooks. When a FeathersJS service is configured to use CockroachDB as its persistence layer, developers may inadvertently expose API keys or service credentials through insecure service definitions, logging, or error handling.
The risk occurs when a Feathers service queries CockroachDB with raw parameters that include sensitive metadata, such as an API key stored in a request query or payload. If the service does not sanitize inputs or enforce authorization rules, an attacker can manipulate the request to retrieve or infer the API key. For example, a misconfigured before hook might pass an API key as a query option directly to CockroachDB, and a verbose error message could reveal the key in a stack trace or log entry.
In a black-box scan, middleBrick checks whether unauthenticated endpoints can leak sensitive data by analyzing input validation, authorization logic, and data exposure paths. If a Feathers service connected to CockroachDB does not apply strict property-level checks, an API key could appear in logs, error responses, or client-side traces, violating data exposure controls.
Additionally, insecure integration patterns—such as embedding API keys in client-side requests or failing to mask sensitive fields in serialized responses—amplify the exposure. middleBrick’s checks for Data Exposure and Unsafe Consumption validate whether API keys are protected during transit and serialization, flagging cases where Cockroachdb query results include sensitive metadata without encryption or truncation.
Cockroachdb-Specific Remediation in Feathersjs — concrete code fixes
To secure a FeathersJS service using CockroachDB, explicitly separate sensitive configuration from request flow and enforce strict input validation and authorization in hooks.
1. Use environment variables for secrets
Store API keys and database credentials outside the codebase. In your Feathers service, reference them via process.env and avoid passing raw keys to CockroachDB queries.
// src/environment.js
module.exports = {
cockroachdb: {
connectionString: process.env.COCKROACHDB_CONNECTION_STRING,
apiKey: process.env.EXTERNAL_API_KEY
}
};
2. Parameter sanitization in before hooks
Ensure that any user-supplied data used in CockroachDB queries is validated and stripped of sensitive fields before reaching the database.
// src/hooks/sanitize-api-key.js
module.exports = function sanitizeApiKey() {
return async context => {
const { params } = context;
// Remove API key from query if present in payload
if (params.query && params.query.api_key) {
delete params.query.api_key;
}
// Ensure metadata does not contain raw keys
if (context.data && context.data.metadata) {
context.data.metadata = Object.fromEntries(
Object.entries(context.data.metadata).filter(([key]) => key !== 'api_key')
);
}
return context;
};
};
3. Secure service configuration with field masking
Configure your Feathers service to exclude sensitive fields from responses and to pass only necessary options to CockroachDB.
// src/services/records/records.service.js
const { Service } = require('feathers-sequelize');
const { cockroachdb } = require('../../environment');
class SecureRecordsService extends Service {
async find(params) {
// Call super with sanitized query options
const result = await super.find({
...params,
// Ensure no API key is forwarded as a query option
query: {
...params.query,
$select: ['id', 'name', 'createdAt'],
$mask: { apiKey: '**REDACTED**' }
}
});
return result;
}
}
module.exports = function () {
const app = this;
app.use('/records', new SecureRecordsService({
Model: require('./records.model'),
paginate: { default: 10, max: 50 }
}));
const recordsService = app.service('records');
recordsService.hooks({
before: {
all: [
require('./hooks/sanitize-api-key'),
context => {
// Example: inject API key from secure env for backend use only
if (!context.params.query.api_key) {
context.params.query.api_key = cockroachdb.apiKey;
}
return context;
}
],
find: [],
get: [],
create: [],
update: [],
patch: [],
remove: []
},
after: {
all: [],
find: [],
get: [],
create: [],
update: [],
patch: [],
remove: []
},
error: {
all: [],
find: [],
get: [],
create: [],
update: [],
patch: [],
remove: []
}
});
};
4. Use parameterized queries and avoid dynamic SQL
When interacting with CockroachDB through an ORM or query builder, prefer parameterized inputs to prevent injection and accidental exposure of keys in logs.
// Example using a parameterized query pattern
const { Sequelize } = require('sequelize');
const sequelize = new Sequelize(cockroachdb.connectionString);
async function getRecordById(id) {
const record = await sequelize.query(
'SELECT id, name FROM records WHERE id = :id',
{ replacements: { id }, type: Sequelize.QueryTypes.SELECT }
);
return record;
}
These practices reduce the likelihood that API keys or CockroachDB credentials appear in logs, error messages, or client responses, aligning with Data Exposure and Input Validation checks.