Api Key Exposure in Strapi with Dynamodb
Api Key Exposure in Strapi with Dynamodb — how this specific combination creates or exposes the vulnerability
When Strapi uses DynamoDB as its data store, API key exposure can occur through misconfigured data models, overly permissive IAM policies, or insecure runtime handling of keys. Strapi stores configuration such as database connections and plugin settings, including credentials for external services, in JSON fields within DynamoDB tables. If these entries are readable by unauthenticated or low-privilege roles, an attacker who can invoke an unauthenticated endpoint may retrieve sensitive values through IDOR or BOLA flaws.
In this combination, the risk arises because DynamoDB does not enforce field-level permissions by default. A Strapi model that references an API key stored in a DynamoDB table may inadvertently expose the key if the service role used by DynamoDB has broad read permissions and the API endpoint does not enforce ownership or scope checks. Attackers can probe unauthenticated endpoints to enumerate records, then read entries that contain plaintext keys, especially when the table name or record structure is predictable.
Additionally, if Strapi logs or caches data from DynamoDB without redaction, keys can appear in logs or error messages that are exposed through information-disclosure endpoints. The scan categories Authentication, BOLA/IDOR, and Data Exposure are particularly relevant here: weak authentication allows enumeration, insecure record-level access control leads to IDOR, and missing redaction results in data exposure. Because middleBrick tests unauthenticated attack surfaces, it can identify endpoints that return sensitive configuration records, including API keys stored in DynamoDB, and map findings to frameworks such as OWASP API Top 10 A01 and A07.
An example pattern is a Strapi collection type that stores third-party service credentials in a DynamoDB attribute named meta.config.apiKey. If a route like /api/integrations/:integrationId returns the full integration record without verifying that the requesting context is authorized to view that integration, the API key is exposed. The DynamoDB scan findings from middleBrick will highlight this as a Data Exposure issue with high severity, providing remediation guidance to enforce authorization checks and avoid returning sensitive attributes.
middleBrick’s 12 security checks run in parallel and include specific Data Exposure and Authentication tests that surface these issues. Its OpenAPI/Swagger analysis resolves $ref definitions and cross-references spec structures with runtime responses, so if your spec references a DynamoDB-backed model that contains API keys, the scanner can flag mismatches between declared responses and actual data exposure. The tool does not fix or block; it detects and reports with prioritized findings and remediation guidance, helping you understand how to reduce exposure in your architecture.
Dynamodb-Specific Remediation in Strapi — concrete code fixes
To reduce API key exposure when using DynamoDB with Strapi, apply runtime checks, least-privilege IAM, and secure handling of sensitive fields. Below are concrete practices and code examples tailored to Strapi controllers and services that interact with DynamoDB.
1. Enforce ownership and scope checks in Strapi controllers. Before returning a record that references a DynamoDB-stored API key, verify that the requesting user or context is allowed to access it. In Strapi, you can add a check inside a custom controller to compare the authenticated entity with the record’s owner or tenant.
// src/api/integration/controllers/integration.js
'use strict';
module.exports = {
async findOne(ctx) {
const { id } = ctx.params;
const { user } = ctx.state;
if (!user) {
return ctx.unauthorized(null, 'Authentication required');
}
const record = await strapi.entityService.findOne('api::integration.integration', id, {
populate: ['owner', 'config'],
});
if (!record) {
return ctx.notFound();
}
// Scope check: ensure user can access this integration
const canAccess = record.owner && record.owner.id === user.id;
if (!canAccess) {
return ctx.forbidden(null, 'Access denied to this integration');
}
// Redact sensitive fields before sending response
const safeRecord = { ...record.toJSON ? record.toJSON() : record };
if (safeRecord.meta && safeRecord.meta.config) {
delete safeRecord.meta.config.apiKey;
}
return safeRecord;
},
};
This pattern ensures that even if a DynamoDB-backed model contains an apiKey attribute, it is removed from the response. The check uses Strapi’s entity service and relies on the authenticated context from Strapi’s auth middleware.
2. Apply least-privilege IAM policies for the DynamoDB role used by Strapi. Configure the IAM role or user that Strapi assumes to have only the necessary DynamoDB actions on the specific table and attributes. For example, allow dynamodb:GetItem and dynamodb:Query on the table, but deny access to attributes that are not needed at runtime.
3. Use DynamoDB condition expressions and attribute-level permissions where feasible. While DynamoDB does not support row-level security natively, you can encode ownership in the partition key (e.g., tenantId#userId) and use condition expressions in queries to ensure users only retrieve their own data.
// Example: Query with condition to enforce tenant ownership
const AWS = require('aws-sdk');
const dynamo = new AWS.DynamoDB.DocumentClient();
async function getTenantIntegration(tenantId, integrationId) {
const params = {
TableName: process.env.DYNAMODB_TABLE,
KeyConditionExpression: 'pk = :pk AND begins_with(sk, :sk)',
FilterExpression: 'integrationId = :integrationId',
ExpressionAttributeValues: {
':pk': `tenant#${tenantId}`,
':sk': `integration#${integrationId}`,
},
};
const result = await dynamo.query(params).promise();
return result.Items || [];
}
This query ensures that even if the table contains multiple tenants’ data, the condition on the partition key and sort key limits results to the tenant’s items, reducing the risk of IDOR. Combine this with field projection to return only non-sensitive attributes.
4. Redact sensitive fields in logs and error messages. Ensure that Strapi and any custom logging do not include API keys. Override error handlers to scrub DynamoDB responses before they are written to logs.
// src/middlewares/error-handler.js
module.exports = (config) => {
return async (ctx, next) => {
try {
await next();
} catch (err) {
const safeError = { ...err };
if (safeError.details && safeError.details.includes('apiKey')) {
safeError.details = safeError.details.replace(/apiKey[^,]*,/, 'apiKey:[redacted],');
}
ctx.throw(err.status || 500, safeError.message || 'Internal Server Error');
}
};
};
With these measures, the risk of API key exposure is reduced, and findings from middleBrick’s Data Exposure and BOLA/IDOR checks will show lower severity. The scanner will still detect misconfigurations, but your remediation will align with checks such as Authentication, Data Exposure, and Property Authorization.