| name | insecure-defaults |
| description | Detects fail-open vulnerabilities where applications run insecurely with missing configuration. Finds hardcoded credentials, weak env var fallbacks, and insecure-by-default settings. Adapted from Trail of Bits methodology. |
| allowed-tools | ["Read","Grep","Glob","Bash"] |
| group | security |
| triggers | [".env","config","secrets","безопасно ли деплоить","есть ли hardcoded"] |
| output | security report: hardcoded credentials, insecure defaults, fail-open risks |
| calls | [] |
Insecure Defaults
Identifies fail-open vulnerabilities: configurations where missing env vars, secrets, or settings cause the application to run in an insecure state rather than failing safely.
When to Use
- Pre-deployment security audit of production application
- Reviewing config files,
.env handling, or secrets management
- Auditing environment variable usage across the codebase
- Checking cryptographic algorithm choices
- Reviewing Docker / IaC / Kubernetes configs for permissive defaults
- User asks "is this safe to deploy?" or "are there hardcoded secrets?"
When NOT to Use
- Test code (
tests/, spec/, __tests__/, *.test.*) — test defaults are intentional
.example, .template, .sample files — placeholders by design
- Documentation examples
- Build-time config guaranteed to be replaced during deployment
- Dev-only tooling that never runs in production
Rationalizations to Reject
- "The default is only used locally" — local development often mirrors production configs; defaults leak
- "We always set the env var in production" — "always" breaks eventually; code must fail-safe
- "It's an internal service, not exposed" — internal breach + fail-open = full compromise
- "The weak algorithm is only for non-sensitive data" — "non-sensitive" classifications drift over time
- "The tests pass with the default" — test pass ≠ production safe
Core Distinction
The fundamental question for every finding:
Fail-Open (DANGEROUS): App runs insecurely when config is absent
SECRET = os.environ.get('SECRET_KEY') or 'default-secret'
Fail-Secure (SAFE): App crashes/refuses to start when required config is absent
SECRET = os.environ['SECRET_KEY']
SECRET = os.environ.get('SECRET_KEY')
if not SECRET:
raise RuntimeError("SECRET_KEY environment variable is required")
Analysis Workflow (4 Phases)
Phase 1 — Discovery
Map the attack surface:
grep -rn "os.environ\|os.getenv\|process.env\|getenv" --include="*.py" --include="*.ts" --include="*.js" .
find . -name "config*.py" -o -name "settings*.py" -o -name "*.env*" | grep -v ".example"
grep -rn "password\|secret\|token\|api_key\|apikey\|credential" -i --include="*.py" .
grep -rn "password\|secret\|token\|api_key\|apikey\|credential" -i --include="*.ts" .
Inventory:
- All env var reads and their fallback values
- All cryptographic operations and algorithm choices
- All authentication/authorization configuration points
- All external service configuration (URLs, timeouts, TLS settings)
Phase 2 — Verification
For each env var read, classify:
| Pattern | Classification | Risk |
|---|
os.environ['KEY'] | Fail-secure | Safe |
os.environ.get('KEY') with no default + validation | Fail-secure | Safe |
os.environ.get('KEY', '') + if not value: raise | Fail-secure | Safe |
os.environ.get('KEY') or 'fallback' | Fail-open | HIGH |
os.environ.get('KEY', 'fallback') | Fail-open | HIGH |
os.environ.get('KEY', None) used without None-check | Fail-open | MEDIUM |
Trace each fail-open pattern: where is the value used?
- Used in cryptographic operation → CRITICAL
- Used in auth check → CRITICAL
- Used in external API call → HIGH
- Used in logging / non-security context → LOW
Phase 3 — Production Assessment
Verify whether production actually sets required variables:
- Check deployment configs:
docker-compose.yml, k8s/, .env.production, CI/CD secrets
- Check if documented: is the env var listed in README / deployment guide?
- Check if validated at startup: is there an explicit startup check?
A fail-open pattern is more severe if:
- No startup validation exists
- Env var is not documented
- Deployment config shows it's sometimes unset
Phase 4 — Findings Documentation
For each finding:
## [Severity] <Short title>
**File:** path/to/file.py:42
**Pattern:** fail-open / hardcoded / weak algorithm
**Vulnerable code:**
```python
SECRET = os.environ.get('SECRET_KEY') or 'dev-secret-change-me'
What happens if env var is missing:
Application starts with SECRET_KEY = 'dev-secret-change-me'. An attacker
who knows this default can forge session tokens / HMAC signatures.
Fix:
SECRET = os.environ.get('SECRET_KEY')
if not SECRET:
raise RuntimeError("SECRET_KEY is required. Set it in your environment.")
---
## Finding Categories
### 1. Weak Env Var Fallbacks
```python
# All of these are fail-open:
SECRET = os.getenv('SECRET') or 'default'
SECRET = os.environ.get('SECRET', 'changeme')
DB_PASSWORD = config.get('db_password', 'postgres')
API_KEY = os.environ.get('API_KEY', '') # empty string = no auth
2. Hardcoded Credentials
DB_URI = "postgresql://admin:password123@localhost/prod"
AWS_SECRET = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
3. Weak Cryptographic Algorithms
hashlib.md5(password)
hashlib.sha1(password)
Cipher.new(key, AES.MODE_ECB)
DES.new(key)
4. Permissive Default Access Controls
CORS_ORIGINS = ["*"]
DEBUG = os.environ.get('DEBUG', True)
ALLOW_REGISTRATION = True
5. TLS / Certificate Validation
requests.get(url, verify=False)
ssl._create_unverified_context()
6. Insecure Defaults in Config Files
services:
db:
environment:
POSTGRES_PASSWORD: ""
server_tokens on;
Severity Classification
| Severity | When |
|---|
| 🔴 Critical | Fail-open on auth/crypto/session secret; hardcoded production credential |
| 🟠 High | Fail-open on API key, DB password; weak algorithm for security-critical data |
| 🟡 Medium | Permissive CORS/access defaults; weak algorithm for non-critical data |
| 🟢 Low | Missing startup validation despite correct production config; undocumented required var |
Output Format
# Insecure Defaults Audit: <scope>
## Summary
- Fail-open patterns found: X
- Hardcoded credentials found: X
- Weak algorithms found: X
- Files audited: X / Y total
## 🔴 Critical
### [C1] Fail-open session secret
...
## 🟠 High
...
## ✅ What's secure
- `DATABASE_URL` correctly uses `os.environ['DATABASE_URL']` (fail-secure)
- Password hashing uses `bcrypt` correctly