Webhook Abuse in Feathersjs with Dynamodb
Webhook Abuse in Feathersjs with Dynamodb — how this specific combination creates or exposes the vulnerability
FeathersJS is a framework for creating JavaScript APIs with services that expose REST and real-time behavior. When using Dynamodb as the persistence layer, webhook configurations can introduce abuse risks if service methods accept untrusted input for endpoint configuration or event routing. Webhook abuse in this context refers to scenarios where an attacker influences how or where webhook events are delivered, potentially causing data exfiltration, information disclosure, or unauthorized actions.
The combination creates risk when a FeathersJS service intended to interact with Dynamodb exposes webhook settings through user-controlled data. For example, if a create or patch operation accepts a webhook_url field that is later used to send notifications, an attacker can supply any external endpoint, leading to server-side request forgery (SSRF) or data exposure. Because Dynamodb stores the configuration as item attributes, persisted malicious webhook URLs can repeatedly trigger outbound requests to attacker-controlled servers, bypassing network-level egress restrictions that assume only trusted endpoints are configured.
Additionally, webhook abuse can occur when event names or routing keys are derived from user input without strict allowlisting. An attacker may supply crafted event names that cause the service to trigger unintended workflows or invoke sensitive operations that interact with Dynamodb, such as administrative data exports or batch writes. The stateless nature of webhook delivery means each triggered event performs the configured action with the permissions of the service, which often includes broad read/write access to Dynamodb tables.
Another vector involves the use of webhook retries and error handling. If a FeathersJS service does not validate the target endpoint or response expectations, an attacker can induce repeated failed deliveries, leading to resource consumption or indirect denial-of-service conditions against downstream systems. Because Dynamodb does not natively enforce webhook policies, the application layer must enforce strict validation and scope controls.
To detect such patterns, middleBrick scans the unauthenticated attack surface and checks for overly permissive webhook configurations and exposed event routing logic. Findings include references to OWASP API Top 10 A01:2023 broken object level authorization and A05:2023 broken function level authorization, with remediation guidance focused on input validation, allowlisting, and secure delivery patterns.
Dynamodb-Specific Remediation in Feathersjs — concrete code fixes
Remediation centers on strict input validation, allowlisting, and isolating webhook configuration from user-controlled data. Below are concrete code examples for a FeathersJS service using Dynamodb that implement these controls.
1. Define a fixed webhook configuration schema and disallow user input
Do not accept webhook URLs or endpoints from client payloads. Instead, store configuration server-side and reference it by a fixed identifier.
// src/services/webhooks/hooks.js
const allowedWebhooks = {
orderCreated: 'https://internal.example.com/webhooks/order',
userSignedUp: 'https://internal.example.com/webhooks/user'
};
module.exports = function (app) {
const webhooks = app.get('webhooks');
return async context => {
const { eventName, data } = context.result; // event from your business logic
const url = allowedWebhooks[eventName];
if (!url) { return context; }
await fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ data, event: eventName })
});
return context;
};
};
2. Use a hardcoded endpoint with strict validation if dynamic routing is required
If you must derive routing from metadata, validate against a strict allowlist and never echo user input into the URL path or host.
// src/services/notifications/hooks.js
const ALLOWED_ORIGINS = new Set(['order-service', 'auth-service']);
module.exports = function (app) {
return async context => {
const { origin, changes } = context.result;
if (!ALLOWED_ORIGINS.has(origin)) {
throw new Error('Webhook origin not allowed');
}
// Safe: origin is validated, not used to build the URL
await app.service('webhook-delivery').create({
target: 'https://internal.example.com/webhook-endpoint',
payload: changes,
origin
});
return context;
};
};
3. Secure Dynamodb item writes that include routing metadata
When storing items that include routing keys, enforce server-side defaults and sanitize inputs to prevent injection into webhook-related attributes.
// src/services/events/hooks.js
module.exports = function (app) {
return async context => {
const data = context.data || {};
// Enforce server-side defaults; do not trust client-provided routing
const routingKey = data.routingKey && ALLOWED_ROUTING.has(data.routingKey)
? data.routingKey
: 'default-route';
// Explicitly set other attributes; do not forward arbitrary fields to Dynamodb
context.data = {
routingKey,
payload: data.payload,
createdAt: new Date().toISOString(),
status: 'pending'
};
return context;
};
};
// src/lib/allowed-routes.js
exports.ALLOWED_ROUTING = new Set(['email', 'sms', 'internal']);
4. Middleware and validation layer for incoming data
Add a hook that validates and removes any webhook-related fields from user input before they reach Dynamodb, preventing storage of malicious URLs.
// src/global-hooks/webhook-sanitization.js
module.exports = function (app) {
return async context => {
if (context.data && context.data.webhookUrl) {
// Reject any user-supplied webhook URL
delete context.data.webhookUrl;
}
// Optionally, replace with a safe default or server-side value
return context;
};
};
5. Integration with middleBrick for ongoing verification
Use the middleBrick CLI to validate that your endpoints do not expose webhook configuration in responses and that no user-controlled fields reach Dynamodb items used for routing. Run regular scans from terminal with middlebrick scan <url> to detect regressions.