Project-specific skill to audit codebase for: - Error handling: silent failures, swallowed exceptions, hidden errors - Security: missing auth, data exposure, injection risks - Architecture: DI violations, import boundaries, coupling Pattern definitions in YAML with verdict hints (ISSUE_IF/OK_IF) for context-aware analysis. Tailored to Mantimon TCG architecture patterns (core independence, stateless backend, repository pattern). Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
97 lines
3.7 KiB
YAML
97 lines
3.7 KiB
YAML
# Security Anti-Patterns
|
|
# Patterns that may expose security vulnerabilities
|
|
|
|
name: Security
|
|
description: |
|
|
Detects patterns that could lead to security vulnerabilities including
|
|
missing authorization, data exposure, injection risks, and unsafe operations.
|
|
Specific to Mantimon TCG patterns and FastAPI/Python conventions.
|
|
|
|
patterns:
|
|
- id: missing-auth-dependency
|
|
description: Endpoint without authentication dependency
|
|
grep_pattern: '@router\.(post|put|patch|delete)\([^)]*\)\n(async )?def \w+\([^)]*\):'
|
|
multiline: true
|
|
context_lines: 5
|
|
file_glob: 'app/api/**/*.py'
|
|
verdict_hints:
|
|
ISSUE_IF: "Mutating endpoint without get_current_user dependency"
|
|
OK_IF: "Public endpoint (login, register, health) or has auth in deps"
|
|
|
|
- id: password-in-log
|
|
description: Password or secret potentially logged
|
|
grep_pattern: 'logger\.\w+\(.*["\']?.*(password|secret|token|key|credential).*["\']?'
|
|
context_lines: 2
|
|
verdict_hints:
|
|
ISSUE_IF: "Sensitive value included in log message"
|
|
OK_IF: "Just logging field name, not value; or intentionally masked"
|
|
|
|
- id: sql-string-format
|
|
description: SQL query built with string formatting (injection risk)
|
|
grep_pattern: '(execute|text)\([^)]*(%|\.format|f["\'])'
|
|
context_lines: 3
|
|
verdict_hints:
|
|
ISSUE_IF: "User input could be interpolated into SQL"
|
|
OK_IF: "Only constant values interpolated; user input uses params"
|
|
|
|
- id: hidden-game-info-exposure
|
|
description: Deck/hand contents potentially exposed to wrong player
|
|
grep_pattern: '(deck|hand|prize).*\.(cards|contents|order)'
|
|
context_lines: 5
|
|
file_glob: 'app/services/game_service.py'
|
|
verdict_hints:
|
|
ISSUE_IF: "Opponent's hidden zone contents sent to client"
|
|
OK_IF: "Only counts sent, or filtered through visibility layer"
|
|
|
|
- id: missing-ownership-check
|
|
description: Resource access without verifying ownership
|
|
grep_pattern: 'await.*(get_deck|get_collection|get_game).*\n(?!.*user_id|player_id)'
|
|
multiline: true
|
|
context_lines: 5
|
|
file_glob: 'app/api/**/*.py'
|
|
verdict_hints:
|
|
ISSUE_IF: "Resource fetched without checking user owns it"
|
|
OK_IF: "Ownership check in service layer or resource is public"
|
|
|
|
- id: hardcoded-secret
|
|
description: Hardcoded secret or API key in code
|
|
grep_pattern: '(api_key|secret|password|token)\s*=\s*["\'][^"\']{8,}["\']'
|
|
context_lines: 2
|
|
exclude_tests: false
|
|
verdict_hints:
|
|
ISSUE_IF: "Real credential hardcoded in source"
|
|
OK_IF: "Placeholder/example value; real value from environment"
|
|
|
|
- id: debug-mode-check
|
|
description: Debug mode check that might expose info in production
|
|
grep_pattern: 'if.*(debug|DEBUG|dev_mode).*:\n.*print|logger'
|
|
multiline: true
|
|
context_lines: 4
|
|
verdict_hints:
|
|
ISSUE_IF: "Sensitive data logged only when debug flag set"
|
|
OK_IF: "Debug info is non-sensitive; flag properly controlled"
|
|
|
|
- id: unsafe-pickle
|
|
description: Pickle usage (arbitrary code execution risk)
|
|
grep_pattern: 'pickle\.(load|loads)'
|
|
context_lines: 3
|
|
verdict_hints:
|
|
ISSUE_IF: "Unpickling data from untrusted source"
|
|
OK_IF: "Never OK for external data; use JSON/msgpack instead"
|
|
|
|
- id: eval-usage
|
|
description: eval() or exec() usage
|
|
grep_pattern: '(eval|exec)\s*\('
|
|
context_lines: 3
|
|
verdict_hints:
|
|
ISSUE_IF: "Evaluating user-controlled input"
|
|
OK_IF: "Extremely rare valid use; usually should refactor"
|
|
|
|
- id: cors-wildcard
|
|
description: CORS allowing all origins
|
|
grep_pattern: 'allow_origins\s*=\s*\["\*"\]|allow_origin_regex.*\.\*'
|
|
context_lines: 3
|
|
verdict_hints:
|
|
ISSUE_IF: "Production API allows any origin"
|
|
OK_IF: "Development only; production has specific origins"
|