This skill should be used when Agent 6 needs to "audit security", "review authentication", "check for vulnerabilities", "implement CORS", "validate input", "secure API endpoints", or address OWASP Top 10 risks in TheMoon project.
42:T1e08,
This skill provides security checklists, vulnerability patterns, and secure coding guidelines for Agent 6 (Security Auditor).
Risk: Untrusted data sent to interpreter as part of command/query.
Check Points:
# VULNERABLE: String concatenation
query = f"SELECT * FROM users WHERE name = '{user_input}'"
# SECURE: Parameterized query
query = session.query(User).filter(User.name == user_input)
# SECURE: SQLAlchemy ORM (always parameterized)
user = repo.get_by_name(user_input)
Audit Commands:
# Search for raw SQL
grep -r "execute(" backend/
grep -r "raw(" backend/
grep -r "text(" backend/
Check Points:
Secure Password Handling:
from passlib.context import CryptContext
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
def hash_password(password: str) -> str:
return pwd_context.hash(password)
def verify_password(plain: str, hashed: str) -> bool:
return pwd_context.verify(plain, hashed)
Check Points:
Audit Commands:
# Find hardcoded secrets
grep -r "password\s*=" --include="*.py" backend/
grep -r "secret\s*=" --include="*.py" backend/
grep -r "api_key\s*=" --include="*.py" backend/
Check Points:
Check Points:
Secure Endpoint Pattern:
from fastapi import Depends, HTTPException, status
from app.core.security import get_current_user, get_current_admin
@router.get("/admin/users")
def list_users(admin: User = Depends(get_current_admin)):
"""Only admins can list all users."""
return user_service.get_all()
@router.get("/users/{user_id}")
def get_user(user_id: int, current_user: User = Depends(get_current_user)):
"""Users can only access their own data."""
if current_user.id != user_id and not current_user.is_admin:
raise HTTPException(status_code=403, detail="Access denied")
return user_service.get(user_id)
Check Points:
Security Headers:
async def add_security_headers(request: Request, call_next):
response = await call_next(request)
response.headers["X-Content-Type-Options"] = "nosniff"
response.headers["X-Frame-Options"] = "DENY"
response.headers["X-XSS-Protection"] = "1; mode=block"
response.headers["Strict-Transport-Security"] = "max-age=31536000"
response.headers["Content-Security-Policy"] = "default-src 'self'"
return response
Check Points:
Frontend Protection:
{userInput} syntaxCheck Points:
Check Points:
Audit Commands:
# Python dependencies
pip-audit
safety check
# npm dependencies
npm audit
Check Points:
from fastapi.middleware.cors import CORSMiddleware
# Production: Specific origins only
ALLOWED_ORIGINS = [
"https://themoon.example.com",
"https://admin.themoon.example.com",
]
# Development: Add localhost
if settings.DEBUG:
ALLOWED_ORIGINS.extend([
"http://localhost:3000",
"http://localhost:3500",
])
app.add_middleware(
CORSMiddleware,
allow_origins=ALLOWED_ORIGINS, # Never use ["*"] in production
allow_credentials=True,
allow_methods=["GET", "POST", "PUT", "PATCH", "DELETE"],
allow_headers=["Authorization", "Content-Type"],
)
from pydantic import BaseModel, Field, field_validator
import re
class UserCreate(BaseModel):
email: str = Field(..., max_length=255)
password: str = Field(..., min_length=8, max_length=100)
name: str = Field(..., min_length=1, max_length=100)
@field_validator("email")
@classmethod
def validate_email(cls, v: str) -> str:
pattern = r"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$"
if not re.match(pattern, v):
raise ValueError("Invalid email format")
return v.lower()
from fastapi import UploadFile, HTTPException
import magic
ALLOWED_TYPES = {"image/jpeg", "image/png", "application/pdf"}
MAX_SIZE = 10 * 1024 * 1024 # 10MB
async def validate_file(file: UploadFile) -> None:
content = await file.read()
if len(content) > MAX_SIZE:
raise HTTPException(400, "File too large")
mime_type = magic.from_buffer(content, mime=True)
if mime_type not in ALLOWED_TYPES:
raise HTTPException(400, f"File type {mime_type} not allowed")
await file.seek(0)
from slowapi import Limiter
from slowapi.util import get_remote_address
limiter = Limiter(key_func=get_remote_address)
@router.post("/auth/login")
@limiter.limit("5/minute")
def login(request: Request, credentials: LoginRequest):
pass
@router.post("/upload")
@limiter.limit("10/hour")
def upload(request: Request, file: UploadFile):
pass
## Security Audit Report
**Date**: YYYY-MM-DD
**Auditor**: Agent 6
### Summary
- Critical: X | High: X | Medium: X | Low: X
### Findings
#### [CRITICAL] Issue Title
- Location: file:line
- Risk: Description
- Recommendation: Fix approach
- Status: Open/Fixed
| Vulnerability | Check | Fix |
|---|---|---|
| SQL Injection | grep "execute(" | Use ORM/parameterized |
| XSS | Check raw HTML rendering | Sanitize or escape |
| CSRF | Cookie without SameSite | Add SameSite=Strict |
| Hardcoded secrets | grep "password=" | Use env variables |
| Weak CORS | allow_origins=["*"] | Whitelist domains |
| No rate limit | Check auth endpoints | Add slowapi |