Cors Wildcard in Sails
How Cors Wildcard Manifests in Sails
CORS wildcard misconfigurations in Sails applications create a particularly dangerous attack surface because Sails' default configuration can be overly permissive. The most common manifestation occurs when Sails applications use the Sails.js CORS hook with wildcard origins, allowing any domain to make cross-origin requests to your API.
The critical issue appears when Sails applications set allRoutes: true in their CORS configuration:
// config/cors.js
module.exports.cors = {
allRoutes: true, // This enables CORS on ALL routes
origin: '*', // This allows ANY origin
credentials: true // This allows credentials to be sent
};
This configuration creates a perfect storm: any website can make requests to your Sails API, and because credentials: true is enabled, browsers will include cookies and authentication headers. An attacker can then host a malicious site that makes requests to your Sails API on behalf of logged-in users.
The attack pattern typically unfolds like this:
- An authenticated user visits a malicious website
- The malicious site makes AJAX requests to your Sails API (CORS allows this)
- Browsers include the user's cookies (credentials are allowed)
- The malicious site can read the response data (CORS wildcard permits it)
This is particularly problematic in Sails because the framework's philosophy emphasizes convention over configuration, which can lead developers to accept default settings without understanding the security implications. The Sails CORS hook is enabled by default in many versions, and developers often don't realize they need to explicitly configure it.
Another Sails-specific manifestation occurs with Sails blueprints. When using Sails blueprints for CRUD operations with wildcard CORS, an attacker can exploit the automatic API endpoints:
// An attacker can create a malicious site that:
// 1. Lists all users via GET /user
// 2. Creates new records via POST /user
// 3. Updates existing records via PUT /user/:id
// 4. Deletes records via DELETE /user/:id
The combination of Sails blueprints + wildcard CORS effectively turns your API into a public data store that anyone can read from and write to, regardless of authentication status.
Sails-Specific Detection
Detecting CORS wildcard issues in Sails requires examining both configuration files and runtime behavior. Start by checking your Sails configuration:
# Check if CORS is enabled globally
grep -r "cors" config/ | grep -i "allRoutes\|origin"
# Look for wildcard origins
grep -r "origin.*\*" config/
# Check for credentials being enabled
grep -r "credentials.*true" config/
In Sails applications, the CORS configuration is typically found in config/cors.js. Look for these dangerous patterns:
// DANGEROUS: Allows all origins
origin: '*'
// DANGEROUS: Enables CORS on all routes
allRoutes: true
// DANGEROUS: Allows credentials with wildcard origins
credentials: true
middleBrick's scanner specifically detects these Sails CORS misconfigurations through runtime testing. When you scan a Sails API endpoint with middleBrick, it:
- Attempts cross-origin requests from different domains
- Checks if credentials are accepted from arbitrary origins
- Verifies if wildcard CORS headers are present in responses
- Tests blueprint endpoints for unintended exposure
The CLI command for scanning a Sails API is straightforward:
npm install -g middlebrick
middlebrick scan https://yourapi.com
middleBrick will report findings like:
CORS Wildcard Risk: HIGH
- Origin: * (allows all domains)
- Credentials: true (allows cookies/auth headers)
- Routes affected: All (allRoutes: true)
- Sails blueprints exposed: GET /user, POST /user, etc.
For automated detection in your CI/CD pipeline, use the middleBrick GitHub Action:
- name: Scan API Security
uses: middlebrick/middlebrick-action@v1
with:
url: https://staging.yourapp.com
fail-on-severity: high
This will automatically fail your build if CORS wildcard issues are detected, preventing insecure configurations from reaching production.
Sails-Specific Remediation
Fixing CORS wildcard issues in Sails requires a security-first approach to configuration. The most secure pattern is to explicitly define allowed origins and disable credentials unless absolutely necessary.
Here's the secure configuration for a typical Sails application:
// config/cors.js
module.exports.cors = {
allRoutes: false, // Disable CORS by default
origin: (origin, cb) => {
const allowedOrigins = [
'https://yourapp.com',
'https://admin.yourapp.com',
'https://partner.yourapp.com'
];
if (allowedOrigins.includes(origin)) {
cb(null, true);
} else {
cb(new Error('Not allowed by CORS'));
}
},
credentials: false, // Never use credentials with wildcard origins
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
headers: ['Content-Type', 'Authorization'],
exposedHeaders: ['X-Total-Count']
};
This configuration ensures that only your specified domains can access the API, and credentials are never sent to untrusted origins.
For Sails blueprints, you should explicitly disable CORS on blueprint routes and enable it only on specific controllers:
// config/blueprints.js
module.exports.blueprints = {
cors: false, // Disable CORS on all blueprints
// ... other blueprint settings
};
// api/controllers/UserController.js
module.exports = {
friendlyName: 'Get Users',
description: 'Returns a list of users.',
inputs: {
// ... input definitions
},
exits: {
success: {
description: 'OK.',
statusCode: 200,
headers: {
'Access-Control-Allow-Origin': 'https://yourapp.com',
'Access-Control-Allow-Credentials': 'false'
}
}
},
fn: async function (inputs, exits) {
// Your controller logic here
return exits.success({
users: await User.find()
});
}
};
For Sails applications using policies for authentication, combine CORS restrictions with proper authentication checks:
// api/policies/cors-and-auth.js
module.exports = async function (req, res, proceed) {
// First, check CORS origin
const allowedOrigins = ['https://yourapp.com'];
if (!allowedOrigins.includes(req.headers.origin)) {
return res.status(403).json({ error: 'CORS not allowed' });
}
// Then, check authentication
if (!req.session.userId) {
return res.status(401).json({ error: 'Not authenticated' });
}
return proceed();
};
Finally, test your remediation using middleBrick to verify the fixes:
middlebrick scan https://yourapp.com --check=cors
The scan should now report that wildcard CORS is no longer present, and your API is properly secured against cross-origin attacks.
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 |