OWASP Juice Shop

github.com/juice-shop/juice-shop — modern Angular + Node training app with ~80 deliberate bugs.

Results

toolfindingswall-clock
rastray807.3 s
semgrep23140.5 s
gitleaks5016.6 s
eslint-security1 8234.6 s
banditN/A
gosecN/A

What rastray fires on

The top families on Juice Shop:

codecountwhat it catches
RSTR-PERF-10130await inside a loop (serialised async calls)
RSTR-INJ-00112SQL injection via template literal
RSTR-ORM-00412Raw SQL template literal in ORM call
RSTR-CRY-00511Math.random() for security purposes
RSTR-INJ-0034eval / new Function dynamic execution
RSTR-REDOS-0013Catastrophic backtracking heuristic
RSTR-IAC-0012FROM image:latest
RSTR-CRY-0012MD5 used for hashing

Where rastray catches more than Semgrep

  • The 30 RSTR-PERF-101 findings are pure throughput bugs the p/owasp-top-ten Semgrep registry does not aim for (Semgrep has perf packs, but they aren't in the OWASP set).
  • RSTR-CRY-005 (Math.random() for tokens) fires 11 times; Semgrep's OWASP pack does not include this generic check.
  • RSTR-ORM-004 (raw SQL template literals) fires 12 times for Sequelize / Knex / Prisma .raw(\SELECT ... ${x}`)` patterns.

Where Semgrep catches things rastray misses

Semgrep's deeper rules occasionally span call boundaries — for example, identifying a sink that takes a req-derived value after it has been assigned through a const (rastray deliberately does not flow analyze; see Introduction).

On the eslint-security count (1 823)

security/detect-object-injection produces ~95% of that total. Most security teams disable it because it flags every obj[variable] access regardless of whether variable is user-controlled. Excluding it brings eslint-security's actionable count to ~80 — comparable to what rastray reports.

Reproduce

powershell -File scripts/benchmarks/run.ps1 -Target juice-shop