Most security scans end with a long list and no clear answer to "so what do I fix first?"

This teardown is from a real run — the sample scan we publish so builders can see exactly what a check looks like before they buy one. No client code was involved. The targets were two public Java codebases, scanned as-is:

  • MyBatis JPetStore-6 — a real online-store web app: 46 Java files, 7,628 lines
  • Spark (perwendel/spark) — a Java web framework: 184 Java files, 21,272 lines

Total: 230 files, 28,900 lines, about 46 seconds of instrument time. The instrument was Semgrep 1.140.0 with a frozen set of OWASP-category rules for Java — SQL injection, XSS, command injection, path traversal, weak crypto, weak randomness, insecure cookies, and others. It reads Java source only; anything living in XML mappers or config is outside its sight, and we say so in the report.

Findings issued: 16. Every one was read in context and dispositioned.

What actually broke

One real fix, low severity — and it's the kind of bug almost nobody writes on purpose:

Spark, Response.java:314 — the cookie that deletes a cookie was built without the Secure flag.

Spark's normal cookie path does this right. Its deletion path didn't carry the same flag. A deletion cookie should carry the same protections as the cookie it replaces. Otherwise you have one code path that respects your cookie policy and a second, quieter path that doesn't.

The fix is one line. The lesson is bigger:

Check every path that sets a cookie — create, update, and delete. Frameworks and apps usually secure the happy path. The cleanup path is where the flag gets dropped.

If you ship anything with session cookies, grep for every cookie construction in your codebase today — not just the login handler.

What held — and why we report it anyway

JPetStore-6: 1 finding, not a defect. A ThreadLocalRandom call in the Maven wrapper downloader names a temporary file during a build-tool download. It protects nothing, so weak randomness there is not a security problem. Counted, explained, no fix recommended.

Spark, Response.java:292: not a defect. This is the correct normal cookie method. It calls setSecure(secured) from its own parameter. A pattern scanner can't see that the flag is parameterized, so it fired anyway. We note it so a reader can see why a hit was dismissed, not just that it was.

The noise, counted in the open

  • 4 × SQL injection (CWE-89) in Spark's route dispatcher — false positives. The lines are route-dispatch calls like Routes.execute(...). The file contains no SQL at all. The rule's sink pattern binds on a generic execute(...) shape. That's a known collision class.
  • 8 × insecure cookie in test code. Mock verifications asserting that a cookie method was called. They set no cookies. Counted here, excluded from the fix list.
  • 1 × weak randomness in example code. new Random() minting an ID in a bundled example app. Fine in a demo. It would be a real problem if that pattern were copied into production — predictable IDs are guessable IDs.

Tally: 1 real fix (low), 1 informational, 14 not-a-defect — each with the reason printed beside it.

On the labeled benchmark corpus where this same rule set was calibrated, its measured precision was 0.7169. In plain terms: even a decent scanner will hand you hits that don't survive reading. The reading is the service.

What a builder can use from this

  1. Audit cookie deletion as well as cookie creation. Same flags, every path.
  2. Don't let example-code randomness reach production. new Random() for IDs, tokens, or filenames that matter is a defect; for a throwaway temp name, it isn't. Context decides.
  3. Demand dispositions, not just counts. "16 findings" means nothing until each one is marked real, informational, or not-a-defect with a reason. If a report won't show its dismissals, you can't trust its fixes.

If you want this kind of check on your own app before launch, the intake is at verify.novitasnexus.com — verify@novitasnexus.com if you prefer email.