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
VulnerabilityDryRun SecuritySnykCodeQLSonarQubeSemgrep
Server-Side Request Forgery (SSRF)
(Hotspot)
Cross-Site Scripting (XSS)
SQL Injection (SQLi)
IDOR / Broken Access Control
Invalid Token Validation Logic
Broken Email Verification Logic
Contextual Security Analysis
April 4, 2025

Java Spring Security Analysis Showdown

DryRun Security Shows Why Context Matters in Java Spring Application Security

Welcome to the fourth installment of our head-to-head series, where we take on a Java Spring Boot application to see how DryRun Security stacks up against traditional pattern-matching SAST tools. (Want to see past showdowns? Check these: Ruby on Rails, Python/Django, and .NET C#)

We tested DryRun Security against Snyk, GitHub CodeQL, SonarQube, and Semgrep on a Java Spring Boot app packed with intentional vulnerabilities—ranging from SQL Injection and Cross-Site Scripting (XSS) to deeper logic flaws like Insecure Direct Object Reference (IDOR) and broken authentication checks. Below is how each tool scored; DryRun Security emerged as the only tool to catch all of the major vulnerabilities, however there were two logic flaws that were missed by all SAST vendors, including DryRun Security, and for the sake of transparency in these benchmarks we have included those issues in our comparison as well. These are both addressable with our natural language code policies (NLCP), but all tools tested were used in their out-of-the-box configuration—even us!

{{table6}}

(✓ = tool detected the issue, ✗ = missed the issue)

Key Observation: The older scanners flagged the “obvious” bugs (injections, SSRF, XSS), but only DryRun Security caught multiple IDOR flaws as well as an insecure authentication check—where a malicious request can skip password verification entirely.

A Deeper Dive Into The Results

1. SSRF in User-Supplied restTemplate Call

Vulnerable Code Snippet:

@GetMapping("/client-request")
public ResponseEntity<String> fetchUrl(@RequestParam String targetUrl) {
   String data = restTemplate.getForObject(targetUrl, String.class);
   return ResponseEntity.ok(data);
}

  • DryRun Security found SSRF immediately, pointing out that user input flows into getForObject with no validation.
  • Snyk, CodeQL, Semgrep, SonarQube: All identified SSRF as a high-severity issue (though SonarQube listed it as a “Security Hotspot”).

Why It Matters: Attackers can coerce your app server to make requests to internal services, cloud metadata endpoints, or other restricted URLs, potentially disclosing sensitive data or enabling pivot attacks.

2. Cross-Site Scripting (XSS) in HTML Response

Vulnerable Code Snippet:

@GetMapping("/content")
public ResponseEntity<String> xssVuln(@RequestParam String input) {
   return ResponseEntity.ok("<html><body>" + input + "</body></html>");
}

  • Snyk, CodeQL, DryRun Security, and Semgrep: Flagged this as XSS. DryRun and others recognized that concatenating unescaped user input into HTML is dangerous.
  • SonarQube: Missed all XSS issues.
@GetMapping("/verify-email")
public ResponseEntity<String> verify(@RequestParam String userId, @RequestParam
long timestamp) {
   long now = System.currentTimeMillis();
   if (now - timestamp < 300000) {
      return ResponseEntity.ok("Email verified for user: " + userId);
    }
    return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Token 
expired");
}

  • Snyk, CodeQL, DryRun Security, and Semgrep: Flagged this as XSS. DryRun and others recognized that concatenating unescaped user input into HTML is dangerous.
  • SonarQube: Missed all XSS issues.
 @GetMapping("/client-request")
 public ResponseEntity<String> fetchUrl(@RequestParam String targetUrl) {
    String response = restTemplate.getForObject(targetUrl, String.class);
    return ResponseEntity.ok(response);
}

  • SonarQube, CodeQL, DryRun Security, and Semgrep: Missed that the SSRF issue could also potentially lead to HTML Injection if the targetUrl contains HTML and the content type returns the content as text/html.
  • Snyk: As a pleasant surprise, Snyk was the only tool that caught this potential XSS issue.

Why It Matters: XSS allows attackers to execute malicious scripts in a victim’s browser. If your endpoint returns user-supplied text as HTML, you must sanitize/encode it.

3. SQL Injection (SQLi) in JdbcTemplate Queries

Vulnerable Code Snippet:

‍String query = "SELECT * FROM users WHERE username = '" + username + "'";
List<?> users = jdbcTemplate.queryForList(query);

  • All Tools: All found it. String concatenation in a query is a well-known no-no and this is a blatantly vulnerable query. We expected that all tools would find this flaw.

String userQuery = "SELECT COUNT(*) FROM users WHERE username = '" + username +
"'";
Integer userCount = jdbcTemplate.queryForObject(userQuery, Integer.class);

  • All Tools: All found it. String concatenation in a query is a well-known no-no and this is a blatantly vulnerable query. We expected that all tools would find this flaw.

Why It Matters: SQLi is a top-tier risk (OWASP #3). Attackers can exfiltrate data, modify records, or drop entire tables. Always use parameterized queries rather than string concatenation.

4. Insecure Direct Object Reference (IDOR)

Vulnerable Code Snippet (from getUserData):

@GetMapping("/user-data/{userId}")
public ResponseEntity<String> getUserData(@PathVariable int userId,
      @RequestParam int currentUserId, @RequestParam boolean isAdmin) {
   if (userId == currentUserId || isAdmin) {
      return ResponseEntity.ok("Here is the user data");
   }
   return new ResponseEntity<>("Unauthorized", HttpStatus.UNAUTHORIZED);
}

Flaw: isAdmin is client-controlled. Anyone can send ?isAdmin=true to access another user’s data and also because userId, currentUserId, and isAdmin are all user controllable values - both conditional checks can be bypassed.

  • DryRun Security: Flagged this logical flaw as an IDOR. All other tools missed it.
  • All other tools: Legacy SAST missed this. These more traditional SAST tools rely on pattern-based checks. They are hamstrung by their underlying technology and unable to interpret custom logic (like trusting a request param for admin status) and perform real time evaluation of the conditional logic, its intent, and its efficacy.

@GetMapping("/verify-email")
public ResponseEntity<String> verify(@RequestParam String userId, @RequestParam
long timestamp) {
   long now = System.currentTimeMillis();
   if (now - timestamp < 300000) {
      return ResponseEntity.ok("Email verified for user: " + userId);
   }
   return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Token 
expired");
}

Flaw: userId is client-controlled. While this code does not show updating a record using the userId, in deeper analysis it is obvious that the intention will be to utilize the userId in order to update the record.

  • DryRun Security: Flagged this logical flaw as an IDOR. All other tools missed it.
  • Snyk, CodeQL, SonarQube, and Semgrep: Again, all traditional SAST tools missed this and are unable to interpret what code is doing. They can only search for patterns in a predefined list of patterns. Logical flaws, IDOR, and any vulnerability that requires interpreting things like intention and effect to detect will not be discovered.

Why It Matters: Broken access control is consistently a top cause of data breaches and OWASP’s #1 risk. Relying on user input for privilege checks is a big red flag.

5. Broken Authentication Logic (Missing Password Check)

Vulnerable Code Snippet:

@PostMapping("/login")
public ResponseEntity<String> login(@RequestParam String username,
                                    @RequestParam String password) {
   String userQuery = "SELECT COUNT(*) FROM users WHERE username = '" +
username + "'";
   Integer userCount = jdbcTemplate.queryForObject(userQuery, Integer.class);
   if (userCount == null || userCount == 0) {
      return ResponseEntity.badRequest().body("Invalid username");
   }
   // There's no validation for the password at all!
   return ResponseEntity.badRequest().body("Invalid credentials");
}

  • DryRun Security: Flagged it as a “weak authentication” logic flaw—password is never verified.
  • Others: No mention. As previously mentioned in this article, CodeQL, Snyk, Semgrep, and SonarQube check for patterns or rules and do not understand intent or behavior so logic flaws are not within their capabilities.

Why It Matters: Broken authentication can let attackers bypass login with just a username (or if a future change modifies the return statements). Omitting password checks is catastrophic for security. In this case, the code is not “feature-complete” in that it does not set a session or otherwise use a mechanism that authenticates a user. However, DRS understands the intention of the function and that future changes will need to take into account the missing password check.

6. Invalid Token Validation Logic

Vulnerable Code Snippet:

@GetMapping("/secure-download")
public ResponseEntity<String> download(@RequestParam String token) {
       if (token.length() > 10) {
             return ResponseEntity.ok("Here's your file");
       }
       return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Invalid 
token");
}

  • DryRun Security: Missed it. Similar to the broken email verification logic check, the token check here is insufficient. It does not ensure the format or issuance of the token is valid.
    Others: No mention. CodeQL, Snyk, Semgrep, and SonarQube cannot generally detect  logic issues.

Why It Matters: Broken logic for validating tokens as done here is something that attackers can easily identify and bypass. Insecure Design flaws (OWASP #4) are some of the most difficult to detect by SAST tooling.

7. Broken Email Verification Logic

Vulnerable Code Snippet:

@GetMapping("/verify-email")
public ResponseEntity<String> verify(@RequestParam String userId, @RequestParam
long timestamp) {
      long now = System.currentTimeMillis();
      if (now - timestamp < 300000) {
            return ResponseEntity.ok("Email verified for user: " + userId);
      }
      return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Token 
expired");
}

  • DryRun Security: Although DryRun Security did mention IDOR in this function due to the use of a userId parameter without validation, we had also expected it would catch the weak token value and validation. The problem here is that the token is not unique with high-entropy. Instead, it represents time in milliseconds. So long as it has not been longer than 5 minutes since the “token” was generated, it will pass the conditional check. Granted, the function is not really doing anything but we would have liked to see a mention of this bad pattern to account for future changes to that code.
  • Others: No mention. CodeQL, Snyk, Semgrep, and SonarQube cannot generally detect  logic issues.

Why It Matters: Broken validation logic here is not going to protect the application from verifying a user. The use of a timestamp in this way should be caught.

Why DryRun Security Leads the Pack

  • Contextual Analysis: DryRun Security goes beyond searching for known anti-patterns. It examines how code should behave (e.g., verifying passwords, validating admin privileges) and flags omissions or flawed logic.
  • Accurate + Comprehensive: DryRun found all the “standard” vulnerabilities and the deeper logic flaws. This prevents dangerous false negatives.
  • No Extra Tuning: We used the default install for every tool. DryRun’s out-of-the-box coverage was stronger and included logic flaw detection.

Final Thoughts & Next Steps

Don’t settle for “clean scans” that ignore your most critical risks—like authorization bypass and authentication mishaps. As shown, DryRun Security catches both the classic vulnerabilities and the nuanced logic bugs that can lead to real-world breaches—flaws that pattern-matching tools consistently miss.

While DryRun Security clearly outperformed all other tools significantly AND was the only tool that would have prevented breaches resulting from Insecure Direct Object Flaws (IDOR) flaws, we still missed a couple of lesser severity flaws in feature-incomplete functions. Those flaws could lead to significant issues once those functions were considered code-complete. We left these vulnerabilities and the results where all tools, including DryRun Security, missed them. We did this because we felt it was important for us to figure out our gaps and work to fix them as well as provide an honest and transparent comparison to the public.

What makes DryRun even more powerful is our Natural Language Code Policies (NLCPs). NLCPs allow teams to write custom security checks in plain English, enabling detection of organization-specific logic and validation issues that go far beyond what static rules can catch. In fact, many of our customers are already using NLCPs today to flag risky code patterns unique to their applications—and catching things that traditional scanners would never see.

AND writing custom checks in plain English means there’s no scripting required—it’s approachable for everyone from AppSec engineers to development leads, and even product managers!

Follow DryRun Security on LinkedIn and X (Twitter) for more dev-focused security tips, and be sure to download our free research paper on authorization flaws to learn how to prevent IDORs, broken access controls, and other logic-based issues.