Api Key Exposure in Express with Dynamodb
Api Key Exposure in Express with Dynamodb — how this specific combination creates or exposes the vulnerability
When an Express application uses AWS DynamoDB to manage secrets such as API keys, improper access patterns and server-side configuration can unintentionally expose those keys. DynamoDB stores data in tables; if table policies, IAM roles, or application logic allow overly permissive read access, an authenticated or unauthenticated API consumer may be able to enumerate or retrieve sensitive items that contain API keys.
Express routes that proxy requests to DynamoDB typically interact with the SDK to query or scan tables. If these endpoints are not carefully scoped, they may expose item metadata or full attribute values, including keys used for downstream service authentication. For example, a route like /keys/:service that fetches an item by partition key without validating the requester’s identity can disclose the stored key in the response. This becomes a cross-leak when the same API surface also exposes metadata or error messages that reveal table structure or key names.
Common patterns that increase risk include using administrative IAM credentials in the runtime environment, failing to enforce resource-based policies on the DynamoDB table, and returning raw DynamoDB JSON to clients without filtering sensitive attributes. Insecure serialization formats (e.g., exposing the DynamoDB AttributeValue format) can also aid an attacker in mapping item schemas. If the Express app is reachable without TLS or if logging captures full responses, an attacker can harvest API keys from logs or error traces.
Another vector involves DynamoDB Streams or Time to Live (TTL) configurations: if streams are enabled and consumed by an insecure downstream processor, API key updates can be replayed to unauthorized consumers. Similarly, misconfigured backup or export processes can leave snapshots accessible to broader identities than necessary.
Because middleBrick tests unauthenticated attack surfaces by default, endpoints that leak keys through verbose error messages or open CORS policies can be identified quickly. The scanner’s checks for Data Exposure and Authentication highlight cases where API keys are returned without proper authorization boundaries, and findings map to OWASP API Top 10 and SOC2 controls relevant to secret management.
Dynamodb-Specific Remediation in Express — concrete code fixes
Apply least privilege and strict input validation when your Express service accesses DynamoDB. Use IAM roles scoped to specific table actions and partition keys, and never return raw DynamoDB attribute values to API consumers. Instead, construct minimal, filtered responses that exclude sensitive fields.
Below are concrete, syntactically correct examples using the AWS SDK for JavaScript (v3) in an Express route. Ensure environment variables supply table names and that TLS is enforced in production.
Secure fetch by authenticated caller with field filtering
import { DynamoDBClient, GetItemCommand } from "@aws-sdk/client-dynamodb";
import { unmarshall } from "@aws-sdk/util-dynamodb";
import express from "express";
const app = express();
const client = new DynamoDBClient({ region: process.env.AWS_REGION });
app.get("/api/keys/:service", async (req, res) => {
const { service } = req.params;
// Validate input to prevent unexpected table access or key patterns
if (!/^[a-z0-9_-]+$/.test(service)) {
return res.status(400).json({ error: "invalid service name" });
}
const params = {
TableName: process.env.SECRETS_TABLE,
Key: {
pk: { S: `SERVICE#${service}` },
sk: { S: "apikey" }
},
// ExpressionAttributeNames can further limit exposed attribute names
ExpressionAttributeNames: { "#v": "value" },
ProjectionExpression: "#v"
};
try {
const command = new GetItemCommand(params);
const data = await client.send(command);
if (!data.Item) {
return res.status(404).json({ error: "not found" });
}
const item = unmarshall(data.Item);
// Return only the field you need; do not echo the full DynamoDB item
res.json({ apiKey: item.value });
} catch (err) {
// Avoid leaking stack traces or AWS details
console.error("Failed to fetch key", err);
res.status(500).json({ error: "internal error" });
}
});
app.listen(3000);
Scoped query with strict condition and selective return
import { DynamoDBClient, QueryCommand } from "@aws-sdk/client-dynamodb";
import { unmarshall } from "@aws-sdk/util-dynamodb";
import express from "express";
const app = express();
const client = new DynamoDBClient({ region: process.env.AWS_REGION });
app.get("/api/services/:team", async (req, res) => {
const { team } = req.params;
if (!/^[a-z0-9]+$/.test(team)) {
return res.status(400).json({ error: "invalid team" });
}
const params = {
TableName: process.env.SERVICES_TABLE,
IndexName: "gsi_team_keys",
KeyConditionExpression: "team = :team",
FilterExpression: "attribute_exists(keyId) AND keyStatus = :enabled",
ExpressionAttributeValues: {
":team": { S: team },
":enabled": { S: "ENABLED" }
},
// Select only non-sensitive attributes for the caller
ProjectionExpression: "keyId, endpoint"
};
try {
const command = new QueryCommand(params);
const data = await client.send(command);
const items = data.Items?.map((it) => unmarshall(it)) || [];
// Exclude key material; if clients need it, require an additional authenticated step
res.json({ services: items });
} catch (err) {
console.error("Query failed", err);
res.status(500).json({ error: "internal error" });
}
});
app.listen(3000);
Complement these code changes with DynamoDB best practices: enable encryption at rest, use VPC endpoints or private links when possible, and rotate keys outside the scope of the API response. middleBrick’s scans can verify that endpoints do not return sensitive attributes and that authentication checks are enforced; findings will reference Data Exposure and Authentication with remediation guidance tied to frameworks such as OWASP API Top 10 and SOC2.
Frequently Asked Questions
Can middleBrick detect API key leaks in Express endpoints backed by DynamoDB?
Does middleBrick provide a CLI to test these routes from the terminal?
middlebrick scan <url>. It returns JSON or text output and integrates easily into scripts and CI workflows.