From latestaiagents
OWASP A06 - Security Misconfiguration Detection. Use this skill when configuring servers, frameworks, cloud services, or deploying applications. Activate when: server config, nginx config, apache config, CORS, headers, debug mode, default credentials, error messages, directory listing, cloud security, S3 bucket, environment variables.
npx claudepluginhub latestaiagents/agent-skills --plugin skills-authoringThis skill uses the workspace's default tool permissions.
**Detect and fix insecure default configurations, missing security headers, exposed debug info, and cloud misconfigurations.**
Detects security misconfigurations like permissive CORS, production debug modes, missing security headers, wildcard hosts, and default credentials in server configs and deployments.
Audits IaC templates (Terraform/CloudFormation), app configs, Docker/Kubernetes manifests, and web server settings for security misconfigurations per OWASP and CIS benchmarks.
Detects security misconfigurations like enabled debug modes, default credentials, missing security headers, exposed endpoints, and TLS issues using grep patterns in Python/Django/Flask, Java/Spring, PHP/Laravel, Go/Gin, Node.js apps.
Share bugs, ideas, or general feedback.
Detect and fix insecure default configurations, missing security headers, exposed debug info, and cloud misconfigurations.
| Issue | Risk | Impact |
|---|---|---|
| Debug mode enabled | HIGH | Information disclosure |
| Default credentials | CRITICAL | Full system compromise |
| Missing security headers | MEDIUM | XSS, clickjacking |
| Directory listing | MEDIUM | Information disclosure |
| Verbose error messages | MEDIUM | Attack surface exposure |
| Open cloud storage | CRITICAL | Data breach |
| Unnecessary services | MEDIUM | Increased attack surface |
// VULNERABLE - Debug mode enabled
app.set('env', 'development');
DEBUG=* node app.js
// VULNERABLE - Stack traces in errors
app.use((err, req, res, next) => {
res.status(500).json({
error: err.message,
stack: err.stack // Never in production!
});
});
// VULNERABLE - Source maps in production
// webpack.config.js
devtool: 'source-map' // Exposes source code
// VULNERABLE - No security headers set
app.get('/', (req, res) => {
res.send('<html>...</html>');
});
// Check current headers
curl -I https://example.com
// Missing: X-Frame-Options, CSP, etc.
// VULNERABLE - Allow all origins
app.use(cors({
origin: '*',
credentials: true // Dangerous with wildcard!
}));
// VULNERABLE - Reflecting origin
app.use(cors({
origin: req.headers.origin, // Reflects any origin
credentials: true
}));
// VULNERABLE - Public S3 bucket policy
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-bucket/*"
}]
}
const helmet = require('helmet');
app.use(helmet({
// Content Security Policy
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "'unsafe-inline'"], // Adjust as needed
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", "data:", "https:"],
connectSrc: ["'self'", "https://api.example.com"],
fontSrc: ["'self'", "https://fonts.gstatic.com"],
objectSrc: ["'none'"],
frameAncestors: ["'none'"],
upgradeInsecureRequests: []
}
},
// Prevent clickjacking
frameguard: { action: 'deny' },
// Prevent MIME type sniffing
noSniff: true,
// XSS filter
xssFilter: true,
// HSTS
hsts: {
maxAge: 31536000,
includeSubDomains: true,
preload: true
},
// Referrer policy
referrerPolicy: { policy: 'strict-origin-when-cross-origin' },
// Permissions policy
permittedCrossDomainPolicies: { permittedPolicies: 'none' }
}));
// Additional headers
app.use((req, res, next) => {
res.setHeader('X-Content-Type-Options', 'nosniff');
res.setHeader('X-Permitted-Cross-Domain-Policies', 'none');
res.setHeader('Permissions-Policy', 'geolocation=(), microphone=(), camera=()');
next();
});
const cors = require('cors');
const allowedOrigins = [
'https://example.com',
'https://app.example.com',
'https://admin.example.com'
];
app.use(cors({
origin: (origin, callback) => {
// Allow requests with no origin (mobile apps, curl)
if (!origin) return callback(null, true);
if (allowedOrigins.includes(origin)) {
callback(null, true);
} else {
callback(new Error('CORS not allowed'));
}
},
credentials: true,
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization'],
exposedHeaders: ['X-Total-Count'],
maxAge: 86400 // 24 hours
}));
// Environment-aware error handler
app.use((err, req, res, next) => {
// Log full error for debugging
logger.error('Unhandled error', {
error: err.message,
stack: err.stack,
path: req.path,
method: req.method,
userId: req.user?.id
});
// Send safe response
const statusCode = err.statusCode || 500;
const response = {
error: {
message: statusCode === 500
? 'Internal server error' // Generic message in production
: err.message,
code: err.code || 'UNKNOWN_ERROR',
requestId: req.id // For support tickets
}
};
// Include stack trace only in development
if (process.env.NODE_ENV === 'development') {
response.error.stack = err.stack;
}
res.status(statusCode).json(response);
});
server {
listen 443 ssl http2;
server_name example.com;
# SSL Configuration
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# Security Headers
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline';" always;
# Hide server version
server_tokens off;
# Disable directory listing
autoindex off;
# Block access to hidden files
location ~ /\. {
deny all;
}
# Block access to sensitive files
location ~* \.(git|env|config|sql|log|bak|swp)$ {
deny all;
}
# Restrict methods
if ($request_method !~ ^(GET|POST|PUT|DELETE|OPTIONS)$) {
return 405;
}
}
// Secure S3 bucket policy
const s3BucketPolicy = {
Version: '2012-10-17',
Statement: [
{
Sid: 'DenyPublicAccess',
Effect: 'Deny',
Principal: '*',
Action: 's3:*',
Resource: [
'arn:aws:s3:::my-bucket',
'arn:aws:s3:::my-bucket/*'
],
Condition: {
Bool: {
'aws:SecureTransport': 'false'
}
}
}
]
};
// Block public access settings
const publicAccessBlock = {
BlockPublicAcls: true,
IgnorePublicAcls: true,
BlockPublicPolicy: true,
RestrictPublicBuckets: true
};
# AWS CLI - Block public access
aws s3api put-public-access-block \
--bucket my-bucket \
--public-access-block-configuration \
"BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true"
// config/index.js - Environment-aware configuration
const config = {
development: {
debug: true,
logLevel: 'debug',
sourceMaps: true,
showErrors: true
},
production: {
debug: false,
logLevel: 'error',
sourceMaps: false,
showErrors: false,
helmet: true,
rateLimit: true
}
};
module.exports = config[process.env.NODE_ENV] || config.production;
# Use specific version, not 'latest'
FROM node:20.11-alpine
# Run as non-root user
RUN addgroup -g 1001 appgroup && \
adduser -u 1001 -G appgroup -s /bin/sh -D appuser
WORKDIR /app
# Copy package files first (better caching)
COPY package*.json ./
RUN npm ci --only=production
# Copy application
COPY --chown=appuser:appgroup . .
# Switch to non-root user
USER appuser
# Don't expose unnecessary ports
EXPOSE 3000
# Use exec form, not shell form
CMD ["node", "server.js"]
# Check security headers
curl -I https://example.com
# Online header checker
# https://securityheaders.com
# SSL/TLS configuration
# https://www.ssllabs.com/ssltest/
# Check for exposed .git
curl -I https://example.com/.git/HEAD
# Check for directory listing
curl https://example.com/images/
# S3 bucket checker
aws s3 ls s3://bucket-name --no-sign-request