Class: RailsMcpInsight::Analyzers::SecurityAnalyzer
- Inherits:
-
Object
- Object
- RailsMcpInsight::Analyzers::SecurityAnalyzer
- Defined in:
- lib/rails_mcp_insight/analyzers/security_analyzer.rb
Overview
Static security analysis for common Rails vulnerabilities. Checks for SQL injection, mass assignment, CSRF, XSS patterns.
Constant Summary collapse
- CHECKS =
{ sql_injection: { pattern: /\.where\(\s*["'][^"']*#\{/, description: "Possible SQL injection via string interpolation in .where()", severity: "high" }, raw_sql: { pattern: /\.execute\s*\(|ActiveRecord::Base\.connection\.exec/, description: "Raw SQL execution — verify inputs are sanitized", severity: "medium" }, mass_assignment: { pattern: /\.update_attributes?\s*\(\s*params\b(?!.*permit)/, description: "Possible mass assignment — params passed directly without permit", severity: "high" }, open_redirect: { pattern: /redirect_to\s+params\[/, description: "Possible open redirect — redirecting to user-supplied URL", severity: "high" }, html_safe: { pattern: /\.html_safe\b/, description: "Using .html_safe may allow XSS if applied to user input", severity: "medium" }, raw_helper: { pattern: /\braw\s*\(/, description: "raw() bypasses HTML escaping — verify content is safe", severity: "medium" }, send_method: { pattern: /\.send\s*\(\s*params\b/, description: "Dynamic dispatch using params — possible arbitrary method call", severity: "high" }, eval_usage: { pattern: /\beval\s*\(/, description: "eval() usage — extremely dangerous if user input reaches here", severity: "critical" }, system_call: { pattern: /\bsystem\s*\(|\bexec\s*\(|`[^`]*#\{/, description: "System/exec call — verify no user input is injected", severity: "high" }, cookie_serialization: { pattern: /cookies\.signed|cookies\.encrypted.*Marshal/, description: "Cookie serialization — ensure using JSON serializer, not Marshal", severity: "medium" } }.freeze
Instance Method Summary collapse
-
#analyze(focus: nil) ⇒ Object
Run all security checks or a specific focus area.
-
#initialize(config) ⇒ SecurityAnalyzer
constructor
A new instance of SecurityAnalyzer.
Constructor Details
#initialize(config) ⇒ SecurityAnalyzer
Returns a new instance of SecurityAnalyzer.
61 62 63 |
# File 'lib/rails_mcp_insight/analyzers/security_analyzer.rb', line 61 def initialize(config) @config = config end |
Instance Method Details
#analyze(focus: nil) ⇒ Object
Run all security checks or a specific focus area
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/rails_mcp_insight/analyzers/security_analyzer.rb', line 66 def analyze(focus: nil) checks_to_run = if focus CHECKS.select { |k, _| k.to_s == focus.to_s } else CHECKS end findings = [] ruby_files = Dir.glob(File.join(@config.app_path, "**", "*.rb")) ruby_files += Dir.glob(File.join(@config.lib_path, "**", "*.rb")) if Dir.exist?(@config.lib_path) ruby_files.each do |file| content = File.read(file) lines = content.lines checks_to_run.each do |check_name, check| lines.each_with_index do |line, idx| next if line.strip.start_with?("#") next unless line.match?(check[:pattern]) findings << { check: check_name.to_s, severity: check[:severity], description: check[:description], file: relative_path(file), line: idx + 1, code: line.strip } end end end { total_findings: findings.length, by_severity: { critical: findings.count { |f| f[:severity] == "critical" }, high: findings.count { |f| f[:severity] == "high" }, medium: findings.count { |f| f[:severity] == "medium" } }, findings: findings.sort_by { |f| severity_order(f[:severity]) } } end |