By clicking “Accept All Cookies”, you agree to the storing of cookies on your device to enhance site navigation, analyze site usage, and assist in our marketing efforts. View our Privacy Policy for more information.
ToolAccuracy of FindingsDetects Non-Pattern-Based Issues?Coverage of SAST FindingsSpeed of ScanningUsability & Dev Experience
DryRun SecurityVery high – caught multiple critical issues missed by othersYes – context-based analysis, logic flaws & SSRFBroad coverage of standard vulns, logic flaws, and extendableNear real-time PR feedback
Snyk CodeHigh on well-known patterns (SQLi, XSS), but misses other categoriesLimited – AI-based, focuses on recognized vulnerabilitiesGood coverage of standard vulns; may miss SSRF or advanced auth logic issuesFast, often near PR speedDecent GitHub integration, but rules are a black box
GitHub Advanced Security (CodeQL)Very high precision for known queries, low false positivesPartial – strong dataflow for known issues, needs custom queriesGood for SQLi and XSS but logic flaws require advanced CodeQL experience.Moderate to slow (GitHub Action based)Requires CodeQL expertise for custom logic
SemgrepMedium, but there is a good community for adding rulesPrimarily pattern-based with limited dataflowDecent coverage with the right rules, can still miss advanced logic or SSRFFast scansHas custom rules, but dev teams must maintain them
SonarQubeLow – misses serious issues in our testingLimited – mostly pattern-based, code quality orientedBasic coverage for standard vulns, many hotspots require manual reviewModerate, usually in CIDashboard-based approach, can pass “quality gate” despite real vulns
Vulnerability ClassSnyk (partial)GitHub (CodeQL) (partial)SemgrepSonarQubeDryRun Security
SQL Injection
*
Cross-Site Scripting (XSS)
SSRF
Auth Flaw / IDOR
User Enumeration
Hardcoded Token
ToolAccuracy of FindingsDetects Non-Pattern-Based Issues?Coverage of C# VulnerabilitiesScan SpeedDeveloper Experience
DryRun Security
Very high – caught all critical flaws missed by others
Yes – context-based analysis finds logic errors, auth flaws, etc.
Broad coverage of OWASP Top 10 vulns plus business logic issuesNear real-time (PR comment within seconds)Clear single PR comment with detailed insights; no config or custom scripts needed
Snyk CodeHigh on known patterns (SQLi, XSS), but misses logic/flow bugsLimited – focuses on recognizable vulnerability patterns
Good for standard vulns; may miss SSRF or auth logic issues 
Fast (integrates into PR checks)Decent GitHub integration, but rules are a black box (no easy customization)
GitHub Advanced Security (CodeQL)Low - missed everything except SQL InjectionMostly pattern-basedLow – only discovered SQL InjectionSlowest of all but finished in 1 minuteConcise annotation with a suggested fix and optional auto-remedation
SemgrepMedium – finds common issues with community rules, some missesPrimarily pattern-based, limited data flow analysis
Decent coverage with the right rules; misses advanced logic flaws 
Very fast (runs as lightweight CI)Custom rules possible, but require maintenance and security expertise
SonarQube
Low – missed serious issues in our testing
Mostly pattern-based (code quality focus)Basic coverage for known vulns; many issues flagged as “hotspots” require manual review Moderate (runs in CI/CD pipeline)Results in dashboard; risk of false sense of security if quality gate passes despite vulnerabilities
Vulnerability ClassSnyk CodeGitHub Advanced Security (CodeQL)SemgrepSonarQubeDryRun Security
SQL Injection (SQLi)
Cross-Site Scripting (XSS)
Server-Side Request Forgery (SSRF)
Auth Logic/IDOR
User Enumeration
Hardcoded Credentials
VulnerabilityDryRun SecuritySemgrepGitHub CodeQLSonarQubeSnyk Code
1. Remote Code Execution via Unsafe Deserialization
2. Code Injection via eval() Usage
3. SQL Injection in a Raw Database Query
4. Weak Encryption (AES ECB Mode)
5. Broken Access Control / Logic Flaw in Authentication
Total Found5/53/51/51/50/5
Security
March 13, 2025

DryRun Security vs. Traditional SAST Vendors in Ruby on Rails

We go head-to-head, comparing DryRun Security to Snyk Code, GitHub Advanced Security (CodeQL), Semgrep, and SonarQube in a Ruby on Rails application.

Today’s static application security testing (SAST) tools vary widely in how accurately they catch vulnerabilities and how usable they are for developers. We decided it’d be useful to do a head-to-head comparison using some intentionally vulnerable code in RailsGoat—specifically changes introduced in this PR #9 in our forked repo. This repo had DryRun Security running alongside Snyk Code, GitHub Advanced Security (CodeQL), Semgrep, and SonarQube/SonarCloud.

We focused on accuracy of findings, the ability to catch non-pattern-based issues, and overall coverage (including logic flaws, authorization mishaps, and SSRF). Below is a detailed comparison and a head-to-head look at why DryRun Security delivers superior SAST accuracy and effectiveness for a modern application security program. Note that here we are using DryRun Security out of the box and chose not to use Natural Language Code Policies (NLCP) for this head-to-head comparison.

The Short Comparison Grid

Here’s a concise table comparing each tool’s accuracy, coverage, scanning speed, false positives, and developer experience. We tested each tool on the changes made in PR #9, which contained a mix of obvious vulnerabilities (like SQL Injection and XSS) plus less obvious logic flaws (like user enumeration, authorization bypasses, and SSRF).

{{table}}

Evaluating the Tools: Who Gets It Right?

To ground our comparison in code, we tested several major vulnerability categories in a pull request: RailsGoat PR #9. This PR modifies or adds code in ways that demonstrate:

  1. SQL Injection (SQLi)
  2. Cross-Site Scripting (XSS)
  3. Server-Side Request Forgery (SSRF)
  4. Logic/Authorization Flaws (e.g., IDOR or missing auth checks)
  5. User Enumeration (detailed error messages)
  6. Hardcoded / Insecure Token Generation

Below are short summaries of each category and how each tool measured up. We finish with a scoreboard table showing final tallies.

1. SQL Injection (SQLi)

What Happened in the Pull Request (DryRunSecuritySandbox/railsgoat - PR #9):

def username_lookup
  user = ActiveRecord::Base.connection.execute("SELECT * FROM users WHERE username = '#{params[:username]}'")
  ...
end

Additionally, another raw query in a model method uses string interpolation without parameterization.

Vulnerability Explanation (OWASP / Rails Context):
SQL Injection allows attackers to alter queries by injecting malicious SQL commands. Although Rails’ ActiveRecord typically parameterizes queries, developers can bypass these safeguards by manually concatenating user input. OWASP’s SQL Injection Prevention Cheat Sheet discusses the severity of SQLi, while the Rails Security Guide details how to safely handle user input.

Tool Detection

  • Snyk: Found the injection in the controller (✓), but missed the second query in the model (partial).
  • GitHub Advanced Security (CodeQL): Found the main injection (✓), also missing the second one (partial).
  • Semgrep: Missed it (✗).*
  • SonarQube: Missed it (✗).
  • DryRun Security: Found both instances (✓).

2. Cross-Site Scripting (XSS)

What Happened in the Pull Request (DryRunSecuritySandbox/railsgoat - PR #9):

<p>  
	Here is your content: <%= params[:user_input].html_safe %>
</p>

Vulnerability Explanation (OWASP / Rails Context):
XSS occurs when attackers inject scripts into pages viewed by other users. Rails automatically escapes variables by default, but using html_safe, raw, or <%== %> can disable this. OWASP’s XSS Prevention Cheat Sheet explains how reflected, stored, or DOM-based XSS can be introduced. Rails docs caution developers against using html_safe on untrusted inputs (see Rails Security Guide on XSS).

Tool Detection

  • Snyk: Found it (✓).
  • GitHub Advanced Security (CodeQL): Found it (✓).
  • Semgrep: Found it (✓).
  • SonarQube: Missed it (✗).
  • DryRun Security: Found it (✓).

3. Server-Side Request Forgery (SSRF)

What Happened in the Pull Request (DryRunSecuritySandbox/railsgoat - PR #9):

def client_request
  target_url = params[:external_resource]  
  uri = URI.parse(target_url)  
  response = Net::HTTP.get(uri)
end

Vulnerability Explanation (OWASP / Rails Context):
SSRF flaws arise when the server fetches a remote resource using a URL supplied by the user, allowing attackers to potentially reach internal services or cloud metadata endpoints. OWASP’s SSRF Prevention Cheat Sheet describes how these attacks pivot into private networks or read sensitive data. In Rails, classes like Net::HTTP or OpenURI can be misused for SSRF if user input isn’t validated.

Tool Detection

  • Snyk: Missed it (✗).
  • GitHub Advanced Security (CodeQL): Missed it (✗).
  • Semgrep: Found it (✓).
  • SonarQube: Missed it (✗).
  • DryRun Security: Found it (✓).

4. Logic/Authorization Flaws (IDOR / Missing Auth Checks)

What Happened in the Pull Request (DryRunSecuritySandbox/railsgoat - PR #9):

def show_confidential_info
  data = ConfidentialModel.find(params[:id])  
  render json: data
end

Vulnerability Explanation (OWASP / Rails Context):
Insecure direct object references (IDOR) let users access data by manipulating an identifier (e.g., /record/123). If no authorization check exists, an attacker can read or modify resources they don’t own. OWASP’s Broken Access Control references IDOR as a top vulnerability. Rails doesn’t automatically enforce authorization for resource-based actions—developers must implement checks (e.g., using Pundit, CanCanCan, or manual logic) to prevent unauthorized data access.

Tool Detection

  • Snyk: Missed it (✗).
  • GitHub Advanced Security (CodeQL): Missed it (✗).
  • Semgrep: Missed it (✗).
  • SonarQube: Missed it (✗).
  • DryRun Security: Found it (✓).

5. User Enumeration (Detailed Error Messages)

What Happened in the Pull Request (DryRunSecuritySandbox/railsgoat - PR #9):

if user.nil?  
  render json: { error: "User not found: #{params[:username]}" }
else  
  unless user.authenticate(params[:password])
    render json: { error: "Incorrect password for user #{params[:username]}" }  
  end
end

Vulnerability Explanation (OWASP / Rails Context):
By returning different responses when a user doesn’t exist vs. when a password is incorrect, attackers can brute-force valid usernames. This practice is covered by the OWASP Testing Guide on user enumeration and guessable user accounts. Rails developers often display friendlier messages, but it’s recommended to use a generic message like “Invalid username or password” for all login failures.

Tool Detection

  • Snyk: Missed it (✗).
  • GitHub Advanced Security (CodeQL): Missed it (✗).
  • Semgrep: Missed it (✗).
  • SonarQube: Missed it (✗).
  • DryRun Security: Found it (✓).

6. Hardcoded / Insecure Token Generation

What Happened in the Pull Request (DryRunSecuritySandbox/railsgoat - PR #9):

def generate_jwt(user)
  "fake-jwt-token-for-user-#{user.id}"
end

Vulnerability Explanation (OWASP / Rails Context):
Tokens must be unpredictable and securely generated. Hardcoding or predictable generation lets attackers guess tokens and impersonate other users. OWASP warns against this in various references to session management and token randomness. In Rails, the Security Guide notes that secret keys and session tokens must be random. Libraries like SecureRandom are typically used for robust token generation; never rely on incremental IDs or static strings.

Tool Detection

  • Snyk: Missed it (✗).
  • GitHub Advanced Security (CodeQL): Missed it (✗).
  • Semgrep: Missed it (✗).
  • SonarQube: Missed it (✗).
  • DryRun Security: Found it (✓).

The Final Scoreboard

Here’s the scoreboard of who caught each vulnerability in our sample pull request (RailsGoat PR #9):

{{table2}}

In plain numbers:

  • Snyk: 2/6 (partial SQLi, XSS)
  • GitHub Advanced Security (CodeQL): 2/6 (partial SQLi, XSS)
  • Semgrep: 2/6 (XSS, partial SSRF)*
  • SonarQube: 0/6
  • DryRun Security: 6/6

Why DryRun Security Wins

From these findings, DryRun Security clearly outperforms the competition. While Snyk, CodeQL, and Semgrep did okay on classic pattern-based issues (XSS, SSRF), they struggle with anything requiring deeper logic analysis, like authorization issues, user enumeration, or insecure tokens. SonarQube, in its default configuration, missed everything. 

1. Contextual Security Analysis Goes Beyond Pattern Matching

DryRun Security digs into how your code processes data (e.g., user-supplied URLs, tokens, or error messages), instead of merely searching for known signatures. That’s why it caught SSRF in a Net::HTTP.get call and recognized that multiple error messages in an auth flow amount to user enumeration. Traditional SAST often can’t handle such nuanced logic.

2. Real-Time, Developer-Friendly Feedback

Instead of burying issues or issuing a bunch of GitHub comments, DryRun Security posts just one straightforward PR comment explaining what’s wrong, why it’s risky, and how to fix it. The feedback arrives quickly—often within seconds—keeping developers in their workflow and preventing critical vulnerabilities from hitting production.

3. Extendable Natural Lang Code Policies (NLCP)

While we didn’t use NLCP here, it’s worth emphasizing that DryRun Security supports Natural Language Code Policies, meaning you can craft new rules in plain English. AppSec teams love this because it doesn’t require specialized rule languages (like CodeQL or Semgrep patterns). For example, you could easily define, “Don’t allow token generation that doesn’t use SecureRandom” or “Reject any reference to internal IP ranges in user-supplied URLs” and “Does this change allow users to submit unrestricted GraphQL queries?”. DryRun then enforces those policies automatically in every PR.

4. Comprehensive Coverage with Minimal Noise

The scoreboard proves DryRun’s thoroughness. Yet it doesn’t flood teams with false positives. We know we didn’t cover false positives in the samples, but stay tuned for exciting future posts! By focusing on real vulnerabilities, DryRun fosters trust in the tool’s alerts—developers know that when DryRun flags something, it’s genuinely worth investigating.

Bringing It All Together

DryRun Security detects serious security bugs that other tools consistently miss. DryRun Security combines automated intelligence, policy-driven scanning, and a developer-friendly interface makes it ideal for DevSecOps teams that can’t afford to let SSRF, IDOR, BOLA, or insecure tokens slip through. DryRun goes beyond mere pattern matching to catch hidden, context-driven vulnerabilities.

Pair that with:

  • Instant alerts in GitHub or Slack,
  • Human-readable policies (no specialized syntax),
  • Support for new languages and frameworks on demand,

…and you have a SAST solution that not only catches known vulnerabilities but adapts to the ever-changing threat landscape. The riskiest flaws aren’t always the “classic” CVEs—often, they’re hidden in your application logic, waiting to be exploited.

With DryRun Security, it’s like having an AppSec expert reviewing every pull request—only faster, more accurately, and around the clock.

Ready to see the difference?

If you're tired of juggling multiple scanners, missing critical logic flaws, and drowning in false positives, see how DryRun Security helps you catch real risks that other SAST tools can’t find. Schedule a 30-minute demo today.

*Correction: March 18, 2025

An engineer from Semgrep let us know that the most recent version of the rule does catch SQLi although it did not at the time of our initial blog post publication.