.claude/skills/security-audit/SKILL.md
Audits Rails application security against OWASP Top 10, detects vulnerabilities with Brakeman, and verifies Pundit authorization policies. Use when the user wants a security audit, vulnerability scan, or when user mentions security, OWASP, Brakeman, XSS, SQL injection, or authorization. WHEN NOT: Implementing security fixes (use specialist agents), setting up authentication (use authentication-flow), or writing Pundit policies (use policy-agent).
npx skillsauth add ThibautBaissac/rails_ai_agents security-auditInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
You are an expert in Rails application security, OWASP Top 10, and common web vulnerabilities. You NEVER modify credentials, secrets, or production files.
bin/brakeman
bin/bundler-audit check --update
bundle exec rspec spec/policies/
Audit all files in app/controllers/, app/models/, app/services/,
app/queries/, app/forms/, app/views/, app/policies/, config/.
Format: Vulnerability → Location (file:line) → Risk → Fix (code example) Prioritize: P0 (critical) → P1 (high) → P2 (medium) → P3 (low)
# Bad — SQL Injection
User.where("email = '#{params[:email]}'")
# Good — Bound parameters
User.where(email: params[:email])
# Bad — Predictable token
user.update(reset_token: SecureRandom.hex(4))
# Good — Sufficiently long token
user.update(reset_token: SecureRandom.urlsafe_base64(32))
# Bad — Logging sensitive data
Rails.logger.info("Password: #{password}")
# Good — Filter sensitive params
Rails.application.config.filter_parameters += [:password, :token, :secret]
# Bad
Nokogiri::XML(user_input)
# Good
Nokogiri::XML(user_input) { |config| config.nonet.noent }
# Bad — No authorization
@entity = Entity.find(params[:id])
# Good — Pundit
@entity = Entity.find(params[:id])
authorize @entity
# production.rb
config.force_ssl = true
<%# Bad %>
<%= raw user_input %>
<%= user_input.html_safe %>
<%# Good %>
<%= user_input %>
<%= sanitize(user_input) %>
# Bad
YAML.load(user_input)
# Good
YAML.safe_load(user_input, permitted_classes: [Symbol, Date])
bin/bundler-audit check --update
Rails.logger.warn("Failed login for #{email} from #{request.remote_ip}")
config.force_ssl = true in productionauthorize on all actionshtml_safe/raw on user inputdevelopment
Creates Turbo Streams, Turbo Frames, and morphing patterns for real-time UI updates. Use when adding real-time updates, partial page rendering, form submissions, or broadcasting. WHEN NOT: For Stimulus JavaScript controllers (see stimulus-patterns skill). For general view conventions (see rules/views.md).
testing
Writes Minitest tests with fixtures following 37signals conventions. Uses Minitest (not RSpec) and fixtures (not factories). Use when writing tests, adding test coverage, or creating fixtures. WHEN NOT: For RSpec or FactoryBot patterns (this project uses Minitest + fixtures exclusively). For test configuration/CI setup (see project docs).
tools
Builds focused, single-purpose Stimulus controllers for progressive enhancement. Use when adding JavaScript behavior, UI interactions, form enhancements, or building reusable client-side components. WHEN NOT: For Turbo Stream/Frame patterns (see turbo-patterns skill). For server-side view logic (see rules/views.md).
testing
Implements the state-as-records-not-booleans pattern for rich state tracking. Use when modeling state changes, replacing boolean flags with record-based state, or when user mentions state records, closures, publications, or toggling state. WHEN NOT: Technical flags like cached/processed (use booleans), concern extraction (use concern-patterns), general model work (use model-patterns).