Type Confusion in Feathersjs with Cockroachdb
Type Confusion in Feathersjs with Cockroachdb — how this specific combination creates or exposes the vulnerability
Type confusion in a Feathersjs service that uses Cockroachdb typically arises when application code or an ORM layer does not enforce strict schema validation before constructing SQL queries. Feathersjs is framework-agnostic about data sources, so if a service handler trusts client-supplied type indicators (e.g., a type or kind field) to decide how to build a Cockroachdb query, an attacker can change that value to alter query behavior.
Consider a Feathersjs service that accepts a payload to create or lookup records. If the handler uses a conditional based on a field like recordType to decide which SQL expression to build, and that value is passed directly into query building without validation, an attacker can change recordType from normal to something that causes unintended table joins or column selections. In Cockroachdb, which uses PostgreSQL wire protocol and supports complex types and schemas, confusion between composite types, table names, or even JSON fields can lead to data leakage or unauthorized modification when the ORM or raw query misinterprets the intended structure.
For example, an attacker may supply a type value that references a system table or a view with broader privileges, causing the query to read or write data it should not. Because Cockroachdb enforces SQL semantics strictly, a malformed or unexpected type reference can either result in an error that leaks schema information or, worse, allow an attacker to pivot by exploiting weak type checks in the application layer. This is not a Cockroachdb bug; it is a consequence of insufficient validation in the Feathersjs service logic combined with Cockroachdb’s strict typing and schema awareness.
Real-world relevance includes misconfigurations where dynamic query building uses string concatenation or naive template interpolation. If a Feathersjs hook or service method builds a WHERE clause like WHERE type = '${userInput}' without sanitization, an input such as '; DROP TABLE IF EXISTS users; -- is less likely to succeed due to Cockroachdb’s parameterization expectations, but type confusion can still lead to privilege escalation via crafted composite type names or schema-qualified identifiers that bypass intended row-level restrictions.
To detect this during a scan, middleBrick runs checks that submit unauthenticated probes designed to observe how the API reacts to unexpected type indicators, observing whether the endpoint executes unintended logic or exposes data. Findings include insecure direct object references or missing property authorization when type-based conditions fail to constrain access appropriately.
Cockroachdb-Specific Remediation in Feathersjs — concrete code fixes
Remediation centers on strict validation, parameterized queries, and avoiding dynamic type-based routing in Feathersjs services. Below are concrete, realistic code examples for a Feathersjs service using a Cockroachdb data source via an ORM or direct client.
1. Use an enum-like constant map instead of raw user input
Define allowed types in your service and map user input to known safe values. This prevents type confusion by rejecting unexpected values early.
// src/services/records/records.class.js
const ALLOWED_RECORD_TYPES = new Set(['account', 'transaction', 'audit']);
class RecordsService {
constructor(client) {
this.client = client; // Cockroachdb client
}
async create(data) {
const { type, payload } = data;
if (!ALLOWED_RECORD_TYPES.has(type)) {
throw new Error('Invalid record type');
}
// Use parameterized query to avoid injection and type confusion
const result = await this.client.query(
'INSERT INTO records (record_type, data, created_at) VALUES ($1, $2, NOW()) RETURNING id',
[type, JSON.stringify(payload)]
);
return result.rows[0];
}
}
module.exports = function (app) {
const client = app.get('cockroachClient');
app.use('/records', new RecordsService(client));
};
2. Enforce schema and type checks in hooks
Feathersjs hooks can validate and sanitize before a query reaches Cockroachdb. This ensures that even if the client sends a malicious type, it is corrected or rejected before execution.
// src/hooks/validate-type.hook.js
module.exports = function validateTypeHook(options) {
return async context => {
const validTypes = ['account', 'transaction', 'audit'];
if (context.data && context.data.type && !validTypes.includes(context.data.type)) {
throw new Error('Invalid type supplied');
}
// Ensure type is explicitly set to a safe default if missing
if (context.data && !context.data.type) {
context.data.type = 'account';
}
return context;
};
};
// In your service configuration
app.use('/records', new RecordsService(client), {
hooks: {
before: {
all: [validateTypeHook()]
}
}
});
3. Parameterized queries with explicit schema qualification
When using raw SQL, always use placeholders and qualify table names with explicit schemas. Do not allow user input to dictate schema or table names.
const { Client } = require('pg'); // Cockroachdb compatible driver
const client = new Client({ connectionString: process.env.DATABASE_URL });
async function getRecordsByType(userSuppliedType) {
// Map to a known safe schema.table
const allowedTableMap = {
account: 'public.accounts',
transaction: 'public.transactions',
audit: 'public.audit_logs'
};
const table = allowedTableMap[userSuppliedType];
if (!table) {
throw new Error('Invalid type for table lookup');
}
const res = await client.query(
`SELECT id, data FROM ${table} WHERE owner_id = $1 AND archived = $2`,
[context.params.account.id, false]
);
return res.rows;
}
4. Avoid dynamic type-based routing in service methods
Do not write service methods that switch behavior based on a field value to decide which query to run. Instead, use explicit branches that are verified at compile time or via strict validation.
// Bad — prone to type confusion
async get(data) {
if (data.type === 'admin') {
return this.client.query('SELECT * FROM admin_records WHERE id = $1', [data.id]);
} else {
return this.client.query('SELECT * FROM user_records WHERE id = $1', [data.id]);
}
}
// Good — explicit and safe
async getById(id, requesterRole) {
const table = requesterRole === 'admin' ? 'admin_records' : 'user_records';
const result = await this.client.query(
`SELECT * FROM ${table} WHERE id = $1`,
[id]
);
return result.rows[0];
}
By combining these practices — strict enumerated types, hook-level validation, parameterized queries with schema-qualified table names, and avoiding dynamic type routing — you eliminate type confusion risks while maintaining compatibility with Cockroachdb’s SQL semantics. middleBrick can validate these protections by scanning your endpoints and confirming that type-based conditions do not lead to unintended data exposure or behavior.
Related CWEs: inputValidation
| CWE ID | Name | Severity |
|---|---|---|
| CWE-20 | Improper Input Validation | HIGH |
| CWE-22 | Path Traversal | HIGH |
| CWE-74 | Injection | CRITICAL |
| CWE-77 | Command Injection | CRITICAL |
| CWE-78 | OS Command Injection | CRITICAL |
| CWE-79 | Cross-site Scripting (XSS) | HIGH |
| CWE-89 | SQL Injection | CRITICAL |
| CWE-90 | LDAP Injection | HIGH |
| CWE-91 | XML Injection | HIGH |
| CWE-94 | Code Injection | CRITICAL |