Scan infrastructure configuration files for security vulnerabilities, misconfigurations, and deviations from best practices.
Scans infrastructure files for security vulnerabilities and misconfigurations. Triggers automatically when you edit Docker Compose, Kubernetes manifests, or Terraform files, providing immediate remediation guidance.
/plugin marketplace add cassao29/claude-secure-plugins/plugin install security-scanner@claude-secure-pluginsThis skill inherits all available tools. When active, it can use any tool Claude has access to.
Scan infrastructure configuration files for security vulnerabilities, misconfigurations, and deviations from best practices.
Scan docker-compose.yml, docker-compose.*.yml, compose.yml
| Issue | Detection | Fix |
|---|---|---|
| Public port binding | ports: ["8080:8080"] | Use 127.0.0.1:8080:8080 |
| Privileged container | privileged: true | Remove or use specific capabilities |
| Host network mode | network_mode: host | Use bridge network |
| Writable /etc or /root | Volume mounts to sensitive paths | Use read-only or avoid |
| Root user | No user: specified | Add user: "1000:1000" |
| Missing security_opt | No security_opt section | Add no-new-privileges:true |
| Issue | Detection | Fix |
|---|---|---|
| No health check | Missing healthcheck: | Add health check |
| No resource limits | Missing deploy.resources | Add CPU/memory limits |
| No restart policy | Missing restart: | Add unless-stopped |
| Default bridge network | No custom networks | Define isolated networks |
| No logging limits | Missing logging.options | Add max-size, max-file |
| Issue | Detection | Fix |
|---|---|---|
Using latest tag | image: app:latest | Pin specific version |
| Deprecated version key | version: "3.8" | Remove (optional in modern Docker) |
| No container name | Missing container_name | Add for easier management |
Scan *.yaml, *.yml files with Kubernetes API objects
| Issue | Detection | Fix |
|---|---|---|
| Running as root | runAsUser: 0 or missing | Set runAsNonRoot: true |
| Privileged pod | privileged: true | Set privileged: false |
| Host PID/Network | hostPID: true | Remove |
| No resource limits | Missing resources.limits | Define limits |
| Writable root FS | readOnlyRootFilesystem: false | Set to true |
| All capabilities | capabilities: add: [ALL] | Drop ALL, add specific |
| Issue | Detection | Fix |
|---|---|---|
| No network policy | Missing NetworkPolicy | Create restrictive policy |
| No pod security | Missing securityContext | Add security context |
| No liveness probe | Missing livenessProbe | Add health check |
| Service type LoadBalancer | type: LoadBalancer | Use ClusterIP + Ingress |
Scan *.tf, *.tfvars files
| Issue | Detection | Fix |
|---|---|---|
| Open security group | 0.0.0.0/0 in ingress | Restrict to specific IPs |
| Public S3 bucket | acl = "public-read" | Use private |
| Unencrypted storage | Missing encryption config | Enable encryption |
| Hardcoded secrets | password = "..." | Use variables/secrets manager |
| No state encryption | Plain state file | Enable encryption |
| Issue | Detection | Fix |
|---|---|---|
| Default VPC | Using default VPC | Create custom VPC |
| No VPC flow logs | Missing flow logs | Enable for audit |
| IMDSv1 enabled | Missing IMDSv2 requirement | Require IMDSv2 |
| No backup | Missing backup config | Enable automated backups |
╔══════════════════════════════════════════════════════════════╗
║ SECURITY SCAN REPORT ║
║ 2025-12-10 14:30:00 ║
╠══════════════════════════════════════════════════════════════╣
║ Files Scanned: 5 ║
║ Issues Found: 12 ║
║ ║
║ ⛔ Critical: 3 ║
║ ⚠️ Medium: 5 ║
║ ℹ️ Low: 4 ║
╚══════════════════════════════════════════════════════════════╝
⛔ CRITICAL: Public Port Exposure
File: docker-compose.yml
Line: 15
Service: web
Found:
ports:
- "8080:8080"
Risk: Port 8080 is exposed to all network interfaces (0.0.0.0).
Attackers can access this service from the internet.
Fix:
ports:
- "127.0.0.1:8080:8080"
Reference: CIS Docker Benchmark 5.13
rules:
- id: DC001
name: public-port-binding
severity: critical
pattern: 'ports:\s*-\s*"?\d+:\d+"?'
exclude: '127\.0\.0\.1:|localhost:'
message: "Port exposed publicly without localhost binding"
fix: "Prepend 127.0.0.1: to port binding"
- id: DC002
name: privileged-container
severity: critical
pattern: 'privileged:\s*true'
message: "Container running in privileged mode"
fix: "Remove privileged: true or use specific capabilities"
- id: DC003
name: missing-security-opt
severity: high
pattern: 'services:'
require: 'security_opt:'
message: "Service missing security_opt configuration"
fix: "Add security_opt: [no-new-privileges:true]"
- id: DC004
name: no-health-check
severity: medium
pattern: 'services:'
require: 'healthcheck:'
message: "Service missing health check"
fix: "Add healthcheck with test, interval, timeout"
- id: DC005
name: no-resource-limits
severity: medium
pattern: 'services:'
require: 'deploy:\s*resources:\s*limits:'
message: "Service missing resource limits"
fix: "Add deploy.resources.limits for CPU and memory"
- id: DC006
name: host-network
severity: critical
pattern: 'network_mode:\s*host'
message: "Container using host network mode"
fix: "Use bridge network with explicit port bindings"
- id: DC007
name: latest-tag
severity: low
pattern: 'image:\s*\S+:latest'
message: "Using latest tag which is mutable"
fix: "Pin to specific version tag"
rules:
- id: K8S001
name: run-as-root
severity: critical
pattern: 'runAsUser:\s*0'
message: "Container configured to run as root"
fix: "Set runAsNonRoot: true or specify non-root user"
- id: K8S002
name: privileged-pod
severity: critical
pattern: 'privileged:\s*true'
message: "Pod running in privileged mode"
fix: "Set privileged: false"
- id: K8S003
name: no-security-context
severity: high
pattern: 'containers:'
require: 'securityContext:'
message: "Container missing security context"
fix: "Add securityContext with appropriate restrictions"
- id: K8S004
name: capabilities-all
severity: critical
pattern: 'capabilities:\s*add:\s*\[\s*ALL'
message: "Container granted all capabilities"
fix: "Drop ALL capabilities and add only required ones"
- id: K8S005
name: host-pid
severity: critical
pattern: 'hostPID:\s*true'
message: "Pod sharing host PID namespace"
fix: "Remove hostPID: true"
rules:
- id: TF001
name: open-security-group
severity: critical
pattern: 'cidr_blocks\s*=\s*\["0\.0\.0\.0/0"\]'
context: 'ingress'
message: "Security group allows traffic from anywhere"
fix: "Restrict to specific IP ranges"
- id: TF002
name: public-s3-bucket
severity: critical
pattern: 'acl\s*=\s*"public'
message: "S3 bucket configured for public access"
fix: "Use acl = \"private\" and bucket policies"
- id: TF003
name: unencrypted-ebs
severity: high
pattern: 'aws_ebs_volume'
require: 'encrypted\s*=\s*true'
message: "EBS volume not encrypted"
fix: "Add encrypted = true"
- id: TF004
name: hardcoded-credentials
severity: critical
pattern: '(password|secret|key)\s*=\s*"[^"$]+'
message: "Hardcoded credentials in Terraform"
fix: "Use variables or secrets manager"
This skill can be integrated as a validation hook:
{
"hooks": {
"PreToolUse": [{
"matcher": "Write|Edit",
"hooks": [{
"type": "command",
"command": "security-scan --file $FILE_PATH"
}]
}]
}
}
# GitHub Actions
- name: Security Scan
run: |
claude plugin run security-scanner --path .
if [ $? -ne 0 ]; then
echo "Security issues found!"
exit 1
fi
When issues are found, the scanner provides:
Some patterns may be intentional. Mark as accepted:
# security-scan: ignore DC001
ports:
- "0.0.0.0:443:443" # Intentionally public (reverse proxy)
Or create .security-scan-ignore:
ignore:
- rule: DC001
file: nginx/docker-compose.yml
reason: "Nginx is intentionally public-facing"
| Rule | CIS Docker | CIS Kubernetes | OWASP |
|---|---|---|---|
| DC001 | 5.13 | - | A05 |
| DC002 | 5.4 | - | A01 |
| DC003 | 5.25 | - | A05 |
| K8S001 | - | 5.2.6 | A01 |
| K8S002 | - | 5.2.1 | A01 |
| TF001 | - | - | A05 |