Api Key Exposure in Strapi with Api Keys
Api Key Exposure in Strapi with Api Keys — how this specific combination creates or exposes the vulnerability
Strapi is a headless CMS that supports API keys as an authorization mechanism for its GraphQL and REST endpoints. When API keys are used without strict scoping, leakage, or misuse, they can lead to unauthorized access to content and configuration. In a typical Strapi deployment, API keys are created in the Settings → API Tokens section and intended to limit permissions to specific content types and actions. However, developers sometimes expose these keys in client-side JavaScript, public repositories, or logs, which allows an unauthenticated attacker to use them directly.
Because middleBrick performs unauthenticated scans, it can detect exposed API keys in error messages, source code comments, or open API documentation. One common pattern is a misconfigured CORS rule that permits any origin to call a Strapi endpoint using an API key. An attacker can extract the key from network traffic or a public repo and then reuse it to call /graphql or /api routes. For example, a key intended only for reading articles might be used to attempt mutations if the associated role permissions are not tightly restricted.
During the scan, middleBrick checks whether API keys are referenced in insecure contexts. This includes detection of keys in client-side bundles via static analysis of JavaScript responses and detection of verbose error messages that reveal key identifiers. One real-world indicator is a 403 response that includes a message such as Invalid API key or Token expired, which confirms the presence of key-based authentication. Because Strapi’s GraphQL endpoint often exposes introspection by default, an exposed key can also allow an attacker to explore available queries and mutations, escalating the risk from information disclosure to data manipulation.
Another relevant risk pattern involves the combination of API keys and overly permissive Content-Types or Upload permissions. If an API key has write access to uploads, an attacker could push malicious assets or inject executable content. middleBrick tests for BFLA and Privilege Escalation by attempting operations that exceed expected read-only usage. For instance, a key scoped to content-type articles might be probed for create, update, or delete actions. The scanner also checks for missing or weak rate limiting on key-authorized endpoints, which could enable credential stuffing or brute-force attempts against valid keys.
SSRF is another concern when Strapi runs in cloud environments and API keys have metadata or instance credentials attached. middleBrick includes SSRF checks that attempt to make the backend call internal endpoints using the key context. Data Exposure findings may surface if key-authorized endpoints return sensitive content such as user emails or role identifiers in responses that should be restricted. middleBrick’s checks align with OWASP API Top 10:2023 A01 (Broken Object Level Authorization) and A02 (Broken Authentication), as weak scoping of API keys can enable horizontal or vertical privilege escalation.
Encryption and Transport checks performed by middleBrick verify whether API keys are transmitted over non-TLS channels or logged insecurely. If Strapi is served over HTTP or if keys are embedded in query strings without HTTPS, the scanner flags Data Exposure and Encryption findings. Remediation guidance includes enforcing HTTPS, rotating exposed keys, and narrowing permissions using Strapi roles and policies to follow least privilege.
Api Keys-Specific Remediation in Strapi — concrete code fixes
Remediation focuses on reducing the attack surface of API keys in Strapi by tightening permissions, enforcing transport security, and avoiding client-side exposure. Below are concrete steps and code examples that you can apply directly in Strapi projects.
1. Restrict API key permissions with roles and policies
Create a dedicated role for each integration and assign only the required permissions. For example, a read-only key for a public GraphQL endpoint should not have create, update, or delete rights. In Strapi admin, navigate to Settings → Roles & Permissions and define granular permissions per content type.
2. Use environment variables for keys and avoid hardcoding
// config/plugins.js or server/config/server.js
module.exports = ({ env }) => ({
upload: {
config: {
provider: env('UPLOAD_PROVIDER', 'local'),
providerOptions: env('PROVIDER_OPTIONS', null) ? JSON.parse(env('PROVIDER_OPTIONS')) : {},
},
},
apiKey: env('STRAPI_API_KEY'), // store securely, do not commit
});
3. Require API keys only on specific routes
Instead of applying a key globally, use custom routes with explicit policies. Create a policy that checks for a valid key before allowing access.
Create a policy: src/policies/require-api-key.js
module.exports = async (ctx, next) =>
{
const providedKey = ctx.request.header['x-api-key'];
const expectedKey = process.env.STRAPI_API_KEY;
if (!providedKey || providedKey !== expectedKey) {
return ctx.unauthorized({ message: 'Invalid API key' });
}
await next();
};
Apply the policy in src/policies/role.js or routes config
// In src/routes/catalog.js or routes config
module.exports = {
routes: [
{
method: 'GET',
path: '/articles',
handler: 'article.find',
config: {
policies: ['path/to/require-api-key'],
scopes: ['read::articles'],
},
},
{
method: 'POST',
path: '/articles',
handler: 'article.create',
config: {
policies: ['path/to/require-api-key'],
scopes: ['create::articles'],
},
},
],
};
4. Enforce HTTPS and secure transport
Ensure Strapi is served over HTTPS and that API keys are never transmitted in URLs. Configure your reverse proxy or load balancer to terminate TLS and set HTTP Strict Transport Security (HSTS).
5. Rotate keys and audit usage
Regularly rotate keys and monitor access logs. In Strapi, you can revoke and recreate tokens from Settings → API Tokens. Combine this with environment-based keys so that compromised keys can be rotated quickly without redeploying code.
6. Disable unnecessary introspection on GraphQL
If your use case does not require schema introspection in production, disable it to reduce exposure of queries and mutations that could be leveraged with an exposed key.
// src/graphql/config.js
module.exports = {
endpoint: '/graphql',
playground: false,
apolloServer: {
introspection: true, // set to false in production
subscriptions: false,
},
};