Rate Limiting Bypass in Feathersjs with Basic Auth
Rate Limiting Bypass in Feathersjs with Basic Auth — how this specific combination creates or exposes the vulnerability
Feathersjs is a framework for building REST and SocketJS APIs. By default, Feathers does not enforce global rate limits on endpoints. When Basic Auth is used, credentials are typically passed via the Authorization header as Basic base64(username:password). A common misconfiguration is applying rate limiting only to unauthenticated routes or to routes before the authentication handler runs. If the rate limiting middleware is placed after the authentication middleware, or is omitted for authenticated paths, an attacker who knows or guesses a valid Basic Auth credential can reuse that credential across many requests, effectively bypassing intended rate limits because the request is already authenticated and may be processed by a less-restricted handler.
This combination exposes issues such as credential enumeration and brute-force attacks. Because Basic Auth is static per user, an attacker can rotate through stolen credentials or test known accounts without being throttled if the rate limiter is not applied at the endpoint or service layer. Additionally, Feathers services can expose nested routes or hooks that do not inherit global limits. If an authenticated route has no explicit limit, or if limits are applied only to specific HTTP methods (e.g., POST but not GET), an attacker can perform excessive GET requests to data retrieval endpoints, leading to data exposure and potential account takeover.
An example misconfiguration in Feathers might define an authentication hook but omit a service-specific rate limit:
const authentication = require('@feathersjs/authentication');
const hooks = require('feathers-authentication/hooks');
app.configure(authentication({
entity: 'user',
service: 'users',
secret: 'supersecret'
}));
app.use('/messages', createService());
// Missing global or service-level rate limiter
app.use('/messages', require('./messages'));
In this setup, if /messages is protected by Basic Auth via a hook but no rate limiter is applied, an attacker with valid credentials can send high-volume requests to enumerate messages or trigger side effects, such as logging sensitive data or causing denial through resource exhaustion. The vulnerability is not in Basic Auth itself, but in the placement and scope of rate limiting relative to authentication and service routes.
Another scenario involves socket endpoints. Feathers supports real-time communication via sockets, and if socket services do not implement rate limits or if authentication on sockets is handled separately, an authenticated socket connection may bypass REST-level throttling. This illustrates the importance of applying controls consistently across transport layers.
To detect such bypasses, scanning should validate that authenticated and unauthenticated paths share consistent rate-limiting policies, inspect middleware ordering, and confirm that nested or socket services inherit appropriate controls. Findings typically map to OWASP API Top 10 API4:2023 — Injection (in the context of data exposure) and API2:2023 — Broken Authentication when enumeration is possible, and to PCI-DSS requirements around access control and logging.
Basic Auth-Specific Remediation in Feathersjs — concrete code fixes
Remediation centers on enforcing rate limits at the service or global level, ensuring they run before or alongside authentication, and avoiding exemptions for authenticated routes. Use a dedicated rate-limiting library and apply it consistently.
1. Apply a global rate limiter before authentication so that unauthenticated and authenticated requests are both subject to limits. Example using express-rate-limit with Feathers:
const rateLimit = require('express-rate-limit');
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // limit each IP to 100 requests per windowMs
standardHeaders: true,
legacyHeaders: false,
});
app.use(limiter);
app.configure(authentication({ /* options */ }));
2. Apply rate limits directly to Feathers services using hooks. This ensures limits are enforced per-service and can vary by method:
const { iff, isProvider } = require('feathers-hooks-common');
const rateLimit = require('feathers-rate-limit');
app.use('/messages', createService({
before: {
all: [
iff(isProvider('external'), rateLimit({
period: 60000,
max: 60,
message: 'Too many requests'
}))
]
}
}));
3. When using Basic Auth, ensure credentials are not reused across users to reduce blast radius. Rotate secrets and avoid embedding credentials in client-side code. Example of a secure Basic Auth setup:
const authentication = require('@feathersjs/authentication');
const basic = require('@feathersjs/authentication-basic');
app.configure(authentication({
entity: 'user',
service: 'users',
secret: processAUTH_SECRET
}));
app.configure(basic());
4. Combine rate limiting with validation and filtering to reduce load and exposure. For example, restrict query parameters and avoid returning large data sets without pagination:
app.use('/messages', createService({
paginate: {
default: 10,
max: 25
},
hooks: {
before: {
all: [
require('feathers-authentication').restrictToAuthenticated(),
(context) => {
if (context.params.query && context.params.query.search) {
// Validate and sanitize input to prevent abuse
}
return context;
}
]
}
}
}));
These steps ensure that rate limiting is applied uniformly, authentication does not create implicit exceptions, and Feathers services remain resilient against brute-force and enumeration attacks.
Related CWEs: resourceConsumption
| CWE ID | Name | Severity |
|---|---|---|
| CWE-400 | Uncontrolled Resource Consumption | HIGH |
| CWE-770 | Allocation of Resources Without Limits | MEDIUM |
| CWE-799 | Improper Control of Interaction Frequency | MEDIUM |
| CWE-835 | Infinite Loop | HIGH |
| CWE-1050 | Excessive Platform Resource Consumption | MEDIUM |