Trust Misconfiguration Audit
The most common vulnerability in AI-generated code isn't SQL injection or XSS — it's trust misconfiguration. Code that assumes everything is fine. Open CORS, admin-level service accounts, raw input passed to shell commands. The AI optimizes for "make it work" with zero weight on "make it survivable in production."
## Key Points
- **All origins** (CORS `*`)
- **All users** (no authentication on endpoints)
- **All input** (no validation or sanitization)
- **All environments** (hardcoded dev credentials used in prod)
- **All permissions** (service accounts with admin access)
- **All network traffic** (no TLS enforcement, no rate limiting)
1. Search the entire codebase for patterns: `password=`, `secret=`, `api_key=`, `token=`, `sk_live`, `sk_test`, `AKIA` (AWS), `ghp_` (GitHub)
2. Check `.gitignore` includes: `.env`, `.env.local`, `.env.production`, `*.pem`, `*.key`, `serviceAccountKey.json`
3. Check git history: `git log --all -p | grep -i "password\|secret\|api_key"` — credentials removed from code may still be in history
4. Check CI/CD configs for hardcoded secrets (use platform secret management instead)
- SQL queries (parameterize instead)
- Shell commands (use safe APIs instead of `exec`)
## Quick Example
```javascript
app.use(cors()); // Allow all origins
// or
app.use(cors({ origin: '*' }));
```
```json
{
"serviceAccount": "my-app@project.iam.gserviceaccount.com",
"roles": ["roles/owner"]
}
```skilldb get vibe-coding-security-skills/trust-misconfiguration-auditFull skill: 320 linesTrust Misconfiguration Audit
The most common vulnerability in AI-generated code isn't SQL injection or XSS — it's trust misconfiguration. Code that assumes everything is fine. Open CORS, admin-level service accounts, raw input passed to shell commands. The AI optimizes for "make it work" with zero weight on "make it survivable in production."
This skill teaches you to systematically find and fix these trust assumptions before they become incidents.
What Are Trust Misconfigurations?
Trust misconfigurations occur when code implicitly trusts:
- All origins (CORS
*) - All users (no authentication on endpoints)
- All input (no validation or sanitization)
- All environments (hardcoded dev credentials used in prod)
- All permissions (service accounts with admin access)
- All network traffic (no TLS enforcement, no rate limiting)
These aren't bugs in the traditional sense. The code works. Tests pass. It runs on your machine. The vulnerability is invisible until someone exploits it.
The Audit Checklist
1. CORS Configuration
What AI typically generates:
app.use(cors()); // Allow all origins
// or
app.use(cors({ origin: '*' }));
What production needs:
const allowedOrigins = [
'https://yourdomain.com',
'https://app.yourdomain.com',
];
app.use(cors({
origin: (origin, callback) => {
// Allow requests with no origin (mobile apps, curl, etc.)
if (!origin) return callback(null, true);
if (allowedOrigins.includes(origin)) {
return callback(null, true);
}
return callback(new Error('CORS not allowed'), false);
},
credentials: true,
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization'],
}));
Audit question: Does any CORS configuration use * or allow all origins? Does it allow credentials with wildcard origins (browser will block this, but misconfigured proxies won't)?
2. Service Account Permissions
What AI typically generates:
{
"serviceAccount": "my-app@project.iam.gserviceaccount.com",
"roles": ["roles/owner"]
}
What production needs:
{
"serviceAccount": "my-app@project.iam.gserviceaccount.com",
"roles": [
"roles/cloudsql.client",
"roles/storage.objectViewer"
]
}
Audit question: Does any service account, IAM role, or database user have more permissions than the minimum required for its specific function? Can you list exactly which permissions each service account uses?
3. Hardcoded Credentials
What AI typically generates:
DB_URL = "postgresql://admin:supersecret@db.example.com:5432/myapp"
API_KEY = "sk_live_abc123def456"
JWT_SECRET = "my-jwt-secret-key"
What production needs:
import os
DB_URL = os.environ["DATABASE_URL"]
API_KEY = os.environ["API_KEY"]
JWT_SECRET = os.environ["JWT_SECRET"]
# Validate they exist at startup
for var in ["DATABASE_URL", "API_KEY", "JWT_SECRET"]:
if not os.environ.get(var):
raise RuntimeError(f"Required environment variable {var} is not set")
Audit steps:
- Search the entire codebase for patterns:
password=,secret=,api_key=,token=,sk_live,sk_test,AKIA(AWS),ghp_(GitHub) - Check
.gitignoreincludes:.env,.env.local,.env.production,*.pem,*.key,serviceAccountKey.json - Check git history:
git log --all -p | grep -i "password\|secret\|api_key"— credentials removed from code may still be in history - Check CI/CD configs for hardcoded secrets (use platform secret management instead)
4. Input Validation
What AI typically generates:
app.post('/search', (req, res) => {
const query = req.body.query;
const results = db.query(`SELECT * FROM products WHERE name LIKE '%${query}%'`);
res.json(results);
});
What production needs:
import { z } from 'zod';
const searchSchema = z.object({
query: z.string().min(1).max(200).trim(),
page: z.number().int().min(1).max(100).default(1),
limit: z.number().int().min(1).max(50).default(20),
});
app.post('/search', (req, res) => {
const parsed = searchSchema.safeParse(req.body);
if (!parsed.success) {
return res.status(400).json({ error: 'Invalid input', details: parsed.error.issues });
}
const { query, page, limit } = parsed.data;
const results = db.query(
'SELECT * FROM products WHERE name LIKE $1 LIMIT $2 OFFSET $3',
[`%${query}%`, limit, (page - 1) * limit]
);
res.json(results);
});
Audit question: Is any user input used directly in:
- SQL queries (parameterize instead)
- Shell commands (use safe APIs instead of
exec) - File paths (validate and sandbox)
- HTML output (escape or use a template engine)
- URL redirects (whitelist allowed destinations)
- Regular expressions (sanitize to prevent ReDoS)
5. Authentication & Authorization
What AI typically generates:
// "Protected" route that checks nothing
app.get('/api/admin/users', (req, res) => {
const users = db.getAll('users');
res.json(users);
});
What production needs:
function requireAuth(req, res, next) {
const token = req.headers.authorization?.replace('Bearer ', '');
if (!token) return res.status(401).json({ error: 'No token provided' });
try {
const payload = jwt.verify(token, process.env.JWT_SECRET);
req.user = payload;
next();
} catch {
return res.status(401).json({ error: 'Invalid token' });
}
}
function requireRole(role) {
return (req, res, next) => {
if (req.user.role !== role) {
return res.status(403).json({ error: 'Insufficient permissions' });
}
next();
};
}
app.get('/api/admin/users', requireAuth, requireRole('admin'), (req, res) => {
const users = db.getAll('users');
// Strip sensitive fields before returning
const safe = users.map(({ password, ...rest }) => rest);
res.json(safe);
});
Audit question: For every API endpoint, can you answer: Who can access this? What can they do? What data can they see? Is there middleware enforcing this, or is it just "assumed"?
6. Database Security
Common AI patterns to audit:
- Connection strings with admin credentials
- No connection pooling limits (DoS vector)
- No query timeouts (slow query = locked connection)
- Raw queries accepting user input
- No row-level security or tenant isolation
- Backups not encrypted or not configured
The fix:
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
max: 20, // Connection pool limit
idleTimeoutMillis: 30000, // Close idle connections
connectionTimeoutMillis: 5000, // Fail fast on connection issues
statement_timeout: 10000, // Kill queries running > 10s
ssl: process.env.NODE_ENV === 'production'
? { rejectUnauthorized: true }
: false,
});
7. Environment Leakage
What AI typically generates:
// Returns full error stack to client
app.use((err, req, res, next) => {
res.status(500).json({ error: err.message, stack: err.stack });
});
What production needs:
app.use((err, req, res, next) => {
// Log full error internally
console.error('Unhandled error:', err);
// Return safe error to client
res.status(500).json({
error: process.env.NODE_ENV === 'production'
? 'Internal server error'
: err.message
});
});
Audit: Search for stack, err.message, console.log(req), JSON.stringify(process.env), debug endpoints left enabled, and any response that might leak internal paths, versions, or configuration.
Running the Audit
Quick Automated Scan
# Search for common trust misconfigurations
echo "=== Hardcoded Secrets ==="
grep -rn "password\s*=\s*['\"]" --include="*.{js,ts,py,go,java,rb}" .
grep -rn "api_key\s*=\s*['\"]" --include="*.{js,ts,py,go,java,rb}" .
grep -rn "secret\s*=\s*['\"]" --include="*.{js,ts,py,go,java,rb}" .
grep -rn "sk_live\|sk_test\|AKIA\|ghp_\|gho_" .
echo "=== Open CORS ==="
grep -rn "cors()\|origin:\s*['\"\`]\*" --include="*.{js,ts}" .
echo "=== Shell Injection Vectors ==="
grep -rn "exec(\|execSync(\|spawn(" --include="*.{js,ts}" .
grep -rn "os\.system\|subprocess\.call\|subprocess\.run" --include="*.py" .
echo "=== Missing .gitignore entries ==="
for f in .env .env.local .env.production serviceAccountKey.json; do
grep -q "$f" .gitignore 2>/dev/null || echo "MISSING from .gitignore: $f"
done
echo "=== Admin/Owner Permissions ==="
grep -rn "roles/owner\|roles/editor\|AdministratorAccess\|root" --include="*.{json,yaml,yml,tf}" .
echo "=== Raw SQL ==="
grep -rn "query(\`\|query(f\"\|query('" --include="*.{js,ts,py}" .
Manual Review Priorities
- Authentication middleware — Is it applied to every protected route, or just some?
- Error handling — Do errors leak internal details to clients?
- File upload — Is file type validated? Is the storage sandboxed?
- Rate limiting — Does any public endpoint lack rate limiting?
- HTTPS — Is TLS enforced in production? Are there HTTP fallbacks?
- Dependency audit — Run
npm audit,pip audit, or equivalent. AI often picks outdated packages.
The "Before You Ship" Checklist
Before any AI-generated code goes to production:
- All credentials are in environment variables, not in code
-
.gitignorecovers all secret files - Git history has been checked for leaked secrets
- CORS is restricted to known origins
- All user input is validated and sanitized
- SQL queries use parameterized statements
- Service accounts follow least-privilege
- Authentication is enforced on every protected endpoint
- Error responses don't leak internal details
- Rate limiting is configured on public endpoints
- Database connections have pool limits and timeouts
- File uploads are type-checked and size-limited
- Dependencies have been audited for known vulnerabilities
- TLS is enforced in production
- Logging doesn't capture sensitive data (passwords, tokens, PII)
Why AI Gets This Wrong
AI coding assistants optimize for functional correctness. They make code that works. But security is about adversarial correctness — making code that works even when someone is actively trying to break it.
The AI has never been burned by a production incident. It hasn't stayed up until 3am rotating leaked credentials. It doesn't have the scar tissue that makes experienced developers automatically reach for parameterized queries and least-privilege service accounts.
That scar tissue is what this audit replaces. Run it on every AI-generated codebase before shipping. The 30 minutes it takes is cheaper than the incident it prevents.
Install this skill directly: skilldb add vibe-coding-security-skills