Three scanners, same Juice Shop source — but three different classes of tool, so this is about which lens you need, not a single winner.
Audn live red-team (SAST + DAST fusion) — "what actually exploits on the running app?" 103 findings, 18 reproduced live. Codex commit-diff code review — "did this change introduce something bad?" 20 findings, all diff-scoped + patched. Aikido commercial SAST + SCA + secrets + CI platform — "give me a fast, broad baseline." 36 issues in ~52 seconds.
Overlap is still modest. All three agree on only 3 issues (JWT signature not verified, unpinned GitHub Actions, CI fetch-without-integrity) — treat those as certainly real. The big story: Aikido closes the one blind spot Audn and Codex shared — it's the only tool that runs SCA, surfacing 3 real dependency CVEs (jsonwebtoken, express-jwt, sanitize-html) — and it adds deep secrets coverage (incl. test fixtures). But it brings no live proof and no diff awareness.
Bottom line — layers, not substitutes: Aikido is the fast continuous baseline (SCA + secrets + SAST), Codex is the PR gate for regressions, Audn is the periodic live pentest and the only one proving exploitability + business logic. Remaining blind spots shrink to: live infra/edge posture, end-to-end business-logic exploitation, client-side runtime depth, and complete SCA (Aikido itself flags a missing lockfile).
Same target (ozgurozkan123/juice-shop). The severity mixes and the "scanner DNA" chips below show how differently each one works — Audn ranges across a live-confirmed critical tier, Codex reports a tight introduced-issue set, Aikido produces a broad static baseline heavy on secrets.
160f306. Validation rubric + evidence + a generated patch per finding.Audn separates "facts about the running system" from "patterns in the source": just 16 confirmed (static+live) and 2 observed live, versus 63 static-only leads. Codex and Aikido are both fully static — every one of their findings sits, in Audn's terms, at the unverified tier.
Pick by the job. Continuous baseline → Aikido. Gate a pull request → Codex. Prove exploitability / pentest → Audn. Most teams want all three at different points in the lifecycle.
| Dimension | Audn | Codex | Aikido |
|---|---|---|---|
| Core method | SAST + live red-team (DAST) fusion | Static review of a commit diff | SAST + SCA + secrets + CI (ASPM) |
| Scope | Whole app, deployed | What the changeset introduced | Whole repo, static |
| Findings | 103 | 20 | 36 |
| Live confirmation | 18 reproduced + confidence tiers | None (static) | None (static) |
| Dependency CVEs (SCA) | No | No | Yes — 3 (partial; needs lockfile) |
| Secrets scanning | Partial (source) | No | Yes — 17 (source + tests) |
| Remediation | Prose + attack paths | Generated patch | Fix-time estimate + guidance |
| Intentional vs unintended | No | Yes | No |
| Speed | Heavy — 2h 28m | Light — diff-scoped | ~52 seconds |
| Sweet spot | Pentest / exploitability | PR gate / regressions | Continuous baseline |
Because the taxonomies differ, overlap is mapped at the issue-area level. The clearest read: each tool owns a distinct lane, they agree on very little, and Aikido is what plugs the dependency-CVE hole.
18 findings reproduced against the running target — the only live confirmation across all three tools. Plus the whole IDOR / broken-access-control / business-logic layer (basket, order, wallet overspend, coupon abuse) that pattern-based SAST can't reason about, and 32 attack-path chains.
Diff-aware review that catches unintended regressions no whole-repo scan looks for: 2FA temp-JWT accepted as bearer, complaint-scan DoS, Web3 listener race, Google-Fonts privacy leak, Windows i18n bug — and ships a patch per finding.
The only tool that runs SCA: 3 dependency CVEs (jsonwebtoken, express-jwt, sanitize-html) — closing the gap the other two share. Plus aggressive secrets detection across 40+ files incl. tests, CI/IaC hardening, and a full scan in ~52 seconds.
When a live red-team, a diff reviewer, and a commercial SAST/SCA platform independently land on the same thing, it's as close to "definitely real" as this set gets.
Audn (algorithm-confusion + hard-coded key in lib/insecurity.ts) · Codex (forged-JWT registration) · Aikido ("JWT signature is not verified" in insecurity.ts, authenticatedUsers.ts).
Audn #54 (mutable actions get write) · Codex #1/#2 (unpinned + patch) · Aikido ("3rd party GitHub Actions should be pinned" in image_actions.yml, ci.yml).
Audn #32 (remote installer, no integrity) · Codex #6/#12 (npm/lockfile/scripts) · Aikido ("binary pulled from remote without integrity check" in ci.yml).
23 of Aikido's 36 are unique to it. The headline: SCA dependency CVEs (nobody else ran SCA) and a broad secrets sweep including test fixtures. Hover a chip for its location.
Audn traces the hard-coded key + algorithm-confusion in lib/insecurity.ts; Codex flags a newly-introduced global registration of forged JWTs; Aikido's SAST flags "JWT signature is not verified" in the same files. Rare triple agreement — treat as real.
image_actions.yml runs mutable third-party actions with the repo token. Audn (Medium lead), Codex (High + pinning patch), and Aikido ("3rd party GitHub Actions should be pinned") all flag it.
Shell-command injection from the release tag in the news-update workflows. Aikido did not surface this one.
Audn: lockless installs + mutable Docker base. Codex: deleted lockfiles + --ignore-scripts removed. Aikido overlaps on "binary pulled without integrity check" in ci.yml.
Chatbot getOrderById trusts an unverified/unsigned JWT + lossy email match. Aikido's pattern SAST did not reason about this authorization logic.
Same files, different bug each (missing ownership vs listener race). Aikido did not flag these.
Adding Aikido does not cover these: they're introduced/diff-scoped logic, privacy, DoS and cross-platform bugs that only a changeset-aware reviewer surfaces.
A commit stopped inserting no-data JWTs into authenticatedUsers to avoid a crash, but those tokens are still not rejected — they flow through as valid bearer auth. A subtle regression an app-surface red-team wouldn't reach.
routes/2fa flow / insecurity.tsA per-request challenge check runs an unbounded ComplaintModel.findAll() plus an O(n) string-similarity loop over every complaint — a denial-of-service amplifier introduced by the changeset.
routes/verify.ts, models/complaint.tsA newly-added developer/AI-agent skill fetches arbitrary URLs with shell curl and feeds the response back to the agent — untrusted retrieval that can reach localhost/link-local/internal ranges. A supply-chain / agent-tooling surface Audn never scanned.
.junie/skills/add-reference/SKILL.mdThe new default "neon-fire" theme hard-codes remote Google Fonts (fonts.googleapis.com/gstatic.com), leaking every visitor's IP/UA/referer to a third party. A privacy/info-leak class Audn's exploit-focused lens ignores.
config/ctf.yml, index.htmlNew code passes a native Windows absolute glob to Unix-only basename parsing — breaks i18n file restore on Windows. A cross-platform robustness bug, invisible to a Linux live target.
lib/startup/restoreOverwrittenFilesWithOriginals.tsA display-name capitalization mismatch breaks an exact-match lookup, making the Exposed-Credentials guided tutorial unavailable. Non-security functional regression.
data/static/challenges.ymlTest-coverage regression: the spec no longer asserts that exactly 4096 chars is valid. Pure code-health finding.
complaint.component.spec.tsOptional metadata-file absence is no longer handled gracefully and throws a 500 instead of degrading. Robustness regression.
routes/vulnCodeSnippet.tsAikido's SAST overlaps Audn on injection/XSS/secrets, but the live-confirmed criticals and the whole IDOR / broken-access-control / business-logic set stay Audn-only — pattern scanners don't reason about authorization. Green = reproduced live.
Adding Aikido closes one shared blind spot (dependency CVEs) and dents another (secrets). What still isn't covered by any of the three:
Aikido surfaced jsonwebtoken, express-jwt, and sanitize-html. Caveat: Aikido itself flagged a missing lockfile, so its dependency view is still partial — add a lockfile for full transitive SCA.
Audn surfaces IDOR component leads and Aikido none; the multi-step chains (GDPR erasure, forged-coupon, premium unlocks) are still not demonstrated end-to-end by anyone.
All three are code-centric; Angular DOM sinks beyond those flagged, live CSP behaviour, and client routing/auth remain under-explored.
Codex & Aikido are static; Audn ran live but its transport/header/container items were either never reached (#61) or probed with no verdict (#21) — so the real TLS, the actual HTTP security-header set the Render edge returns, and container hardening remain unresolved, not measured. One curl -I closes most of it.
All 20 Codex + all 36 Aikido + 83 of Audn's findings are unverified against a live target. Whether each fires in your deployment is still open.
Even with Aikido, no full transitive dependency graph, license posture, or signed SBOM — the lockfile gap means known-vulnerable transitive packages can still hide.
Where each tool put its attention. ●●● strong (8+), ●● moderate (3–7), ● light (1–2), — none. Shaded rows are classes only Aikido reached (its SCA / deserialization coverage). This is the clearest single view of the three-way spread.
| Vulnerability class | Audn | Codex | Aikido |
|---|---|---|---|
| SQL Injection | ●2 | —— | ●1 |
| NoSQL Injection | ●●3 | —— | ●1 |
| XSS | ●●6 | —— | ●●3 |
| XXE | ●1 | —— | —— |
| SSRF | ●1 | ●2 | ●1 |
| Path Traversal | ●●6 | —— | ●2 |
| Code Injection / RCE | ●2 | ●1 | ●2 |
| Insecure Deserialization | —— | —— | ●1 |
| Broken Access Control / IDOR | ●●●16 | ●2 | —— |
| JWT / Token Auth | ●●3 | ●2 | ●1 |
| Auth Rate-Limiting | ●2 | —— | —— |
| Weak Password Recovery | ●1 | —— | —— |
| Weak Credentials/Hashing | ●2 | —— | —— |
| Hardcoded Secrets/Creds | ●●●11 | —— | ●●●17 |
| Sensitive Data Exposure | ●●●12 | ●2 | —— |
| Open Redirect | ●1 | —— | ●1 |
| CSRF | ●2 | —— | —— |
| Broken Anti-Automation | ●2 | —— | —— |
| Business Logic | ●2 | —— | —— |
| Race Condition | ●●3 | ●2 | —— |
| Improper Input Validation | ●●4 | ●2 | —— |
| Cleartext Transmission | ●2 | —— | —— |
| DoS / Resource Exhaustion | ●●3 | ●1 | —— |
| Supply Chain / CI-CD | ●●●8 | ●●6 | ●●3 |
| Dependency CVE (SCA) | —— | —— | ●●3 |
| Insufficient Verification | ●●3 | —— | —— |
Counts are findings tagged to each class (Codex/Aikido aggregated from their finding lists incl. grouped items). Shaded = Audn 0, Codex 0, Aikido > 0.
Every finding from all three reports, filterable — the working index behind the analysis.
| # | Sev | Issue | Engine | Location | Overlap |
|---|---|---|---|---|---|
| #1 | Critical | jsonwebtoken — attacker can abuse missing input validation | Dependency | dependency (jsonwebtoken) | Aikido only |
| #2 | Critical | Remote Code Execution via eval()-type functions | Code (SAST) | userProfile.ts | Audn+Aikido |
| #3 | Critical | Unsafe YAML load can lead to RCE | Code (SAST) | vulnCodeSnippet.ts, vulnCodeFixes.ts | Aikido only |
| #4 | High | NoSQL injection attack possible | Code (SAST) | deluxe.ts, wallet.ts +19 | Audn+Aikido |
| #5 | High | JWT signature is not verified | Code (SAST) | insecurity.ts, authenticatedUsers.ts | All 3 |
| #6 | High | Path traversal via Express sendFile() | Code (SAST) | fileServer.ts | Audn+Aikido |
| #7 | High | SQL injection via string-based query concatenation | Code (SAST) | dbSchemaChallenge_1.ts, unionSqlInjectionChallenge_1.ts +3 | Audn+Aikido |
| #8 | High | Open redirect usable in social engineering | Code (SAST) | redirect.ts | Audn+Aikido |
| #9 | High | Server-Side Template Injection via express.render() | Code (SAST) | dataErasure.ts | Audn+Aikido |
| #10 | High | express-jwt — attacker can abuse improper authorization | Dependency | dependency (express-jwt) | Aikido only |
| #11 | High | 6 exposed secrets | Secret | users.yml | Audn+Aikido |
| #12 | High | 4 exposed secrets | Secret | login.ts, login.js | Audn+Aikido |
| #13 | High | document.write() methods can lead to XSS | Code (SAST) | index.ts | Aikido only |
| #14 | High | XSS via window.location.href | Code (SAST) | order-history.component.ts | Aikido only |
| #15 | High | File inclusion via reading file | Code (SAST) | validatePreconditions.ts, rsnUtil.ts +9 | Aikido only |
| #16 | High | 3rd party GitHub Actions should be pinned | CI / IaC | image_actions.yml, ci.yml | All 3 |
| #17 | Medium | sanitize-html — XSS attack possible | Dependency | dependency (sanitize-html) | Aikido only |
| #18 | Medium | 1 exposed secret | Secret | .travis.yml | Aikido only |
| #19 | Medium | 1 exposed secret | Secret | server.js | Aikido only |
| #20 | Medium | 1 exposed secret | Secret | users.json | Aikido only |
| #21 | Medium | 33 exposed secrets | Secret | datacreator.js, chat.test.ts +21 | Aikido only |
| #22 | Medium | HTTP request might enable SSRF | Code (SAST) | profileImageUrlUpload.ts | Audn+Aikido |
| #23 | Medium | Binary/code pulled from remote without integrity check | CI / IaC | ci.yml | All 3 |
| #24 | Medium | XSS via bypassSecurityTrustUrl | Code (SAST) | track-result.component.ts, search-result.component.ts +2 | Audn+Aikido |
| #25 | Low | actions/checkout persists Git credentials | CI / IaC | ci.yml, codeql-analysis.yml +11 | Aikido only |
| #26 | Low | 1 exposed secret | Secret | oauth.component.spec.ts | Aikido only |
| #27 | Low | Exposed JWT | Secret | last-login-ip.component.spec.ts | Aikido only |
| #28 | Low | Exposed JWT | Secret | app.guard.spec.ts | Aikido only |
| #29 | Low | Exposed JWT | Secret | verify.unit.test.ts, verifySpec.js +4 | Aikido only |
| #30 | Low | 6 exposed secrets | Secret | checkKeys.test.ts, web3.test.ts +1 | Aikido only |
| #31 | Low | 4 exposed secrets | Secret | 2fa.test.ts | Aikido only |
| #32 | Low | 1 exposed secret | Secret | 2faSetupSpec.js | Aikido only |
| #33 | Low | 1 exposed secret | Secret | totpSetup.spec.ts | Aikido only |
| #34 | Low | 5 exposed secrets | Secret | currentUserSpec.js, currentUserSpec.ts +1 | Aikido only |
| #35 | Low | 2 exposed secrets | Secret | 2faSpec.js, 2fa.test.ts | Aikido only |
| #36 | Low | 6 exposed secrets | Secret | user.test.ts, userApiSpec.js | Aikido only |
| # | Sev | Finding | CWE | Location | Confidence | Overlap |
|---|---|---|---|---|---|---|
| #1 | Critical | CWE-532: Insertion of Sensitive Information into Log File LIVE | CWE-532 | server.ts:280 | Confirmed | Audn only |
| #2 | Critical | CWE-307 LIVE | CWE-307 | server.ts:340 | Confirmed | Audn only |
| #3 | Critical | CWE-521 LIVE | CWE-521 | frontend/src/app/oauth/oauth.component.ts:27 | Confirmed | Audn only |
| #4 | Critical | CWE-321 LIVE | CWE-321 | data/static/users.yml:259 | Confirmed | Audn only |
| #5 | Critical | CWE-798: Use of Hard-coded Credentials LIVE | CWE-798 | data/static/users.yml:167 | Confirmed | Audn only |
| #6 | Critical | CWE-798: Use of Hard-coded Credentials LIVE | CWE-798 | config/7ms.yml:143 | Confirmed | Audn only |
| #7 | Critical | CWE-640: Weak Password Recovery Mechanism for Forgotten Password LIVE | CWE-640 | routes/resetPassword.ts:18 | Confirmed | Audn only |
| #8 | Critical | CWE-798: Use of Hard-coded Credentials LIVE | CWE-798 | routes/login.ts:59 | Confirmed | Audn only |
| #9 | High | CWE-89: Improper Neutralization of Special Elements used in an SQL Command (SQL Injection) LIVE | CWE-89 | routes/search.ts:21 | Confirmed | Audn only |
| #10 | High | CWE-943 LIVE | CWE-943 | routes/trackOrder.ts:15 | Confirmed | Audn only |
| #11 | High | CWE-943 LIVE | CWE-943 | routes/showProductReviews.ts:31 | Confirmed | Audn only |
| #12 | High | CWE-916 LIVE | CWE-916 | models/user.ts:73 | Confirmed | Audn only |
| #13 | High | CWE-79: Improper Neutralization of Input During Web Page Generation (Cross-site Scripting) LIVE | CWE-79 | models/product.ts:42 | Confirmed | Audn only |
| #14 | High | CWE-200: Exposure of Sensitive Information to an Unauthorized Actor LIVE | CWE-200 | routes/memory.ts:22 | Confirmed | Audn only |
| #15 | High | CWE-307 LIVE | CWE-307 | routes/2fa.ts:16 | Confirmed | Audn only |
| #16 | High | CWE-200: Exposure of Sensitive Information to an Unauthorized Actor LIVE | CWE-200 | lib/challengeUtils.ts:52 | Confirmed | Audn only |
| #17 | Critical | Spoofable X-Forwarded-For header bypasses password-reset rate limit (account-takeover enabler) LIVE | | Observed | Audn only | |
| #18 | Critical | Unauthenticated public access logs contain change-password URLs with cleartext current/new passwords LIVE | | Observed | Audn only | |
| #19 | Critical | ZIP upload permits arbitrary application file overwrite | CWE-22 | routes/fileUpload.ts:27 | Probed | Audn only |
| #20 | Critical | Search query causes DOM-based XSS | CWE-79 | frontend/src/app/search-result/search-result.component.ts:135 | Probed | Audn only |
| #21 | Critical | Mutable base images enter production builds | CWE-829 | Dockerfile:1 | Probed | Audn+Codex |
| #22 | Critical | Hardcoded JWT private key enables token forgery | CWE-321 | lib/insecurity.ts:20 | Probed | Audn+Codex |
| #23 | Critical | Release tag enables cross-repository command injection | CWE-78 | .github/workflows/update-news-www.yml:18 | Probed | Audn+Codex |
| #24 | Critical | Tracking ID enables reflected cross-site scripting | CWE-79 | frontend/src/app/track-result/track-result.component.ts:45 | Probed | Audn only |
| #25 | Critical | Build argument injects arbitrary npm packages | CWE-88 | Dockerfile:18 | Probed | Audn+Codex |
| #26 | High | Anonymous XML upload discloses local files | CWE-611 | server.ts:307 | Probed | Audn only |
| #27 | High | Profile image URL enables SSRF | CWE-918 | server.ts:307 | Probed | Audn only |
| #28 | High | Unbounded upload can exhaust server disk | CWE-400 | server.ts:698 | Probed | Audn only |
| #29 | High | Backslashes bypass quarantine path validation | CWE-22 | routes/quarantineServer.ts:10 | Probed | Audn only |
| #30 | High | Order data enables remote code execution | CWE-94 | routes/b2bOrder.ts:19 | Probed | Audn only |
| #31 | High | Stored username enables server-side code execution | CWE-95 | routes/userProfile.ts:54 | Probed | Audn only |
| #32 | High | Remote installer executes without integrity verification | CWE-494 | .github/workflows/ci.yml:357 | Probed | Audn+Codex |
| #33 | High | Remote SVG upload enables stored XSS | CWE-79 | server.ts:310 | Probed | Audn only |
| #34 | High | Lockless installs execute mutable dependency code | CWE-829 | .npmrc:1 | Probed | Audn+Codex |
| #35 | High | JWT verification trusts attacker-selected algorithm | CWE-347 | lib/insecurity.ts:52 | Probed | Audn+Codex |
| #36 | High | Release tag injects commands into legacy website update | CWE-78 | .github/workflows/update-news-www-legacy.yml:18 | Probed | Audn+Codex |
| #37 | Critical | Login query permits authentication bypass | CWE-89 | routes/login.ts:32 | Static lead | Audn only |
| #38 | High | Null suffix bypass enables Windows file traversal | CWE-22 | routes/fileServer.ts:16 | Static lead | Audn only |
| #39 | High | Password change skips current-password verification | CWE-620 | routes/changePassword.ts:39 | Static lead | Audn only |
| #40 | High | Endpoint exposes complete runtime configuration | CWE-200 | routes/appConfiguration.ts:10 | Static lead | Audn only |
| #41 | High | Repository code executes with CI secrets | CWE-200 | .github/workflows/ci.yml:229 | Static lead | Audn only |
| #42 | High | Security answer bypass permits unverified erasure requests | CWE-620 | routes/dataErasure.ts:74 | Static lead | Audn only |
| #43 | Medium | Production error handler exposes stack traces | CWE-209 | server.ts:314 | Static lead | Audn only |
| #44 | Medium | Metrics endpoint is exposed without authentication | CWE-200 | server.ts:725 | Static lead | Audn only |
| #45 | Medium | Anonymous FTP directory listing exposes hidden files | CWE-548 | server.ts:267 | Static lead | Audn only |
| #46 | Medium | Anonymous users can modify products | CWE-862 | server.ts:368 | Static lead | Audn only |
| #47 | Medium | YAML aliases block the Node.js event loop | CWE-400 | routes/fileUpload.ts:101 | Static lead | Audn only |
| #48 | Medium | Substring allowlist permits arbitrary external redirects | CWE-601 | routes/redirect.ts:13 | Static lead | Audn only |
| #49 | Medium | Unbounded image download exhausts server storage | CWE-400 | routes/profileImageUrlUpload.ts:24 | Static lead | Audn only |
| #50 | Medium | Users can edit reviews owned by others | CWE-639 | routes/updateProductReviews.ts:16 | Static lead | Audn only |
| #51 | Medium | NoSQL selector updates every product review | CWE-943 | routes/updateProductReviews.ts:17 | Static lead | Audn only |
| #52 | Medium | Ordinary users can enumerate all user profiles | CWE-862 | routes/authenticatedUsers.ts:10 | Static lead | Audn only |
| #53 | Medium | Arbitrary field selection exposes credential material | CWE-200 | routes/currentUser.ts:20 | Static lead | Audn only |
| #54 | Medium | Mutable actions receive repository write capability | CWE-829 | .github/workflows/image_actions.yml:29 | Static lead | Audn+Codex |
| #55 | Medium | Unversioned Playwright install can overwrite master | CWE-829 | .github/workflows/frontend-bundle-analysis.yml:39 | Static lead | Audn only |
| #56 | Medium | Unvalidated seed data can create administrators | CWE-20 | data/staticData.ts:55 | Static lead | Audn only |
| #57 | Medium | Application name injects executable HTML | CWE-79 | lib/startup/customizeApplication.ts:83 | Static lead | Audn only |
| #58 | Medium | Anonymous callers can forge product reviews | CWE-862 | routes/createProductReviews.ts:14 | Static lead | Audn only |
| #59 | Medium | Unverified JWT controls chatbot order identity | CWE-347 | routes/chat.ts:42 | Static lead | Audn+Codex |
| #60 | Medium | Coupon policy enforced only by the LLM | CWE-862 | routes/chat.ts:176 | Static lead | Audn+Codex |
| #61 | Medium | Default deployment exposes credentials over plain HTTP | CWE-319 | server.ts:130 | Static lead | Audn only |
| #62 | Medium | Bender account password exposed client-side | CWE-798 | frontend/src/hacking-instructor/challenges/loginBender.ts:75 | Static lead | Audn only |
| #63 | Medium | Jim account password exposed client-side | CWE-798 | frontend/src/hacking-instructor/challenges/loginJim.ts:64 | Static lead | Audn only |
| #64 | Medium | CAPTCHA response discloses its answer | CWE-200 | routes/captcha.ts:22 | Static lead | Audn only |
| #65 | Medium | Solved CAPTCHAs remain valid for unlimited reuse | CWE-294 | routes/captcha.ts:35 | Static lead | Audn only |
| #66 | Medium | Failed requests satisfy global anti-cheat checks | CWE-345 | lib/antiCheat.ts:51 | Static lead | Audn only |
| #67 | Medium | Committed CTF key permits flag forgery | CWE-321 | ctf.key:1 | Static lead | Audn only |
| #68 | Medium | Product link uses cleartext HTTP | CWE-319 | config/addo.yml:57 | Static lead | Audn only |
| #69 | Medium | Client clock controls campaign coupon validity | CWE-602 | frontend/src/app/payment/payment.component.ts:152 | Static lead | Audn only |
| #70 | Medium | Feedback accepts ratings outside the valid range | CWE-20 | models/feedback.ts:57 | Static lead | Audn only |
| #71 | Medium | Basket IDOR exposes other users' carts | CWE-639 | routes/basket.ts:18 | Static lead | Audn only |
| #72 | Medium | Duplicate BasketId bypasses basket ownership check | CWE-639 | routes/basketItems.ts:21 | Static lead | Audn only |
| #73 | Medium | Coupon update lacks basket ownership check | CWE-639 | routes/coupon.ts:11 | Static lead | Audn only |
| #74 | Medium | User-controlled layout enables local file disclosure | CWE-22 | routes/dataErasure.ts:103 | Static lead | Audn only |
| #75 | Medium | CAPTCHA answer disclosed in API response | CWE-200 | routes/imageCaptcha.ts:24 | Static lead | Audn only |
| #76 | Medium | Missing CAPTCHA record bypasses verification | CWE-693 | routes/imageCaptcha.ts:42 | Static lead | Audn only |
| #77 | Medium | Wallet debit permits concurrent overspending | CWE-362 | routes/order.ts:148 | Static lead | Audn only |
| #78 | Medium | Checkout lacks basket ownership validation | CWE-639 | routes/order.ts:34 | Static lead | Audn only |
| #79 | Medium | Array ID exposes multiple recycle records | CWE-639 | routes/recycles.ts:11 | Static lead | Audn only |
| #80 | Medium | Premium content served without authorization | CWE-862 | routes/premiumReward.ts:12 | Static lead | Audn only |
| #81 | Medium | Response discrepancy enables account enumeration | CWE-204 | routes/securityQuestion.ts:12 | Static lead | Audn only |
| #82 | Medium | Arbitrary wallet balance top-ups | CWE-20 | routes/wallet.ts:23 | Static lead | Audn only |
| #83 | Medium | Client header spoofs stored login IP | CWE-345 | routes/saveLoginIp.ts:18 | Static lead | Audn only |
| #84 | Medium | Masked email collisions expose other users' orders | CWE-639 | routes/orderHistory.ts:13 | Static lead | Audn only |
| #85 | Medium | Authentication token contains the TOTP seed | CWE-200 | routes/2fa.ts:26 | Static lead | Audn only |
| #86 | Medium | Unverified issue references defeat spam enforcement | CWE-840 | .github/workflows/pr-compliance.yml:275 | Static lead | Audn only |
| #87 | Medium | Any commenter can rebase pull requests | CWE-862 | .github/workflows/rebase.yml:3 | Static lead | Audn only |
| #88 | Medium | Lossy email masking breaks order ownership | CWE-187 | routes/chat.ts:158 | Static lead | Audn+Codex |
| #89 | Medium | New commits bypass completed compliance decisions | CWE-367 | .github/workflows/pr-compliance.yml:3 | Static lead | Audn only |
| #90 | Medium | JWT algorithm confusion accepts forged tokens | CWE-347 | routes/verify.ts:111 | Static lead | Audn+Codex |
| #91 | Medium | Anonymous users can access arbitrary orders | CWE-639 | routes/trackOrder.ts:12 | Static lead | Audn only |
| #92 | Medium | OAuth flow omits state validation | CWE-352 | frontend/src/app/login/login.component.ts:147 | Static lead | Audn only |
| #93 | Medium | Unanchored coupon validation accepts unbounded discounts | CWE-20 | lib/insecurity.ts:102 | Static lead | Audn only |
| #94 | Medium | Generated users share a hard-coded password | CWE-798 | data/datacreator.ts:310 | Static lead | Audn only |
| #95 | Low | Concurrent requests inflate review likes | CWE-362 | routes/likeProductReviews.ts:25 | Static lead | Audn only |
| #96 | Low | Public wallet address accepted as ownership proof | CWE-345 | routes/nftMint.ts:41 | Static lead | Audn+Codex |
| #97 | Low | Profile update lacks CSRF enforcement | CWE-352 | routes/updateUserProfile.ts:16 | Static lead | Audn only |
| #98 | Low | Wallet ownership is never verified | CWE-862 | routes/web3Wallet.ts:14 | Static lead | Audn+Codex |
| #99 | Low | TOTP secrets stored unencrypted | CWE-312 | routes/2fa.ts:105 | Static lead | Audn only |
| #100 | Info | Active user credentials embedded in client code | CWE-798 | frontend/src/hacking-instructor/challenges/exposedCredentials.ts:51 | Likely FP | Audn only |
| #101 | Info | Feedback XSS compromises administrator sessions | CWE-79 | frontend/src/app/administration/administration.component.ts:86 | Likely FP | Audn only |
| #102 | Info | Backslashes bypass log path validation | CWE-22 | routes/logfileServer.ts:9 | Likely FP | Audn only |
| #103 | Info | Backslashes bypass key-file path restriction | CWE-22 | routes/keyServer.ts:10 | Likely FP | Audn only |
| # | Sev | Finding | Key files | Overlap |
|---|---|---|---|---|
| #1 | High | Unpinned CI image actions receive repository token | .github/workflows/image_actions.yml, github/workflows/image_actions.yml | Audn+Codex |
| #2 | High | Unpinned image workflow actions expose CI token | .github/workflows/image_actions.yml, github/workflows/image_actions.yml | Audn+Codex |
| #3 | High | 2FA temporary JWTs accepted as bearer auth | server.ts, lib/insecurity.ts | Audn+Codex |
| #4 | High | Global forged-JWT registration enables account takeover | lib/insecurity.ts, server.ts | Audn+Codex |
| #5 | High | Release tag command injection in legacy website workflow | .github/workflows/update-news-www-legacy.yml, tab_news.md | Audn+Codex |
| #6 | High | Unpinned npm installs in release and Docker builds | package-lock.js, bin/semver.js | Audn+Codex |
| #7 | High | Chat order tool trusts unverified JWT identity | routes/chat.ts, server.ts | Audn+Codex |
| #8 | High | Chat order tool trusts unsigned JWT identity | routes/chat.ts, lib/insecurity.ts | Audn+Codex |
| #9 | Medium | Unbounded complaint similarity scan enables DoS | server.ts, routes/verify.ts | Codex only |
| #10 | Medium | Lazy Web3 imports race creates duplicate listeners | server.ts, routes/nftMint.ts | Audn+Codex |
| #11 | Medium | Lazy ethers import races Web3 listener creation | routes/nftMint.ts, routes/web3Wallet.ts | Audn+Codex |
| #12 | Medium | CI smoke test re-enables npm lifecycle scripts | .github/workflows/ci.yml, package.js | Audn+Codex |
| #13 | Medium | Junie skill curls untrusted reference URLs | .junie/skills/add-reference/SKILL.md, REFERENCES.md | Codex only |
| #14 | Medium | Unsafe Junie curl crawling can expose local/internal resources | .junie/skills/add-reference/SKILL.md, junie/skills/add-reference/SKILL.md | Codex only |
| #15 | Medium | External Google Font leaks visitor metadata | config/ctf.yml, frontend/angular.js | Codex only |
| #16 | Low | Unconditional Google Fonts load leaks CTF visitor metadata | server.ts, frontend/angular.js | Codex only |
| #17 | Low | Windows i18n restore uses Unix-only basename parsing | en.js, lib/startup/restoreOverwrittenFilesWithOriginals.ts | Codex only |
| #18 | Info | Challenge name mismatch hides Hacking Instructor | data/static/challenges.yml, frontend/src/hacking-instructor/challenges/exposedCredentials.ts | Codex only |
| #19 | Info | Complaint length test no longer checks max boundary | frontend/src/app/complaint/complaint.component.spec.ts, frontend/src/app/complaint/complaint.component.ts | Codex only |
| #20 | Info | Missing snippet metadata now causes 500 errors | .info.yml, server.ts | Codex only |
These three aren't competitors; they're gates at different points on the path from commit to main. Cost sets the cadence: Aikido is cheap enough for every push, Codex rides every PR, and Audn — heavy and needing a live target — runs at the merge-to-main gate, exactly as you called it.
| Gate | Tool | Runs on | Cost | Blocks the merge when… |
|---|---|---|---|---|
| Baseline | Aikido | every commit / push | ~52s | a new dependency CVE or a secret enters the tree |
| PR gate | Codex | PR opened | light | the diff introduces a regression or logic bug |
| Merge-to-main gate | Audn | PR ready to merge | ~2h 28m | a vuln is live-confirmed exploitable on a preview deploy |
| Post-merge | Aikido + Audn | continuous / periodic | mixed | — monitoring for new CVEs & drift, not a gate |
The logic: run the cheapest, highest-frequency check (Aikido) earliest and often; reserve the expensive live-target check (Audn) for the merge-to-main milestone, where a false "ship it" is most costly. Codex sits in the middle as the human-review companion. One caveat worth planning for: Audn's ~2h 28m run means the merge gate is not instant — budget for it, or run Audn against the preview as soon as the PR is approved rather than at the moment of merge.