Auth Bypass in Strapi
How Auth Bypass Manifests in Strapi
Auth bypass in Strapi typically occurs through misconfigured role-based access control (RBAC) and improper permission assignments. The most common pattern involves developers granting overly permissive access to the public role or failing to properly restrict API endpoints.
Consider a typical Strapi content-type configuration where the find and findone actions are inadvertently exposed:
// config/policies/permissions.js (default Strapi config)
module.exports = {
settings: {
public: {
find: true, // ⚠️ Dangerous if content should be private
findone: true,
create: false,
update: false,
delete: false,
},
},
};
This configuration allows any unauthenticated user to retrieve records from protected endpoints. For a blog application, this might seem harmless, but for user data, financial records, or sensitive content, it's a critical vulnerability.
Another common Strapi auth bypass pattern involves custom controllers that skip authentication middleware:
// api/users/controllers/user.js
module.exports = {
async findPublicUsers(ctx) {
// ⚠️ No authentication check
return await strapi.services.users.find({
role: 'public'
});
},
};
Strapi's plugin system can also introduce auth bypass risks. The users-permissions plugin, if misconfigured, may allow registration without email verification or expose sensitive user data through improperly secured endpoints.
Dynamic route handling in Strapi can lead to auth bypass when developers use wildcard routes without proper access control:
// api/routes.js
module.exports = ({ strapi }) => {
return [
{
method: 'GET',
path: '/api/protected/*',
handler: async (ctx) => {
// ⚠️ Missing authentication middleware
return await strapi.query('protected-data').find({
slug: ctx.params['*'],
});
},
},
];
};
Version-specific vulnerabilities also matter. Strapi versions before 3.6.7 had issues with the users-permissions plugin where certain endpoints could be accessed without proper authentication tokens, particularly when using custom providers or OAuth configurations.
Strapi-Specific Detection
Detecting auth bypass in Strapi requires examining both configuration files and runtime behavior. Start with the RBAC configuration in config/policies/permissions.js and content-type permissions in the admin panel.
Manual detection checklist for Strapi auth bypass:
- Review
publicrole permissions for each content type - Check custom controllers for missing authentication checks
- Examine dynamic routes for unauthenticated access
- Verify plugin configurations, especially
users-permissions - Test API endpoints with and without authentication tokens
- Check for exposed admin endpoints
Automated detection with middleBrick reveals auth bypass through black-box scanning without requiring access credentials. The scanner tests each endpoint's authentication requirements by attempting requests with and without valid tokens, measuring response differences.
middleBrick specifically identifies Strapi auth bypass patterns:
{
"endpoint": "GET /api/articles",
"auth_bypass": true,
"severity": "high",
"remediation": "Restrict 'find' action for public role or implement authentication middleware",
"stapi_version": "3.6.8",
"vulnerable_path": "api/articles/controller.js"
}
The scanner detects when Strapi's default configurations expose sensitive endpoints. For example, if /api/users returns user data without authentication, middleBrick flags this as a critical auth bypass vulnerability.
middleBrick's LLM security module also tests for auth bypass in AI-powered Strapi plugins. If your Strapi instance includes AI features (like content generation or semantic search), the scanner tests for prompt injection attacks that could bypass authentication controls.
Continuous monitoring through middleBrick Pro alerts you when new auth bypass vulnerabilities are introduced during development, preventing these issues from reaching production.
Strapi-Specific Remediation
Remediating auth bypass in Strapi requires a systematic approach to RBAC configuration and authentication middleware implementation. Start with the most restrictive permissions and grant access only where explicitly needed.
Proper RBAC configuration for Strapi:
// config/policies/permissions.js
module.exports = {
settings: {
// Default: deny all, then explicitly allow
public: {
find: false,
findone: false,
create: false,
update: false,
delete: false,
},
authenticated: {
find: true, // Allow authenticated users to read
findone: true,
create: true, // Allow authenticated users to create
update: ['owner'], // Only owners can update their content
delete: ['owner'], // Only owners can delete their content
},
admin: {
find: true,
findone: true,
create: true,
update: true,
delete: true,
},
},
};
For custom controllers, always implement authentication checks:
// api/articles/controllers/articles.js
module.exports = {
async find(ctx) {
// ⚠️ Always verify authentication
if (!ctx.state.user) {
return ctx.unauthorized('Authentication required');
}
// Check permissions based on user role
if (ctx.state.user.role.name !== 'admin' &&
ctx.state.user.role.name !== 'authenticated') {
return ctx.unauthorized('Insufficient permissions');
}
return await strapi.services.articles.find(ctx.query);
},
async findPublicArticles(ctx) {
// Explicitly public endpoint - document why this is safe
return await strapi.services.articles.find({
published: true,
status: 'published'
});
},
};
Implement middleware for route protection:
// api/middleware/authCheck.js
module.exports = async (ctx, next) => {
const isPublicRoute = ctx.request.path.startsWith('/api/public/');
if (!isPublicRoute) {
const { authorization } = ctx.request.header;
if (!authorization) {
return ctx.unauthorized('Missing authentication token');
}
try {
const verified = await strapi.plugins['users-permissions'].services.jwt.verify(
authorization.split(' ')[1]
);
ctx.state.user = verified;
} catch (error) {
return ctx.unauthorized('Invalid authentication token');
}
}
await next();
};
Register middleware in config/middleware.js:
module.exports = {
http: {
middleware: {
authCheck: {
enabled: true,
priority: 1,
},
},
},
};
For Strapi plugins, verify OAuth and third-party provider configurations:
// extensions/users-permissions/config/policies.js
module.exports = {
settings: {
providers: {
google: {
enabled: true,
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
authorizationUrl: 'https://accounts.google.com/o/oauth2/auth',
// ⚠️ Ensure proper callback handling and token validation
callbackUrl: '${origin}/auth/google/callback',
},
},
},
};
After implementing these fixes, use middleBrick to verify that auth bypass vulnerabilities are resolved. The scanner will confirm that previously vulnerable endpoints now require proper authentication and that no unintended data exposure exists.
Related CWEs: authentication
| CWE ID | Name | Severity |
|---|---|---|
| CWE-287 | Improper Authentication | CRITICAL |
| CWE-306 | Missing Authentication for Critical Function | CRITICAL |
| CWE-307 | Brute Force | HIGH |
| CWE-308 | Single-Factor Authentication | MEDIUM |
| CWE-309 | Use of Password System for Primary Authentication | MEDIUM |
| CWE-347 | Improper Verification of Cryptographic Signature | HIGH |
| CWE-384 | Session Fixation | HIGH |
| CWE-521 | Weak Password Requirements | MEDIUM |
| CWE-613 | Insufficient Session Expiration | MEDIUM |
| CWE-640 | Weak Password Recovery | HIGH |