Data Exposure in Strapi with Bearer Tokens
Data Exposure in Strapi with Bearer Tokens — how this specific combination creates or exposes the vulnerability
Strapi is a headless CMS that often exposes REST and GraphQL endpoints. When endpoints rely on Bearer token authentication implemented incompletely, data exposure can occur in at least three dimensions: authentication bypass, authorization flaws, and insecure transmission or storage.
First, authentication bypass can happen if the API accepts a Bearer token but does not enforce token validation on certain routes. For example, an endpoint like /api/articles might check for the presence of an Authorization header but skip verifying token scope or validity, allowing unauthenticated requests to receive sensitive data such as draft entries or unpublished content.
Second, authorization flaws (BOLA/IDOR) can amplify data exposure when Bearer tokens do not enforce tenant or user boundaries. A token issued to one user could be reused to access another user’s data if the backend only checks that a valid token exists, without confirming that the resource belongs to the token’s subject. This can lead to horizontal privilege escalation where one user views or modifies another user’s records.
Third, insecure transmission or storage of Bearer tokens creates exposure. If tokens are transmitted over non-TLS channels, they can be intercepted. Additionally, if Strapi logs Authorization headers or stores tokens in browser-accessible locations (such as local storage or insecure cookies), tokens may be exfiltrated via XSS or log scraping. Even when TLS is used, weak token entropy or lack of rotation increases the risk that a stolen token can be used to expose sensitive data across the API.
These three dimensions—authentication bypass, authorization flaws, and transmission/storage weaknesses—interact in Strapi deployments to create data exposure scenarios. A scanner that tests unauthenticated attack surfaces and inspects OpenAPI specs can surface these risks by identifying endpoints that accept Bearer tokens without proper validation, scope checks, or tenant isolation, and by correlating findings with insecure transport or storage practices.
Bearer Tokens-Specific Remediation in Strapi — concrete code fixes
Remediation focuses on strict token validation, scope and tenant checks, and secure handling of tokens in both transit and storage. Below are concrete code examples and configuration steps.
1. Enforce Bearer token validation on every request
Ensure Strapi middleware validates the token on each request and rejects malformed or missing tokens. In a custom middleware (e.g., src/middlewares/auth.js), validate the token before proceeding:
// src/middlewares/auth.js
module.exports = (config, { strapi }) => {
return async (ctx, next) => {
const auth = ctx.request.header.authorization || '';
const token = auth.startsWith('Bearer ') ? auth.slice(7) : null;
if (!token) {
ctx.status = 401;
ctx.body = { error: 'Unauthorized', message: 'Missing Bearer token' };
return;
}
try {
// Replace with your actual token verification logic
const payload = await strapi.plugin('auth').service('jwt').verify(token);
ctx.state.user = payload;
await next();
} catch (err) {
ctx.status = 401;
ctx.body = { error: 'Unauthorized', message: 'Invalid Bearer token' };
}
};
};
Register this middleware in config/middlewares.js so it runs before routes that expose sensitive content.
2. Enforce scope and tenant checks in controllers
After verifying the token, confirm that the token’s scope or tenant matches the requested resource. For example, in an articles controller, validate ownership or tenant ID:
// src/api/article/controllers/article.js
module.exports = {
async find(ctx) {
const user = ctx.state.user;
if (!user || !user.scope) {
return ctx.unauthorized('Insufficient scope');
}
// Assuming tenantId is part of the token and articles are scoped to tenant
const where = { tenantId: user.scope.tenantId };
// Optionally restrict by user-specific permissions
if (user.scope.role !== 'admin') {
where.published = true; // only published for non-admins
}
const articles = await strapi.db.query('api::article.article').findMany({ where });
return articles;
},
};
This prevents horizontal IDOR by ensuring users only access data within their tenant or scope, even when a valid Bearer token is presented.
3. Secure token transmission and storage
Always require HTTPS for API endpoints and set secure cookie attributes if storing tokens server-side. In Strapi’s server configuration, enforce strict transport security and avoid logging Authorization headers:
// config/server.js
module.exports = {
settings: {
host: '0.0.0.0',
port: 1337,
admin: {
autoOpen: false,
},
https: {
key: '/path/to/key.pem',
cert: '/path/to/cert.pem',
},
security: {
contentSecurityPolicy: {
useDefaults: true,
directives: {
'connect-src': ["'self'", 'https:'],
'img-src': ["'self'", 'data:', 'https:'],
'media-src': ["'self'", 'https:'],
'script-src': ["'self'", 'cdn.jsdelivr.net', 'https:'],
'style-src': ["'self'", 'https:'],
},
},
},
},
};
On the client side, avoid storing Bearer tokens in local storage. Use short-lived tokens and refresh token rotations to reduce the impact of token leakage.
4. Validate and sanitize inputs to reduce injection risks
Even when Bearer tokens are handled correctly, input validation remains essential to prevent SSRF or injection that could lead to data exposure. Use Strapi’s built-in validation or a library to sanitize query parameters and payloads:
// Example validation in a custom controller
const sanitizeEntity = require('strapi-utils/lib/sanitize-entity');
module.exports = {
async find(ctx) {
const { page = 1, pageSize = 10, q = '' } = ctx.query;
// Validate and sanitize inputs
const safeQ = q.replace(/[^a-zA-Z0-9 _-]/g, '').substring(0, 100);
const where = safeQ ? { title: { $contains: safeQ } } : {};
const [data, meta] = await strapi.db.query('api::article.article').findManyAndCount({
where,
pagination: { page: Number(page), pageSize: Number(pageSize) },
});
const entities = data.map(entity => sanitizeEntity(entity, { model: 'api::article.article' }));
return entities;
},
};
Related CWEs: dataExposure
| CWE ID | Name | Severity |
|---|---|---|
| CWE-200 | Exposure of Sensitive Information | HIGH |
| CWE-209 | Error Information Disclosure | MEDIUM |
| CWE-213 | Exposure of Sensitive Information Due to Incompatible Policies | HIGH |
| CWE-215 | Insertion of Sensitive Information Into Debugging Code | MEDIUM |
| CWE-312 | Cleartext Storage of Sensitive Information | HIGH |
| CWE-359 | Exposure of Private Personal Information (PII) | HIGH |
| CWE-522 | Insufficiently Protected Credentials | CRITICAL |
| CWE-532 | Insertion of Sensitive Information into Log File | MEDIUM |
| CWE-538 | Insertion of Sensitive Information into Externally-Accessible File | HIGH |
| CWE-540 | Inclusion of Sensitive Information in Source Code | HIGH |