# Frontend Security Anti-Patterns
# Patterns that may expose security vulnerabilities in Vue/TypeScript

name: Security
description: |
  Detects patterns that could lead to security vulnerabilities including
  XSS risks, sensitive data exposure, insecure storage, and auth issues.
  Specific to Vue 3, TypeScript, and browser security concerns.

patterns:
  # XSS Risks
  - id: v-html-usage
    description: v-html directive (potential XSS)
    grep_pattern: 'v-html\s*='
    file_glob: '*.vue'
    context_lines: 3
    verdict_hints:
      ISSUE_IF: "Content from API, user input, or any external source"
      OK_IF: "Only static/trusted content; or sanitized with DOMPurify"

  - id: innerhtml-assignment
    description: Direct innerHTML assignment
    grep_pattern: '\.innerHTML\s*='
    file_glob: '*.{vue,ts}'
    context_lines: 3
    verdict_hints:
      ISSUE_IF: "Assigns user-controlled or API content"
      OK_IF: "Static trusted HTML only; prefer v-html with sanitization"

  - id: document-write
    description: document.write usage (XSS and performance)
    grep_pattern: 'document\.write'
    file_glob: '*.{vue,ts}'
    context_lines: 2
    verdict_hints:
      ISSUE_IF: "Almost never acceptable in modern apps"
      OK_IF: "Never OK - refactor to DOM manipulation"

  # Sensitive Data Exposure
  - id: console-log-sensitive
    description: Console logging potentially sensitive data
    grep_pattern: 'console\.(log|debug|info)\(.*\b(token|password|secret|auth|credential|key)\b'
    file_glob: '*.{vue,ts}'
    context_lines: 2
    verdict_hints:
      ISSUE_IF: "Logs sensitive values - visible in browser devtools"
      OK_IF: "Logs field names only, not values; or dev-only code"

  - id: localstorage-sensitive
    description: Storing sensitive data in localStorage
    grep_pattern: 'localStorage\.setItem\([^)]*\b(password|secret|credit|ssn)\b'
    file_glob: '*.{vue,ts}'
    context_lines: 3
    verdict_hints:
      ISSUE_IF: "Sensitive data in localStorage - accessible to XSS"
      OK_IF: "Never OK for passwords/secrets; tokens need careful review"

  - id: token-in-url
    description: Auth token in URL or query params
    grep_pattern: '(url|href|src).*\?(.*&)?(token|auth|key)='
    file_glob: '*.{vue,ts}'
    context_lines: 3
    verdict_hints:
      ISSUE_IF: "Token in URL - logged in server logs, browser history"
      OK_IF: "One-time tokens (email verification); not session tokens"

  - id: hardcoded-secret
    description: Hardcoded API key or secret
    grep_pattern: '(api_?key|secret|password)\s*[:=]\s*["\'][^"\']{8,}["\']'
    file_glob: '*.{vue,ts}'
    context_lines: 2
    exclude_tests: false
    verdict_hints:
      ISSUE_IF: "Real credential in source code"
      OK_IF: "Placeholder; real value from VITE_* env variable"

  # Auth Issues
  - id: auth-check-client-only
    description: Auth check only on client side
    grep_pattern: '(isAuthenticated|isLoggedIn|user)\s*\?\s*<'
    file_glob: '*.vue'
    context_lines: 5
    verdict_hints:
      ISSUE_IF: "UI hidden but API not protected - security by obscurity"
      OK_IF: "UI hint only; API has proper auth middleware"

  - id: token-in-state
    description: Auth token stored in reactive state without persistence consideration
    grep_pattern: 'ref<.*token.*>\s*\('
    file_glob: '*.{vue,ts}'
    context_lines: 4
    verdict_hints:
      ISSUE_IF: "Token in memory only - lost on refresh without secure persistence"
      OK_IF: "Intentional session-only token; or persisted securely elsewhere"

  # Game-Specific Security
  - id: game-state-trust
    description: Trusting game state from client
    grep_pattern: '(damage|hp|energy|prize|winner)\s*=\s*(props|data|event)'
    file_glob: '*.{vue,ts}'
    context_lines: 5
    verdict_hints:
      ISSUE_IF: "Game state from client used without server validation"
      OK_IF: "Display only; actual state from server via WebSocket"

  - id: hidden-info-client
    description: Accessing hidden game info that should be server-only
    grep_pattern: '\.(deck|opponentHand|prizes)\.(cards|contents|order)'
    file_glob: '*.{vue,ts}'
    context_lines: 4
    verdict_hints:
      ISSUE_IF: "Accessing hidden zone contents - should only have counts"
      OK_IF: "Own hand/prizes (visible to player); or mock data in tests"

  # Input Validation
  - id: unsanitized-user-input
    description: User input used directly without validation
    grep_pattern: '(v-model|@input).*\n.*(?!.*validate|sanitize|escape)'
    multiline: true
    file_glob: '*.vue'
    context_lines: 5
    verdict_hints:
      ISSUE_IF: "Input sent to API without validation"
      OK_IF: "Validated before submission; or display-only local state"

  - id: eval-usage
    description: eval() or Function() constructor
    grep_pattern: '\b(eval|Function)\s*\('
    file_glob: '*.{vue,ts}'
    context_lines: 3
    verdict_hints:
      ISSUE_IF: "Executing dynamic code - XSS/injection risk"
      OK_IF: "Never OK in frontend code"

  # Network Security
  - id: http-url
    description: HTTP (non-HTTPS) URL in code
    grep_pattern: '["\']http://(?!localhost|127\.0\.0\.1)'
    file_glob: '*.{vue,ts}'
    context_lines: 2
    verdict_hints:
      ISSUE_IF: "Production URL using HTTP - data sent unencrypted"
      OK_IF: "Development URL; production uses HTTPS"

  - id: cors-credential-any
    description: Credentials with wildcard or any origin
    grep_pattern: 'credentials:\s*["\']include["\']'
    file_glob: '*.{vue,ts}'
    context_lines: 4
    verdict_hints:
      ISSUE_IF: "Credentials sent to any origin - CSRF risk"
      OK_IF: "Server has strict CORS; or same-origin requests only"
