← CamelHive

CamelHive Field Notes

We test every audit rule against real, disclosed vulnerabilities in real production software — not synthetic examples we wrote ourselves.

Logging out didn't revoke a third party's access

GHSA-g72g-r7m4-9x4gCWE-613CVSS 5.3

Four code paths that end a session — password change, forgot-password, reset-password, and sign-out — only revoked the user's own refresh token. Any OAuth token already granted to a third-party app stayed alive, untouched by any of the four.

Fix: PR #13599 adds OAuthToken.revokeAllByUser(user.id) to all four paths. View

CH-SEC-018Session invalidation must revoke everything a session granted, not just the primary session token.

A service-only endpoint was reachable by any logged-in user

GHSA-hr66-5mqr-8mpxCWE-200CVSS 7.5

GET /api/global/users/tenant/:id — tenant user metadata — was registered in loggedInRoutes (any authenticated user) instead of internalRoutes (service-to-service calls only). A four-line routing mistake, not a missing check.

Fix: Moved the route registration from loggedInRoutes to internalRoutes. View

CH-SEC-007Endpoints are classified by who is allowed to call them, not just by whether a session exists.

The sibling bug — two unrelated repos, the same defect

Gitea: DoerViewOtherVisibility() let any non-admin, non-self user see organizations with limited visibility, without excluding restricted accounts. The single-org endpoint checked this correctly; the list endpoint used a different helper and didn't. Immich: ApiKeyService.create() validated that a new key couldn't be granted permissions its creator didn't have; update() applied the request directly, skipping that same check — any key could grant itself admin. Two unrelated codebases, the identical shape of mistake: a check that exists on one path and is missing on its neighbor.

Fix: Gitea PR #39047 adds the doer.IsRestricted check. Immich PR #25363 applies the same permission validation to update(). View

CH-SEC-007When one path validates correctly, check whether its neighbor does too.

A 6-digit login code with no attempt limit

GHSA-cwhc-53hw-qqx6CWE-307CVSS

Email login codes were 6 digits (900,000 combinations), valid for a 10-minute window, and compared in constant time — but with no attempt counter or lockout. The only defense against brute force was the generic HTTP rate limiter, documented elsewhere in the same codebase as bypassable two different ways.

Fix: Commit 1d86a4a adds a Redis-backed attempt counter (max 10) that invalidates the code once exceeded. View

CH-SEC-017Rate limiting and lockout for an auth endpoint have to live in the endpoint itself, not only in generic middleware.

How we verify a case

  • The vulnerable and fixed commits are both cloned at their exact SHA and read directly — never reconstructed from a changelog or an advisory's own description.
  • Ground truth never comes from what our own engine says about the code — it's verified by reading the real source, independent of any tool's output.
  • Every case goes through a second, adversarial review before it's published here.
  • Contamination risk — the possibility that a model already "knows" a recent advisory from training data rather than reading the code — is stated per case, not hidden.

Sourced from public GitHub security advisories. Fix credit belongs entirely to each project's maintainers.