rules:
  - id: auth.ruby.secret.hardcoded-secret-key-base
    languages:
      - ruby
    severity: ERROR
    message: |
      A Rails `secret_key_base` / `secret_key` is assigned a hard-coded string
      literal. This value keys the whole application's signed/encrypted cookies
      (including the session cookie) and message verifiers: committed to source
      control it is one search away from letting an attacker forge session
      cookies and impersonate any user (CWE-798). Inlining a literal secret to
      make an app "just run" is a classic LLM-generated mistake.

      Never assign the secret in code. Store it in `Rails.application.credentials`
      (encrypted) or read it from the environment, e.g.
      `ENV.fetch("SECRET_KEY_BASE")`, and rotate the leaked value out of source
      control and git history.
    # Only a quoted string literal (>= 8 chars) on the RHS fires. ENV[...],
    # ENV.fetch(...) and Rails.application.credentials.* are not string
    # literals, so they are structurally excluded.
    patterns:
      - pattern-either:
          - pattern: '$X.secret_key_base = $V'
          - pattern: '$X.secret_key = $V'
      - metavariable-regex:
          metavariable: $V
          regex: (?s)^["'].{8,}["']$
    paths:
      exclude:
        - "**/spec/**"
        - "**/test/**"
        - "**/*_spec.rb"
        - "**/*_test.rb"
        - "**/features/**"
    metadata:
      oauthlint-rule-id: AUTH-RUBY-SECRET-002
      oauthlint-doc-url: https://oauthlint.dev/rules/ruby-secret-hardcoded-secret-key-base
      category: security
      cwe: CWE-798
      owasp: A07:2021
      llm-prevalence: MEDIUM
      technology:
        - rails
      references:
        - https://guides.rubyonrails.org/security.html#custom-credentials
        - https://cwe.mitre.org/data/definitions/798.html
