Dns Rebinding in Feathersjs with Dynamodb
Dns Rebinding in Feathersjs with Dynamodb — how this specific combination creates or exposes the vulnerability
DNS Rebinding occurs when an attacker tricks a victim’s browser into resolving a domain to an internal IP address, bypassing same-origin policies. In a Feathersjs application that uses Dynamodb as a backend data store, this becomes relevant when the client-side code or API endpoints rely on host-based routing or service discovery that can be manipulated post-resolution.
Feathersjs typically exposes REST or Socket.io endpoints that may internally reference Dynamodb through the AWS SDK. If the service endpoint (e.g., a regional DynamoDB endpoint) is resolved at startup or via configuration, an attacker who can force a rebind to an internal AWS metadata service address (e.g., 169.254.169.254) might attempt to intercept or manipulate requests that include IAM credentials or instance metadata. While Feathersjs itself does not make AWS calls directly, the integration layer (e.g., a custom service file using the AWS SDK) can be invoked from client-side code if improperly exposed.
Consider a Feathersjs service that accepts a table parameter and forwards it to a DynamoDB operation. If an attacker can cause the client to resolve the API host to an internal address, they might probe internal endpoints via the client’s authenticated session. For example, a misconfigured CORS policy or a service that echoes the resolved host in error messages could aid the rebinding chain. The DynamoDB operations (e.g., get, query) executed with the caller’s credentials may expose sensitive data if the attacker can drive the selection of table name or key conditions through controlled input, turning a DNS Rebinding vector into an unauthorized data access path.
In practice, this specific combination is less about DNS Rebinding directly breaking DynamoDB, and more about how the Feathersjs service routes and parameters interact with the AWS SDK under a compromised network context. An attacker might use a malicious site to repeatedly resolve a domain to 127.0.0.1 or an AWS internal prefix, then use the victim’s active session to call a Feathersjs endpoint that performs a DynamoDB.GetItem on a sensitive table. Because the AWS SDK uses the region and credentials from the environment or shared config, the forged requests may be signed and authorized, leading to unintended operations or information disclosure.
To detect such risks, middleBrick scans the unauthenticated attack surface of a Feathersjs endpoint, including how hostnames and parameters influence AWS SDK behavior. Its LLM/AI Security checks look for prompt injection or data exfiltration attempts, while the Input Validation and Authorization checks flag unsafe consumption of user-supplied input that reaches DynamoDB operations.
Dynamodb-Specific Remediation in Feathersjs — concrete code fixes
Remediation centers on strict input validation, avoiding dynamic resolution of internal endpoints, and ensuring that DynamoDB operations are constrained to known-safe parameters. Below are concrete code examples for a Feathersjs service that safely interacts with DynamoDB using the AWS SDK for JavaScript v3.
First, define a service that does not expose internal hostnames and validates all inputs. Use parameterized commands and avoid constructing table names from user input. If dynamic table selection is necessary, use an allowlist.
// src/services/dynamodb-data/dynamodb-data.service.js
const { DynamoDBClient, GetItemCommand, QueryCommand } = require("@aws-sdk/client-dynamodb");
const { marshall, unmarshall } = require("@aws-sdk/util-dynamodb");
class DynamodbDataService {
constructor(options) {
this.client = new DynamoDBClient({ region: process.env.AWS_REGION || "us-east-1" });
this.allowedTables = new Set(["users_prod", "orders_live"]); // allowlist
}
async get(params) {
const { table, key } = params;
if (!this.allowedTables.has(table)) {
throw new Error("Table not authorized");
}
if (!key || !key.id) {
throw new Error("Invalid key");
}
const command = new GetItemCommand({
TableName: table,
Key: marshall(key)
});
const response = await this.client.send(command);
return response.Item ? unmarshall(response.Item) : null;
}
async search(params) {
const { table, indexName, partitionValue } = params;
if (!this.allowedTables.has(table)) {
throw new Error("Table not authorized");
}
const command = new QueryCommand({
TableName: table,
IndexName: indexName,
KeyConditionExpression: "pk = :pk",
ExpressionAttributeValues: marshall({ ":pk": partitionValue })
});
const response = await this.client.send(command);
return response.Items.map(unmarshall);
}
}
module.exports = function (app) {
const service = new DynamodbDataService();
app.use("/data", service);
app.service("/data").hooks({
before: {
all: [async context => {
// Ensure no internal host leakage in errors
context.params.raw = context.params.raw || {};
context.params.raw.customUserAgent = "middlebrick-safe";
return context;
}]
}
});
};This example avoids using the client’s hostname in any request and ensures that only pre-authorized tables are used. It also validates key structures before passing them to DynamoDB, mitigating injection via malformed keys.
Additionally, configure CORS strictly in your Feathersjs app to prevent unauthorized origins from leveraging authenticated sessions for rebinding attempts:
// src/app.js
const cors = require("@koa/cors");
app.use(cors({
origin: process.env.FEATHERS_CORS_ORIGIN || "https://your-trusted-domain.com",
credentials: true
}));Finally, in environments where the application may be deployed behind proxies or load balancers, ensure that headers like x-forwarded-host are not used to dynamically set service endpoints. Use fixed configuration for AWS regions and endpoints, and avoid logging or echoing resolved hostnames in error responses, which could aid rebinding or SSRF chains.