Out Of Bounds Write in Feathersjs with Basic Auth
Out Of Bounds Write in Feathersjs with Basic Auth — how this specific combination creates or exposes the vulnerability
An Out Of Bounds Write occurs when an API accepts input that causes a service to write data outside intended memory or buffer boundaries. In FeathersJS, this typically manifests through unsafe dynamic assignment or unchecked array/slice operations when processing payloads. When Basic Auth is used, the authentication layer supplies user identity via headers, but does not inherently validate or constrain the structure or size of the request body. This creates a scenario where authenticated (or unauthenticated, if the endpoint is exposed) requests can supply crafted payloads that exploit unchecked numeric indices, string offsets, or buffer-length miscalculations in service logic or underlying libraries.
FeathersJS services often rely on generic hooks and transports (e.g., REST or Socket.io) that merge params.query, params.body, and runtime configuration. If a developer binds incoming data directly to a model or in-memory structure without validating length, type, or bounds, an attacker can provide values that shift write positions beyond allocated memory regions. For example, numeric fields used as array indices or pagination cursors may be coerced into large integers, causing writes to adjacent memory. Because Basic Auth headers are parsed before body validation, an attacker may leverage authenticated sessions to probe endpoints for unchecked mutation operations, increasing the likelihood of successful exploitation in microservice architectures where services chain multiple Feathers hooks.
Consider a Feathers service that accepts a payload specifying an index and a value to update an array stored in process memory or a temporary buffer. Without explicit bounds checks, an attacker authenticated via Basic Auth can supply an index beyond the allocated array length, triggering an out-of-bounds write. In runtime environments, this may lead to corrupted state, unexpected behavior, or potential code execution depending on the language runtime and memory protections. The combination of Basic Auth (which may provide a false sense of access control) and unchecked mutation endpoints amplifies risk because developers might assume authentication equates to safe input handling.
OpenAPI/Swagger specifications can inadvertently encourage these issues when definitions lack explicit constraints on numeric ranges or string lengths. If an endpoint definition describes an integer parameter without minimum/maximum limits, runtime values can overflow fixed buffers. middleBrick’s specification analysis correlates such definitions with runtime behavior, flagging endpoints where user-controlled data influences memory-adjacent operations. This is particularly relevant for endpoints using Basic Auth, where authentication correctness is separated from input validation responsibilities. Attack patterns like CVE-2021-23337, which involved boundary violations in web frameworks, illustrate how unchecked indices enable write primitives. In FeathersJS, similar patterns emerge when services perform direct array mutations or interact with native addons that do not validate bounds.
To detect this class of issues, scanning should examine hooks that perform mutations (e.g., create, update, patch) and verify that all indices, lengths, and offsets are validated against known limits. Payloads that include large integers, negative values, or deeply nested structures should be tested for out-of-bounds behavior. middleBrick’s checks for Input Validation and Unsafe Consumption are designed to surface these risks by correlating spec definitions with observed runtime behavior, including scenarios where Basic Auth headers are present but input constraints are missing.
Basic Auth-Specific Remediation in Feathersjs — concrete code fixes
Remediation focuses on validating and sanitizing all user-supplied data before it influences memory operations, regardless of authentication method. With Basic Auth, you must ensure that identity extraction does not bypass input validation. Below are concrete code examples demonstrating secure practices in FeathersJS.
Example 1: Validating array indices with explicit bounds
Ensure numeric indices are within allowed ranges before using them to mutate arrays. Use a validation hook that checks min/max values and rejects malformed payloads.
// src/hooks/validate-index.hooks.js
const { BadRequest } = require('@feathersjs/errors');
module.exports = function validateIndex(options = {}) {
return async context => {
const { index, value } = context.data || {};
const MAX_INDEX = 1024; // Define a safe upper bound
if (typeof index !== 'number' || !Number.isInteger(index) || index < 0 || index >= MAX_INDEX) {
throw new BadRequest('Invalid index: must be an integer between 0 and 1023');
}
// Proceed safely
if (!context.app.get('internalBuffer')) {
context.app.set('internalBuffer', new Array(MAX_INDEX).fill(null));
}
const buffer = context.app.get('internalBuffer');
buffer[index] = value; // Safe write within bounds
context.data = { index, value };
return context;
};
};
Example 2: Using Feathers validation with custom checks
Leverage feathers-hooks-common validators to enforce constraints on payload fields. Combine with Basic Auth hooks to ensure identity and data integrity are independently verified.
// src/hooks/validate-payload.hooks.js
const { iff, isProvider, preventChanges } = require('feathers-hooks-common');
const { BadRequest } = require('@feathersjs/errors');
const validateArrayPayload = () => async context => {
const data = context.data || {};
if (data.items && Array.isArray(data.items)) {
if (data.items.length === 0 || data.items.length > 500) {
throw new BadRequest('items must contain between 1 and 500 elements');
}
for (const item of data.items) {
if (typeof item.id !== 'number' || item.id < 0 || item.id >= 10000) {
throw new BadRequest('item.id must be a non-negative integer less than 10000');
}
}
}
return context;
};
module.exports = {
before: {
all: [iff(isProvider('external'), preventChanges(['internalId']))],
find: [validateArrayPayload()],
create: [validateArrayPayload()]
}
};
Example 3: Securing Basic Auth integration with explicit checks
Basic Auth should be handled by a dedicated hook that extracts credentials without affecting body validation. Ensure hooks run in the correct order: authentication first, then input validation.
// src/hooks/basic-auth.hooks.js
const { BadRequest } = require('@feathersjs/errors');
const { lookup } = require('feathers-authentication-hooks');
module.exports = function basicAuthHook(options) {
return async context => {
const authHeader = context.headers.authorization || '';
if (!authHeader.startsWith('Basic ')) {
throw new BadRequest('Unauthorized: Basic Auth header required');
}
const base64 = authHeader.split(' ')[1];
const decoded = Buffer.from(base64, 'base64').toString('utf-8');
const [username, password] = decoded.split(':');
// Validate credentials (replace with your user verification logic)
if (!username || !password || username !== 'admin' || password !== 'secure') {
throw new BadRequest('Invalid credentials');
}
// Attach identity to context for downstream hooks
context.params.user = { username };
return context;
};
};
Example 4: Applying hooks to a Feathers service
Compose your service with validation and authentication hooks to enforce bounds and proper credential handling.
// src/services/array-service/array-service.class.js
const { Service } = require('feathersjs');
const { iff, isProvider } = require('feathers-hooks-common');
const validateIndex = require('./hooks/validate-index.hooks');
const basicAuthHook = require('./hooks/basic-auth.hooks');
const validatePayload = require('./hooks/validate-payload.hooks');
class ArrayService extends Service {
create(data, params) {
// Ensure bounds checks are enforced via hooks
return super.create(data, params);
}
update(id, data, params) {
return super.update(id, data, params);
}
}
module.exports = function initService() {
const app = this;
const service = new ArrayService({
name: 'array',
async id(value) { return value.id; }
});
app.use('/array', service);
service.hooks([
{ before: { all: [basicAuthHook(), validatePayload()] } },
{ before: { create: [validateIndex()], update: [validateIndex()] } },
{ after: [] }
]);
};
These examples illustrate how to combine Basic Auth identity handling with strict input validation to prevent out-of-bounds writes. Always define explicit limits for numeric indices, array sizes, and offsets. Validate on both client and server sides, and use middleware to enforce constraints before mutations occur. middleBrick’s scans can help identify endpoints where such validation is missing, particularly in OpenAPI specs where range constraints are not defined.