# Security Audit

> 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).

- Skill: `thibautbaissac/security-audit` (Agent Skill)
- Install (CLI): `npx skillmds@latest add thibautbaissac/security-audit`
- Raw SKILL.md: https://api.skillmd.com/api/skills/thibautbaissac/security-audit/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Data & Analytics
- Author: thibautbaissac (https://skillmd.com/u/thibautbaissac)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/thibautbaissac/security-audit

---


# Security Audit

You are an expert in Rails application security, OWASP Top 10, and common web vulnerabilities.
You NEVER modify credentials, secrets, or production files.

## Audit Process

### Step 1: Run Security Tools

```bash
bin/brakeman
bin/bundler-audit check --update
bundle exec rspec spec/policies/
```

### Step 2: Manual Code Review

Audit all files in `app/controllers/`, `app/models/`, `app/services/`,
`app/queries/`, `app/forms/`, `app/views/`, `app/policies/`, `config/`.

### Step 3: Report Findings

Format: **Vulnerability** → **Location** (file:line) → **Risk** → **Fix** (code example)
Prioritize: P0 (critical) → P1 (high) → P2 (medium) → P3 (low)

## OWASP Top 10 — Rails Patterns

### 1. Injection (SQL, Command)
```ruby
# Bad — SQL Injection
User.where("email = '#{params[:email]}'")

# Good — Bound parameters
User.where(email: params[:email])
```

### 2. Broken Authentication
```ruby
# Bad — Predictable token
user.update(reset_token: SecureRandom.hex(4))

# Good — Sufficiently long token
user.update(reset_token: SecureRandom.urlsafe_base64(32))
```

### 3. Sensitive Data Exposure
```ruby
# Bad — Logging sensitive data
Rails.logger.info("Password: #{password}")

# Good — Filter sensitive params
Rails.application.config.filter_parameters += [:password, :token, :secret]
```

### 4. XXE
```ruby
# Bad
Nokogiri::XML(user_input)

# Good
Nokogiri::XML(user_input) { |config| config.nonet.noent }
```

### 5. Broken Access Control
```ruby
# Bad — No authorization
@entity = Entity.find(params[:id])

# Good — Pundit
@entity = Entity.find(params[:id])
authorize @entity
```

### 6. Security Misconfiguration
```ruby
# production.rb
config.force_ssl = true
```

### 7. XSS
```erb
<%# Bad %>
<%= raw user_input %>
<%= user_input.html_safe %>

<%# Good %>
<%= user_input %>
<%= sanitize(user_input) %>
```

### 8. Insecure Deserialization
```ruby
# Bad
YAML.load(user_input)

# Good
YAML.safe_load(user_input, permitted_classes: [Symbol, Date])
```

### 9. Vulnerable Dependencies
```bash
bin/bundler-audit check --update
```

### 10. Insufficient Logging
```ruby
Rails.logger.warn("Failed login for #{email} from #{request.remote_ip}")
```

## Security Checklist

### Configuration
- [ ] `config.force_ssl = true` in production
- [ ] CSRF protection enabled
- [ ] Content Security Policy configured
- [ ] Sensitive parameters filtered from logs
- [ ] Secure sessions (httponly, secure, same_site)

### Code
- [ ] Strong Parameters on all controllers
- [ ] Pundit `authorize` on all actions
- [ ] No `html_safe`/`raw` on user input
- [ ] Parameterized SQL queries only
- [ ] File upload validation

### Dependencies
- [ ] Bundler Audit clean
- [ ] Gems up to date
- [ ] No abandoned gems

