review-security
Use this skill when reviewing Hanami 2.x code for security concerns.
Core principle: Security is layered. Validate at the boundary, authenticate explicitly, and never trust input.
Review Workflow
Follow this sequence when performing a security review. For each step, the Red Flag column indicates a failing condition; if a red flag is found, apply the remediation noted in Core Rules below.
| # |
Concern |
Grep / Check |
Red Flag |
Severity |
| 1 |
Param validation |
grep -rn 'request.params' app/actions/ | grep -v 'params do' |
request.params used directly in business logic without a params block |
Critical |
| 2 |
CSRF protection |
Check config/app.rb for config.actions.csrf_protection |
Missing csrf_protection = true for HTML endpoints |
Critical |
| 3 |
Authentication |
grep -rn 'def handle' app/actions/ cross-checked with grep -rn 'authenticate' |
Auth assumed by convention, no explicit before :authenticate! |
Critical |
| 4 |
Authorization |
Review Actions and service objects for role/permission checks |
Only authn present, no authz |
High |
| 5 |
Secrets in code |
grep -rn 'secret|password|api_key|token' app/ config/ --include='*.rb' | grep -v 'settings|ENV' |
Hardcoded strings for keys/secrets in source files |
Critical |
| 6 |
Logging |
grep -rn 'logger' app/ | grep 'password|token|secret' |
params[:password] or tokens in log calls |
High |
| 7 |
SQL injection |
grep -rn 'where("' app/ |
String interpolation in where("...") |
Critical |
| 8 |
XSS / template output |
grep -rn 'raw ' app/ |
raw or html_safe on user input |
Critical |
| 9 |
Session config |
Review config.sessions in config/app.rb |
No secret, hardcoded secret, or no expiration |
High |
| 10 |
Error messages |
Review auth failure responses |
Messages like "User not found" or "Password incorrect" (user enumeration) |
Advisory |
Completion Checkpoint
After completing all steps, compile findings into a summary:
- Critical — Must be fixed before merge; these are exploitable vulnerabilities (SQL injection, missing auth, hardcoded secrets, missing CSRF, direct param use, XSS).
- High — Should be fixed soon; meaningful risk but harder to exploit directly (missing authz, sensitive logging, insecure session config).
- Advisory — Best-practice improvements with lower immediate risk (generic error messages, structural hardening).
For each finding, report: location (file + line), severity, a summary of the issue (never include actual secret values, passwords, tokens, or API keys — describe their presence without exposing them), and the recommended fix (see Core Rules).
Core Rules
Detailed remediation patterns for each finding category.
Validate all params via the Params DSL:
# GOOD
params do
required(:email).value(:string, format?: /\A.+@.+\z/)
required(:password).value(:string, min_size?: 8)
end
# BAD
user_repo.create(request.params)
Enable CSRF protection for HTML endpoints:
# config/app.rb
config.actions.csrf_protection = true
Authenticate in Actions using injected services:
include Deps["authentication"]
before :authenticate!
def authenticate!(request, response)
halt 401 unless authentication.valid?(request)
end
Never log sensitive data:
# GOOD
logger.info("Login attempt: #{params[:email]}")
# BAD: logger.info("Login: #{params[:email]}, password: #{params[:password]}")
Store secrets in settings, never in code:
# config/settings.rb
setting :session_secret, constructor: Types::String
# .env
SESSION_SECRET=your-secret-here
Prevent SQL injection using ROM's query interface:
# GOOD: users.where(email: params[:email]).one
# BAD: users.where("email = '#{params[:email]}'").one
Escape output in templates — ERB auto-escapes by default; never use raw on user input:
<!-- GOOD -->
<p><%= user.bio %></p>
Use secure session configuration:
config.sessions = :cookie, {
key: "my_app.session",
secret: settings.session_secret,
expire_after: 60 * 60 * 24 * 7
}
Return generic error messages for auth failures:
# GOOD: halt 401, { error: "Invalid credentials" }.to_json
# BAD: halt 401, { error: "User not found" }.to_json
Integration
| Related Skill |
When to chain |
| validate-params |
All params must be validated before use. |
| handle-errors |
Error responses must not leak sensitive information. |
| settings |
Secrets and configuration must use Settings, not hardcoded values. |
| code-review |
Security review is part of every code review. |
| setup-authentication |
For implementing auth strategies. |
| security-review-process (from ruby-core-skills) |
OWASP checklist, Ruby-level security concerns. |
1---2name: review-security3description: Use when conducting a security audit, security review, vulnerability assessment, vulnerability check, or secure coding review on Hanami 2.x applications — validate params via the Params DSL in every Action, verify CSRF protection is enabled in config/app.rb, audit authentication checks via explicit `before :authenticate!`, check authorization with role/permission checks, never log passwords/tokens/secrets, use ROM query interface to prevent SQL injection (no string interpolation in `where("...")`), never use `raw` on user input in templates, store secrets in settings not hardcoded, and return generic error messages for auth failures. Validates parameter handling, CSRF, auth integration, XSS, session configuration, and hardening posture.4license: MIT5---67# review-security89Use this skill when reviewing Hanami 2.x code for security concerns.1011**Core principle:** Security is layered. Validate at the boundary, authenticate explicitly, and never trust input.1213---1415## Review Workflow1617Follow this sequence when performing a security review. For each step, the **Red Flag** column indicates a failing condition; if a red flag is found, apply the remediation noted in **Core Rules** below.1819| # | Concern | Grep / Check | Red Flag | Severity |20|---|---|---|---|---|21| 1 | **Param validation** | `grep -rn 'request.params' app/actions/ \| grep -v 'params do'` | `request.params` used directly in business logic without a `params` block | Critical |22| 2 | **CSRF protection** | Check `config/app.rb` for `config.actions.csrf_protection` | Missing `csrf_protection = true` for HTML endpoints | Critical |23| 3 | **Authentication** | `grep -rn 'def handle' app/actions/` cross-checked with `grep -rn 'authenticate'` | Auth assumed by convention, no explicit `before :authenticate!` | Critical |24| 4 | **Authorization** | Review Actions and service objects for role/permission checks | Only authn present, no authz | High |25| 5 | **Secrets in code** | `grep -rn 'secret\|password\|api_key\|token' app/ config/ --include='*.rb' \| grep -v 'settings\|ENV'` | Hardcoded strings for keys/secrets in source files | Critical |26| 6 | **Logging** | `grep -rn 'logger' app/ \| grep 'password\|token\|secret'` | `params[:password]` or tokens in log calls | High |27| 7 | **SQL injection** | `grep -rn 'where("' app/` | String interpolation in `where("...")` | Critical |28| 8 | **XSS / template output** | `grep -rn 'raw ' app/` | `raw` or `html_safe` on user input | Critical |29| 9 | **Session config** | Review `config.sessions` in `config/app.rb` | No secret, hardcoded secret, or no expiration | High |30| 10 | **Error messages** | Review auth failure responses | Messages like "User not found" or "Password incorrect" (user enumeration) | Advisory |3132### Completion Checkpoint3334After completing all steps, compile findings into a summary:35- **Critical** — Must be fixed before merge; these are exploitable vulnerabilities (SQL injection, missing auth, hardcoded secrets, missing CSRF, direct param use, XSS).36- **High** — Should be fixed soon; meaningful risk but harder to exploit directly (missing authz, sensitive logging, insecure session config).37- **Advisory** — Best-practice improvements with lower immediate risk (generic error messages, structural hardening).3839For each finding, report: location (file + line), severity, a summary of the issue (never include actual secret values, passwords, tokens, or API keys — describe their presence without exposing them), and the recommended fix (see Core Rules).4041---4243## Core Rules4445Detailed remediation patterns for each finding category.46471. **Validate all params** via the Params DSL:4849 ```ruby50 # GOOD51 params do52 required(:email).value(:string, format?: /\A.+@.+\z/)53 required(:password).value(:string, min_size?: 8)54 end5556 # BAD57 user_repo.create(request.params)58 ```59602. **Enable CSRF protection** for HTML endpoints:6162 ```ruby63 # config/app.rb64 config.actions.csrf_protection = true65 ```66673. **Authenticate in Actions** using injected services:6869 ```ruby70 include Deps["authentication"]71 before :authenticate!7273 def authenticate!(request, response)74 halt 401 unless authentication.valid?(request)75 end76 ```77784. **Never log sensitive data**:7980 ```ruby81 # GOOD82 logger.info("Login attempt: #{params[:email]}")83 # BAD: logger.info("Login: #{params[:email]}, password: #{params[:password]}")84 ```85865. **Store secrets in settings**, never in code:8788 ```ruby89 # config/settings.rb90 setting :session_secret, constructor: Types::String91 ```92 ```bash93 # .env94 SESSION_SECRET=your-secret-here95 ```96976. **Prevent SQL injection** using ROM's query interface:9899 ```ruby100 # GOOD: users.where(email: params[:email]).one101 # BAD: users.where("email = '#{params[:email]}'").one102 ```1031047. **Escape output in templates** — ERB auto-escapes by default; never use `raw` on user input:105106 ```erb107 <!-- GOOD -->108 <p><%= user.bio %></p>109 ```1101118. **Use secure session configuration**:112113 ```ruby114 config.sessions = :cookie, {115 key: "my_app.session",116 secret: settings.session_secret,117 expire_after: 60 * 60 * 24 * 7118 }119 ```1201219. **Return generic error messages** for auth failures:122123 ```ruby124 # GOOD: halt 401, { error: "Invalid credentials" }.to_json125 # BAD: halt 401, { error: "User not found" }.to_json126 ```127128---129130## Integration131132| Related Skill | When to chain |133|---|---|134| **validate-params** | All params must be validated before use. |135| **handle-errors** | Error responses must not leak sensitive information. |136| **settings** | Secrets and configuration must use Settings, not hardcoded values. |137| **code-review** | Security review is part of every code review. |138| **setup-authentication** | For implementing auth strategies. |139| **security-review-process** *(from ruby-core-skills)* | OWASP checklist, Ruby-level security concerns. |