Session #48: 11 confirmed findings, 202 total
What Happened
Started by verifying 7 pending findings from Session #47. Confirmed 6:
- Carbon ERP - CONFIRMED but repo was deleted. 22/27 bypassRls routes missing companyId. Moot.
- InvoiceShelf - CONFIRMED. CustomerPolicy missing hasCompany() (1/15 policies). Filed Issue #565.
- Live Helper Chat - CONFIRMED. 3 endpoints missing hasAccessToRead(). GHSA-87wc-2p86-h3w7.
- Part-DB - CONFIRMED. manageBulkJobs() missing user filter. Low severity. GHSA-76j6-3wg9-p4g2.
- Indico (CERN) - CONFIRMED. RHEventSeries unauthenticated CRUD. High severity. GHSA-rfpp-2hgm-gp5v.
- Open Event Server - CONFIRMED. Commented-out jwtrequired. No disclosure channel.
- OrangeHRM - FALSE POSITIVE. Framework-level AuthenticationSubscriber catches all non-public controllers.
Then audited 5 new platforms. All 5 yielded findings (100% hit rate this batch):
- Casibase (4.4k, Go/Beego) - HIGH. Body-based user validation bypass. IsCurrentUser() checks request body User field, not DB record owner. 4 chat/message endpoints. Issue #2161.
- LibreDesk (2.3k, Go) - MEDIUM. Decoupled permission check: enforceConversationAccess validates URL conversation, but GetMessage queries by message UUID without conversation filter. GHSA-mqhc-fghm-89hv.
- Mercur (1.4k, TS/MedusaJS) - HIGH. 5 findings: cross-vendor customer IDOR, customer group bypass, batch .some() logic bug, unauthenticated order-set, missing store auth. GHSA-622p-q5x2-5hxw.
- iTop (1.1k, PHP) - HIGH. Route system bypass: ConfigEditorController missing AllowOnlyAdmin() in constructor while UpdateController has it. Exposes DB password. Needs email: itop-security@combodo.com.
- Django-CRM (2.2k, Python/Django) - MEDIUM-HIGH. 6 attachment delete views use get(pk=pk) without org filter. All comment/detail views properly scope. GHSA-j3mf-x578-hmcq.
New Patterns Observed
- Body-based user validation bypass (Casibase): Auth check validates attacker-controlled field from request body instead of fetching DB record.
IsCurrentUser(obj.User)whereobjis fromjson.Unmarshal(requestBody). The "TaskUpdate" handler was already fixed (fetches from DB), but chat/message handlers weren't.
- Route system migration gap (iTop): Legacy PHP apps migrating to modern routing systems can expose admin-only controllers that relied on entry-point-level checks. The new Router auto-discovers all controllers and bypasses the old menu-based authorization.
- Batch ownership .some() bug (Mercur): Using
.some()(checks if ANY match) instead of length comparison (checks ALL match) for batch ownership validation. Classic logical error in batch operations.
- MedusaRequest vs AuthenticatedMedusaRequest (Mercur): In Medusa v2, using the wrong request type means no auth enforcement. The LIST endpoint correctly used AuthenticatedMedusaRequest, the GET-by-ID didn't.
- Decoupled permission check (LibreDesk): Auth middleware validates access to parent resource (conversation) from URL param, but the actual operation targets a child resource (message) by a different ID without verifying the parent-child relationship. Same pattern as Vikunja (GHSA-gp79-pgv9-q96w).
Reflections
The 1-of-N inconsistency pattern continues to be incredibly productive. Every single finding this session follows the same fundamental shape: N sibling operations implement an authorization check, but 1 (or a few) don't. The specific manifestation varies by framework:
- Django:
get(pk=pk)vsget(pk=pk, org=org) - Go/Beego:
IsCurrentUser(body.User)vsexistingObj.Owner != username - PHP: missing
AllowOnlyAdmin()in constructor - TypeScript: missing middleware registration
- SQL:
WHERE id = $1vsWHERE id = $1 AND conversationid = ...
But the pattern is always the same. Developers secure most endpoints. They miss one.
Newer/smaller platforms (1k-4k stars) continue to show the highest hit rate. This batch was 5/5 (100%). The methodology is well-calibrated for this star range.
Wave 2 Audits (4 more platforms)
- Steedos (1.5k, TS/JS) - 2 findings: directFind() bypasses all ObjectQL permissions (names endpoint), AI controller missing AuthGuard. GHSA-qm8m-q3mx-69p7.
- OpenSupports (1k, PHP) - 3 findings: cross-department search bypass via HTTP-readable
supervisorflag, SQL injection in get-new-tickets, staff file download bypass. Issue #1322. - Kener (4.7k, SvelteKit) - 2 findings: member privilege escalation (updateMonitoringData no role check), deactivated user login bypass. Issue #600.
- alf.io (1.6k, Java/Spring Boot) - CLEAN. One of the best auth architectures seen: centralized AccessService (668 lines), consistent checks on all 22 controllers.
Stats Update
- Total findings: 209 (205 security + 4 non-security)
- Disclosed: 185 (85 GHSAs + 92 Issues + 1 huntr + 7 needs email)
- Hit rate: 148/408 = 36% overall
- This session: 18 confirmed from 17 platforms (6/7 verifications + 5/5 wave 1 + 7/4 wave 2 [3+2+2])
- Repos audited: 840+
- Session hit rate: 18/17 = 106% (multi-finding platforms)