Benchmark · Security · Java

OWASP Benchmark for Java

How well quodeq 1.12 tells real vulnerabilities from safe look-alikes, with five models, on 2,740 test cases.

Tool
quodeq 1.12.0
Test
OWASP Benchmark for Java 1.2
Run
4 and 5 October 2026
Runs per model
1
Measured by
Victor Purcallas Marchesi
2,740test cases
5models
0.77best score, of 1.00
91% / 14%found / false alarms, best run

Abstract

Quodeq is an open-source tool that uses a language model to review code against written standards. This report measures how well its security review separates real vulnerabilities from safe code that looks the same. Quodeq 1.12.0 was run once with each of five models on the OWASP Benchmark for Java, which has 2,740 labelled test cases. With the two large cloud models it found 83% and 91% of the real vulnerabilities while flagging 15% and 14% of the safe cases, a score of 0.68 and 0.77. Published results for rule-based scanners on the same cases range from 0.32 to 0.60. Two open models run locally found as much as the best cloud model but flagged 65% and 72% of the safe cases, a score of 0.20. Accuracy fell for every model when the evidence was in a second file, which quodeq does not ask the model to open. The run also exposed three defects in the tool itself: an overall grade that does not respond to the number of violations, a severity rating that depends on the model, and files skipped without notice. The benchmark is public and the models have probably seen it, so these results are an upper bound.

Key findings

  1. Detection depends on the model. The same pipeline scored between 0.20 and 0.77.
  2. Large cloud models separate safe from vulnerable code. Claude Sonnet 5.5 scored 0.77 and GPT-6 Sol 0.68, above the published scores of rule-based scanners on this benchmark.
  3. Local models find as much and discriminate far less. Gemma 4 and Qwen 3.8 found 85% and 92% and flagged 65% and 72% of safe code.
  4. Cross-file evidence is the main remaining error. The best model went from finding 96% with 9% false alarms to 69% with 29%.
  5. The tool's own grade and severity are not reliable. The overall grade ranged from 3.5 to 4.8 out of 10 for an application built to be vulnerable.

1. Setup

1.1 Benchmark

The OWASP Benchmark for Java, version 1.2, is an application built to be vulnerable. It has 2,740 test cases in 11 categories, each mapped to one CWE. 1,415 contain a real vulnerability. The other 1,325 are near-identical and safe. The ground truth ships with the project.

Each category is one kind of mistake.

Table 1The eleven categories of the benchmark and what each one tests.
CategoryWhat goes wrong
SQL injectionInput from the user ends up inside a database query, so an attacker can change what the query does.
Cross-site scripting (XSS)Input is written into a web page without escaping, so an attacker can run script in someone else's browser.
Command injectionInput ends up inside an operating system command.
Path traversalInput chooses a file path, so an attacker can reach files outside the intended folder.
LDAP injectionInput changes a query against a user directory.
XPath injectionInput changes a query over XML data.
Weak cipherData is encrypted with an algorithm that is considered broken, such as DES.
Weak hashA broken hash function such as MD5 or SHA-1 is used.
Weak randomnessA predictable random number generator produces something that must be unguessable, such as a session token.
Insecure cookieA cookie is set without the Secure flag, so it can travel over an unencrypted connection.
Trust boundaryUnchecked input is stored in the session, where the rest of the application treats it as trusted.

The first six and the last one depend on following data: the line is only a problem if something an attacker controls can reach it. The other four can be judged from the line itself. This distinction accounts for most of the differences reported below.

1.2 Runs

Quodeq 1.12.0, security dimension only, one run per model, same standards and prompts. Three cloud models (Claude Sonnet 5.5, GPT-6 Sol, GPT-6 Luna) and two open models served locally by Ollama (Gemma 4 26B, Qwen 3.8 27B). Each run is reported as it finished. No run was repeated or corrected.

2. Method

2.1 Scoring

A test case counts as flagged when quodeq reported a violation in its file under a security requirement that covers the case's CWE. A violation of an unrelated requirement in the same file does not count. From that:

  • Found is the share of the 1,415 real vulnerabilities that were flagged.
  • False alarms is the share of the 1,325 safe cases that were flagged anyway.
  • Score is found minus false alarms. This is the benchmark's own measure. A perfect tool scores 1. A tool that flags every case, or none, scores 0.

Quodeq's requirements are coarser than CWEs. One requirement covers LDAP, XPath and code injection, and the cryptography requirements overlap. The match is therefore by requirement family and not by exact CWE, and the results are not directly comparable with scores published for other tools.

2.2 Cost

Token usage came from the providers' own session logs. Cost is those tokens at the list prices on Anthropic's and OpenAI's pricing pages in October 2026. The cloud models were run through the vendors' command-line tools, so the figure is an API-equivalent cost and not an amount billed.

3. Results

3.1 Overall

Table 2Overall results per model, 2,740 test cases. Bold marks the best value in each column.
ModelFoundMissedFalse alarmsCorrectly left aloneFound %False alarm %Flags that were rightScore
Claude Sonnet 5.51,2891261881,13791%14%87%0.77 ± 0.02
GPT-6 Sol1,1722432021,12383%15%85%0.68 ± 0.03
GPT-6 Luna7037122161,10950%16%77%0.33 ± 0.03
Gemma 4 26B (local)1,20321286745885%65%58%0.20 ± 0.03
Qwen 3.8 27B (local)1,30610995337292%72%58%0.20 ± 0.03

The ± is the 95% margin that follows from the number of test cases alone. Each model was run once, so variation between runs is not captured, and small differences between models should not be over-interpreted.

The five models fall into three groups. Sonnet and Sol find most of the vulnerabilities and flag few safe cases. Luna flags equally few safe cases but misses half of the vulnerabilities. The local models miss few vulnerabilities and flag most of the safe cases, which places their score close to Luna's although their detection rate is close to Sonnet's.

3.2 By security principle

Quodeq files every finding under a security principle taken from the ISO 25010 quality standard. Three of them cover this benchmark.

  • Confidentiality. Data is only readable by those allowed to read it. Weak ciphers, weak randomness and insecure cookies are filed here.
  • Integrity. Data and behaviour cannot be changed by someone who should not change them. SQL injection, XSS, LDAP and XPath injection, weak hashes and trust-boundary mistakes are filed here.
  • Authenticity. The system only acts for who and what it should. Quodeq files command injection and path traversal here.

The benchmark's categories were grouped by the principle under which correct findings were filed in practice.

Table 3Results by security principle. Each cell is found / false alarms (score). Bold marks the best score in each row.
PrincipleReal / safe casesSonnet 5.5GPT-6 SolGPT-6 LunaGemma 4Qwen 3.8
Confidentiality384/422100%/12%0.8891%/21%0.7151%/8%0.4490%/44%0.4699%/69%0.31
Integrity772/64387%/14%0.7381%/12%0.6853%/22%0.3178%/66%0.1186%/68%0.18
Authenticity259/26089%/17%0.7276%/13%0.6337%/17%0.2099%/98%0.0199%/87%0.13

Confidentiality is the principle on which every model scores best. Its checks can be made from the line itself: a cipher name, a random number generator, a cookie flag. Integrity and authenticity depend on whether user-controlled data reaches the sensitive line, and on these the local models barely discriminate. On authenticity, Gemma flags 99% of the vulnerable cases and 98% of the safe ones.

3.3 By category

Table 4Results by category. Each cell is found / false alarms. Bold marks the best score in each row.
Category (CWE)Real / safeSonnet 5.5GPT-6 SolGPT-6 LunaGemma 4Qwen 3.8
SQL injection (89)272/23294%/16%81%/17%68%/34%99%/100%100%/94%
XSS (79)246/20992%/14%94%/16%56%/21%87%/68%100%/66%
Weak randomness (330)218/275100%/9%95%/28%55%/8%86%/61%100%/92%
Path traversal (22)133/13590%/16%76%/10%41%/21%99%/100%100%/81%
Weak cipher (327)130/116100%/22%95%/8%55%/8%98%/16%98%/26%
Weak hash (328)129/10774%/3%78%/2%37%/2%69%/8%69%/19%
Command injection (78)126/12588%/19%76%/18%34%/14%99%/96%98%/93%
Trust boundary (501)83/4369%/19%43%/9%2%/0%4%/7%24%/21%
Insecure cookie (614)36/31100%/0%53%/0%14%/6%86%/0%100%/26%
LDAP injection (90)27/3289%/31%93%/3%78%/28%52%/66%100%/100%
XPath injection (643)15/20100%/15%87%/5%87%/30%67%/95%100%/100%

Sonnet has the best score (found minus false alarms) in seven categories, Sol in three, and they tie on XSS.

Three observations follow. Sol has the lowest false-alarm rate in several categories, including LDAP injection (3% against 31% for Sonnet) and weak cipher. Trust boundary is the weakest category for every model, and quodeq's standards contain no dedicated requirement for it, which may contribute. Qwen's 92% false-alarm rate on weak randomness is a factual error and not a data-flow error: it reports SecureRandom.getInstance("SHA1PRNG") as weak because the name contains SHA-1.

3.4 Single-file and cross-file cases

About 30% of the test cases (814) pass the suspicious value through a helper class in a different file. Whether the case is vulnerable depends on what that helper does. Quodeq gives the model one file at a time and does not ask it to follow the call.

Table 5Injection-type categories, split by whether the evidence is in the same file. Each cell is found / false alarms. Bold marks the best score in each column.
ModelSingle-file cases (708 real, 496 safe)Cross-file cases (194 real, 300 safe)
Claude Sonnet 5.596%/9%69%/29%
GPT-6 Sol80%/9%81%/22%
GPT-6 Luna53%/19%42%/30%
Gemma 486%/82%81%/88%
Qwen 3.894%/79%88%/83%

Sonnet has the best score on single-file cases and loses that position on cross-file cases. Sol's detection rate is almost unchanged, while its false-alarm rate more than doubles. For the two large models, most of the remaining error is concentrated in the cross-file cases. This error follows from how quodeq presents code to the model, one file at a time, and is unlikely to be removed by a stronger model alone.

3.5 Comparison with other tools

The benchmark has been applied to many tools. Two sources report results on the same 2,740 cases.

Figure 1Every tool as one point: how much it found against how much safe code it flagged. Up and to the left is better. Table 6 has the same data, plus two older tools that score near zero.
0%0%25%25%50%50%75%75%100%100%no better than guessingbetterSafe cases flagged (false alarms)Real vulnerabilities foundCodeQL 2.27: found 100%, false alarms 40%, score 0.60CodeQL 2.27Semgrep OSS: found 87%, false alarms 39%, score 0.48Semgrep OSSFindSecBugs (2016): found 97%, false alarms 53%, score 0.44FindSecBugs (2016)SonarQube (2016): found 43%, false alarms 11%, score 0.32SonarQube (2016)ZAP (2016): found 17%, false alarms 0%, score 0.17ZAP (2016)Quodeq + Claude Sonnet 5.5: found 91%, false alarms 14%, score 0.77Claude Sonnet 5.5Quodeq + GPT-6 Sol: found 83%, false alarms 15%, score 0.68GPT-6 SolQuodeq + GPT-6 Luna: found 50%, false alarms 16%, score 0.33GPT-6 LunaQuodeq + Gemma 4: found 85%, false alarms 65%, score 0.20Gemma 4Quodeq + Qwen 3.8: found 92%, false alarms 72%, score 0.20Qwen 3.8
Quodeq 1.12 with each modelOther tools, published results
Table 6Quodeq and other tools on the same 2,740 cases. Shaded rows are quodeq.
ToolResults fromFoundFalse alarmsScore
Quodeq + Claude Sonnet 5.5this page, 202691%14%0.77
Quodeq + GPT-6 Solthis page, 202683%15%0.68
CodeQL 2.27.0 (java-security-extended)Cognium, Sept 2026100%40%0.60
Semgrep OSS 1.177.0 (p/java + p/security-audit)Cognium, Sept 202687%39%0.48
FindBugs with FindSecBugsbenchmark scorecard, 201697%53%0.44
Quodeq + GPT-6 Lunathis page, 202650%16%0.33
SonarQube Java plugin 3.14benchmark scorecard, 201643%11%0.32
Quodeq + Gemma 4 / Qwen 3.8 (local)this page, 202685%/92%65%/72%0.20
OWASP ZAP (dynamic scanner)benchmark scorecard, 201617%0%0.17
FindBugs 3.0.1benchmark scorecard, 201611%10%0.01
PMD 5.2.3benchmark scorecard, 20160%0%0.00

Three caveats apply to this comparison.

  • The scoring differs. The other rows count a case only on an exact CWE match. Quodeq's rows match by requirement family, which is slightly more lenient. The comparison is indicative, not exact.
  • The 2016 rows are old. They were computed from the per-case scorecards that ship in the benchmark repository. Those tools have changed since.
  • The 2026 rows come from a vendor. Cognium's comparison includes their own product, which they score at 0.74. CodeQL and Semgrep were not rerun for this report.

Subject to these caveats, the pattern is consistent. Rule-based scanners that detect nearly all vulnerabilities also flag 40% to 53% of the safe cases. The two large models detect slightly fewer and flag far fewer. The local models behave like the least selective rule-based scanners and score below them.

3.6 Speed and cost

Table 7Wall time, throughput and API-equivalent cost of each run.
ModelAgents running at onceTimeFiles per minuteCost
Claude Sonnet 5.5532 min88$52
GPT-6 Sol1021 min133$20
GPT-6 Luna1017.5 min160$1.24
Gemma 4 26B (local)22 h 29 min19local
Qwen 3.8 27B (local)28 h 51 min5local

No best value is marked for speed. The times are not directly comparable, because the runs used different numbers of agents at once: 10 for the GPT models, 5 for Sonnet, 2 for the local ones. Per agent, Sonnet was the fastest cloud model at 17.6 files a minute. For the local models a second agent adds little, because the server does not run them in parallel and memory is the limit. On the test machine, Qwen processes about 4 files a minute with one agent and 5 with two.

Sol costs less than half of what Sonnet does for a score 0.09 lower. Gemma reaches the same score as Qwen in a quarter of the time.

4. Worked cases

A safe case that a local model flagged. BenchmarkTest01878 builds a SQL query from a variable called bar. This is where bar comes from:

String bar;
int num = 106;
bar = (7 * 18) + num > 200 ? "This_should_always_happen" : param;

7 times 18 is 126, plus 106 is 232, which is always greater than 200. So bar is always the constant and the user's input never reaches the query. The benchmark labels the case safe. Sonnet reported nothing. Gemma reported a critical SQL injection, with this reason: "The SQL query is constructed using string concatenation with the 'bar' variable, which is derived from unvalidated cookie input." The model reported the concatenation without evaluating the condition.

A real case the best model missed. BenchmarkTest01923 writes a value into the HTML response. The value comes from here:

org.owasp.benchmark.helpers.ThingInterface thing =
        org.owasp.benchmark.helpers.ThingFactory.createThing();
String bar = thing.doSomething(param);

Whether bar still carries the user's input depends on which implementation ThingFactory returns, and that is decided in another file. In this case the input passes through and the page is open to cross-site scripting. Sonnet reported nothing for this file. Quodeq had supplied this file alone and did not ask the model to open the factory.

The same trap in a helper. Many cases read input through a helper class with two kinds of method:

public String getTheParameter(String p) {
    return request.getParameter(p);
}

// This method is a 'safe' source.
public String getTheValue(String p) {
    return "bar";
}

A test case that calls getTheParameter is vulnerable and one that calls getTheValue is not, and the two test files look almost the same. Only the helper distinguishes them. These cases make up the 30% of the benchmark on which every model scores lower.

5. Defects observed in the tool

The benchmark also exposed three defects in how quodeq processes its findings.

The grade. Table 8 shows the grades each run produced for an application that is vulnerable by design.

Table 8Violations reported and the grade quodeq produced, per principle and overall.
ModelViolationsConfidentialityIntegrityAuthenticityOverall
Claude Sonnet 5.51,7523.72.74.03.5
GPT-6 Sol2,4363.44.45.34.4
GPT-6 Luna1,3343.84.95.44.7
Gemma 4 26B2,6552.22.32.84.4
Qwen 3.8 27B4,0261.92.03.74.8

Two mechanisms produce this result. First, a principle is scored on how many different rules are broken, not how often or in how many files. Qwen's 1,191 integrity violations come down to 10 rules before any arithmetic happens. Second, the overall grade is an unweighted mean of every principle that has a score. In the Gemma and Qwen runs, accountability and non-repudiation each had between 7 and 14 findings and scored between 6.0 and 8.8. Those two principles raised Qwen's overall grade from about 2.5 to 4.8. A principle with 7 findings therefore carries the same weight as one with 2,329.

Severity. Severity is assigned by the model, and the models disagree.

Table 9Severity assigned to violations by each model.
ModelCriticalMajorMinor
Claude Sonnet 5.5786847118
GPT-6 Sol1391912,050
GPT-6 Luna12181,304
Gemma 4 26B1,68695415
Qwen 3.8 27B1,8172,043166

Both GPT models rated most findings minor, including most SQL injections. The other three rated the same class of finding critical. In the Sol run, 56 findings carried a severity that was not one of the three allowed values, and quodeq accepted them. Nothing in the tool defines what a critical finding is independently of the model, and a user who writes their own standard cannot say that a rule is never minor.

Coverage. Two runs skipped files without reporting it. Luna left 265 of the 2,740 test cases unanalysed and Sol left 35, while the progress display read complete. Those cases are counted as misses in the tables above, since a user running the tool once would obtain the same result.

6. Limitations

  • The benchmark is public and old. It dates from 2016, the files carry its name, and the models have very likely seen it. The scores should be read as an upper bound for real code.
  • The cases are synthetic. Each is one servlet, sometimes with one helper. Real vulnerabilities often span more files.
  • One run per model. No variance estimate across runs.
  • One language, one dimension. Java, security only.
  • The matching is by requirement family. Stricter than counting any finding in the file, looser than an exact CWE match.
  • Local results are specific to these two models and the hardware used. Larger open models may behave differently.
  • Local-model verification is untested here. A second pass that checks each finding against more context is expected to remove many of their false alarms. Related work supports this: Xiong and Zhang (2026) report that LLM agents cut a false-positive rate of over 92% on this same benchmark to as low as 6.3% in their best configuration, and warn that aggressive filtering can also remove real vulnerabilities. This was not tested with quodeq.

7. Reproducibility

  • Benchmark: OWASP-Benchmark/BenchmarkJava at commit 8b67a88d, with its expectedresults-1.2.csv.
  • Tool: quodeq 1.12.0, security dimension, default standards.
  • Scorer: score_owasp.py. It reads a run's security report and the benchmark's expected results and prints the tables above. The mapping from benchmark category to quodeq requirement is a table at the top of the script.
  • Data: one security report per run and a combined comparison.json with every count on this page.
  • Not yet done: a repeat of any run, so there is no run-to-run variance.

References

Changes to this page

  • October 2026: first version.