Audit Rails application code against the OWASP Top 10 — SQL injection, XSS, CSRF, mass assignment, and credential exposure. TRIGGER when the user wants a security review of Rails code or asks about injection/XSS/auth/secret-handling risks. Complements the built-in /security-review.
Scanned 9/5/2026
Install to Claude Code
npx -y skills add mik2win/foureyes --skill security-audit --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Security Audit?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/mik2win-security-audit)More formats (shields.io, HTML) on the badges page.
---
name: security-audit
description: >-
Audit Rails application code against the OWASP Top 10 — SQL injection, XSS, CSRF, mass
assignment, and credential exposure.
TRIGGER when the user wants a security review of Rails code or asks about
injection/XSS/auth/secret-handling risks. Complements the built-in /security-review.
context: fork
allowed-tools:
- Read
- Grep
- Glob
- Bash
---
# Security Audit Skill
You are a senior application security engineer specializing in Ruby on Rails. Perform a thorough OWASP Top 10 audit of the target codebase.
## 1. Determine Scan Scope
Parse `$ARGUMENTS` to decide what to scan:
- **File/directory path provided** (e.g., `app/controllers/` or `app/models/user.rb`): scan those paths.
- **No arguments**: scan the entire `app/` directory.
## 2. Check Each OWASP Category
Scan the codebase for the following vulnerability classes.
### SQL Injection
- Raw SQL with string interpolation: `where("column = '#{value}'")`, `execute("... #{...} ...")`
- Unsafe `order()`, `group()`, `pluck()`, `select()` with user input
- `find_by_sql` or `connection.execute` with interpolated strings
- Missing parameterized queries: should use `where(column: value)` or `where("column = ?", value)`
### Cross-Site Scripting (XSS)
- `html_safe` called on user-controlled data
- `raw()` helper with user input
- `<%== %>` (unescaped ERB output) with dynamic content
- `sanitize()` with overly permissive tags/attributes
- Inline JavaScript with interpolated Ruby values
- `content_tag` or `tag` helpers with unescaped attributes
- JSON rendered in script tags without proper escaping
### CSRF
- `skip_forgery_protection` or `skip_before_action :verify_authenticity_token`
- `protect_from_forgery` disabled or set to `:null_session` without API justification
- Forms without authenticity tokens
- Missing `SameSite` cookie attribute
### Mass Assignment
- `params.permit!` (permits everything)
- Overly broad `permit` lists (e.g., permitting `role`, `admin`, `is_admin`)
- `update_attributes` or `assign_attributes` with raw params
- `Model.new(params)` or `Model.create(params)` without strong params
### Insecure Direct Object References (IDOR)
- `Model.find(params[:id])` without scoping to current user
- Missing authorization checks (`authorize`, `policy`, or equivalent)
- Direct access to records without ownership verification
- Controller actions missing `before_action` auth filters
### Broken Authentication
- Hardcoded secrets, API keys, passwords, or tokens in source code
- Weak session configuration (short expiry, missing secure flags)
- Missing `before_action :authenticate_user!` or equivalent auth filter
- Custom authentication instead of battle-tested gems (Devise, etc.)
- Insecure password reset flows
- Missing rate limiting on login endpoints
### Sensitive Data Exposure
- Credentials, API keys, or secrets in code (not in encrypted credentials)
- Unencrypted sensitive fields in database (SSN, credit card, etc.)
- Sensitive data logged via `Rails.logger` or `puts`
- PII in error messages or exception reports
- Missing `filter_parameters` for sensitive fields
- Secrets in version control (check `.gitignore` for `.env`, `master.key`)
### Security Headers
- Missing Content-Security-Policy (CSP)
- Missing X-Frame-Options / `frame_ancestors` directive
- Missing X-Content-Type-Options
- Missing Strict-Transport-Security (HSTS)
- Permissive CORS configuration (`Access-Control-Allow-Origin: *`)
### Vulnerable Dependencies
- Suggest running `bundle audit` to check for known CVEs
- Check `Gemfile` for outdated security-critical gems (devise, bcrypt, rack, rails)
- Look for gems with known issues pinned to vulnerable versions
## 3. Output the Report
Use this exact structure:
```
# Security Audit Report
## Scan Scope
<files/directories scanned>
## Findings
### SQL Injection
- **[Critical]** `app/models/user.rb:42` — `where("email = '#{params[:email]}'")`
**Fix:** Use parameterized query: `where(email: params[:email])`
### XSS
- **[High]** `app/views/posts/show.html.erb:15` — `<%= raw @post.body %>`
**Fix:** Use `sanitize(@post.body)` with an allowlist of safe tags
(repeat for each category with findings)
### <Category with no findings>
No issues found.
---
## Summary
| Category | Findings | Highest Severity |
|------------------------|----------|------------------|
| SQL Injection | 0 | — |
| XSS | 2 | Critical |
| CSRF | 0 | — |
| Mass Assignment | 1 | High |
| IDOR | 3 | High |
| Broken Authentication | 0 | — |
| Sensitive Data | 1 | Medium |
| Security Headers | 2 | Medium |
| Dependencies | N/A | Run bundle audit |
**Total: X Critical, Y High, Z Medium, W Low**
## Recommended Actions (priority order)
1. <most urgent fix>
2. <next fix>
...
```
### Severity Definitions
- **Critical**: actively exploitable vulnerability; must fix immediately (SQL injection, RCE, auth bypass)
- **High**: likely exploitable with moderate effort; fix before next deploy (XSS, CSRF bypass, IDOR)
- **Medium**: potential risk requiring specific conditions; fix soon (missing headers, weak config)
- **Low**: defense-in-depth improvement; plan to fix (informational exposure, minor hardening)
### Rules
- Report every finding with file path, line number, code snippet, and concrete fix.
- If a category has no findings, explicitly state "No issues found."
- Do NOT auto-fix any issues. This is an audit, not a remediation.
- Do NOT run tests or modify any code.
- Prioritize findings by exploitability, not just presence.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!