Files
gh-nbarthel-claudy-plugins-…/skills/rails-security-patterns/skill.md
2025-11-30 08:42:29 +08:00

6.6 KiB

name, description, auto_invoke, trigger_on, file_patterns, tags, priority, version
name description auto_invoke trigger_on file_patterns tags priority version
rails-security-patterns Automatically validates security best practices and prevents vulnerabilities true
file_create
file_modify
**/controllers/**/*.rb
**/models/**/*.rb
rails
security
authentication
authorization
sql-injection
1 2.0

Rails Security Patterns Skill

Auto-validates security best practices and blocks common vulnerabilities.

What This Skill Does

Automatic Security Checks:

  • Strong parameters in controllers (prevents mass assignment)
  • SQL injection prevention (parameterized queries)
  • CSRF token handling (API mode considerations)
  • Authentication presence
  • Authorization checks

When It Activates:

  • Controller files created or modified
  • Model files with database queries modified
  • Authentication-related changes

Security Checks

1. Strong Parameters

Checks:

  • Every create and update action uses strong parameters
  • No direct params usage in model instantiation
  • permit calls include only expected attributes

Example Violation:

# BAD
def create
  @user = User.create(params[:user])  # ❌ Mass assignment
end

# GOOD
def create
  @user = User.create(user_params)  # ✅ Strong params
end

private

def user_params
  params.require(:user).permit(:name, :email)
end

Skill Output:

❌ Security: Mass assignment vulnerability
Location: app/controllers/users_controller.rb:15
Issue: params[:user] used directly without strong parameters

Fix: Define strong parameters method:
private

def user_params
  params.require(:user).permit(:name, :email, :role)
end

Then use: @user = User.create(user_params)

2. SQL Injection Prevention

Checks:

  • No string interpolation in where clauses
  • Parameterized queries used
  • No raw SQL without placeholders

Example Violation:

# BAD
User.where("email = '#{params[:email]}'")  # ❌ SQL injection
User.where("name LIKE '%#{params[:query]}%'")  # ❌ SQL injection

# GOOD
User.where("email = ?", params[:email])  # ✅ Parameterized
User.where("name LIKE ?", "%#{params[:query]}%")  # ✅ Safe
User.where(email: params[:email])  # ✅ Hash syntax

Skill Output:

❌ Security: SQL injection vulnerability
Location: app/models/user.rb:45
Issue: String interpolation in SQL query

Vulnerable code:
User.where("email = '#{email}'")

Fix: Use parameterized query:
User.where("email = ?", email)

Or use hash syntax:
User.where(email: email)

3. Authentication Checks

Checks:

  • Controllers have authentication filters
  • Sensitive actions require authentication
  • Token-based auth for API endpoints

Example:

# app/controllers/posts_controller.rb
class PostsController < ApplicationController
  before_action :authenticate_user!  # ✅ Auth required

  def index
    # ...
  end
end

Skill Output (if missing):

⚠️  Security: No authentication found
Location: app/controllers/admin/users_controller.rb
Issue: Admin controller without authentication

Recommendation: Add authentication:
before_action :authenticate_user!
before_action :require_admin!

4. Authorization Checks

Checks:

  • Update/destroy actions verify ownership
  • Role-based access control present
  • Resource-level authorization

Example:

# BAD
def destroy
  @post = Post.find(params[:id])
  @post.destroy  # ❌ No ownership check
end

# GOOD
def destroy
  @post = current_user.posts.find(params[:id])  # ✅ Scoped to user
  @post.destroy
end

# BETTER
def destroy
  @post = Post.find(params[:id])
  authorize @post  # ✅ Using Pundit/CanCanCan
  @post.destroy
end

Skill Output:

⚠️  Security: Missing authorization check
Location: app/controllers/posts_controller.rb:42
Issue: destroy action without ownership verification

Recommendation: Add authorization:
Option 1 (scope to user):
@post = current_user.posts.find(params[:id])

Option 2 (use authorization gem):
authorize @post  # Pundit
authorize! :destroy, @post  # CanCanCan

5. Sensitive Data Exposure

Checks:

  • No passwords in logs
  • API keys not hardcoded
  • Secrets use environment variables

Example Violation:

# BAD
API_KEY = "sk_live_abc123..."  # ❌ Hardcoded secret

# GOOD
API_KEY = ENV['STRIPE_API_KEY']  # ✅ Environment variable

Skill Output:

❌ Security: Hardcoded secret detected
Location: config/initializers/stripe.rb:3
Issue: API key hardcoded in source

Fix: Use environment variable:
API_KEY = ENV['STRIPE_API_KEY']

Add to .env (don't commit):
STRIPE_API_KEY=sk_live_your_key_here

Integration with Pre-commit Hook

This skill works with the pre-commit hook to block unsafe commits:

Automatic blocks:

  • SQL injection vulnerabilities
  • Missing strong parameters in create/update actions
  • Hardcoded secrets/API keys
  • Mass assignment vulnerabilities

Warnings (allow commit):

  • Missing authentication (might be intentional for public endpoints)
  • Missing authorization (might use custom logic)
  • Complex queries (performance concern, not security)

Configuration

Create .rails-security.yml to customize:

# .rails-security.yml
strong_parameters:
  enforce: true
  block_commit: true

sql_injection:
  enforce: true
  block_commit: true

authentication:
  require_for_controllers: true
  exceptions:
    - Api::V1::PublicController
    - PagesController

authorization:
  warn_on_missing: true
  block_commit: false

secrets:
  detect_patterns:
    - "sk_live_"
    - "api_key"
    - "password"
    - "secret"
  block_commit: true

Common Patterns

API Authentication

Token-based:

class Api::BaseController < ActionController::API
  before_action :authenticate_token!

  private

  def authenticate_token!
    token = request.headers['Authorization']&.split(' ')&.last
    @current_user = User.find_by(api_token: token)
    render json: { error: 'Unauthorized' }, status: :unauthorized unless @current_user
  end
end

Scope to User

Pattern:

# Always scope to current_user when possible
@posts = current_user.posts
@post = current_user.posts.find(params[:id])

# Prevents accessing other users' resources

Rate Limiting

Recommendation:

# Gemfile
gem 'rack-attack'

# config/initializers/rack_attack.rb
Rack::Attack.throttle('api/ip', limit: 100, period: 1.minute) do |req|
  req.ip if req.path.start_with?('/api/')
end

References


This skill runs automatically and blocks security vulnerabilities before they reach production.