Skip to content

fix(rate-limit): fail open when the bearer-identity DB lookup errors#9224

Merged
JSONbored merged 1 commit into
mainfrom
fix/9223-rate-limit-identity-db-fail-open
Jul 27, 2026
Merged

fix(rate-limit): fail open when the bearer-identity DB lookup errors#9224
JSONbored merged 1 commit into
mainfrom
fix/9223-rate-limit-identity-db-fail-open

Conversation

@JSONbored

Copy link
Copy Markdown
Owner

Summary

  • validateBearerForRateLimit (src/auth/rate-limit.ts) runs on every request ahead of route handlers to decide whether a bearer token should get its own rate-limit bucket or fall back to IP-keying. It calls into authenticatePrivateTokenauthenticateSessionToken, which does a real D1/Drizzle read against auth_sessions.
  • That read was unguarded. If it throws, the error escapes the app.use("*", ...) middleware uncaught (no app.onError is registered anywhere in the app), and Hono falls back to a bare, non-JSON Internal Server Error for whatever route happened to be hit — indistinguishable from a bug in that route's own handler, even though the request's actual authorization check (later, dedicated middleware) never even ran yet.
  • This mirrors an existing fail-open precedent one function up in the same file: the Durable Object rate-limit-bucket call in checkRateLimitBucket is explicitly wrapped in try/catch for the same reason (fix(orb): /v1/orb/token still returns 500 after the #orb-broker-500 fix (95 Sentry events) #5000 — no global error handler exists, so a rate-limiting side-channel must never be able to take down an otherwise-healthy request).
  • Fix: wrap the DB-touching identity check in try/catch, log, and fail open to "unrecognized token" (IP-keyed identity) on error — this only affects which bucket a request is counted against, never whether it's authorized.

Scope

  • The PR title follows type(scope): short summary Conventional Commit format.
  • This PR is focused and does not mix unrelated backend, UI, MCP, docs, dependency, and deploy changes.
  • This follows CONTRIBUTING.md and does not reintroduce GitHub Pages, VitePress, site/, or CNAME.
  • I linked a currently open issue this PR resolves.

Closes #9223

Validation

  • npx vitest run test/integration/orb-ingest.test.ts — 47/47 pass, including the previously-failing "tolerates a list query that omits results (rows.results ?? [])" regression test, which reproduces this exact failure mode (a DB stub missing .bind() now degrades gracefully instead of throwing an uncaught 500).
  • npm audit --audit-level=moderate — pre-existing high-severity findings in the eslint/brace-expansion devDependency chain only; unrelated to this change (no package.json/lockfile diff).
  • Full npm run test:ci (typecheck, coverage, workers, mcp/miner pack, ui suite, etc.) was not run for this PR.

If any required check was skipped, explain why:

  • This is a maintainer PR for a small, self-contained fix (one function, wrapped in a try/catch matching an existing pattern in the same file). The targeted regression test that already exists in the repo (and was failing before this fix) covers the change; the broader test:ci suite was skipped to land this fix quickly.

Safety

  • No secrets, wallet details, hotkeys, coldkeys, user PATs, private keys, raw trust scores, private rankings, or private maintainer evidence are exposed.
  • Public GitHub text stays sanitized, low-noise, and does not imply compensation guarantees or optimization tactics.
  • Auth-adjacent change (rate-limit identity classification) — behavior on error now falls back to the existing "unrecognized token → IP-keyed" path, covered by the existing test suite's happy-path and 401 tests for this middleware; no new negative-path test was added beyond the existing failing-DB-stub test that now passes.
  • API/OpenAPI/MCP behavior unaffected (internal middleware only, no route contract change).
  • No UI changes.
  • No changelog edit.

Notes

  • No UI Evidence section: this is a backend-only middleware fix with no visible surface.

…9223)

validateBearerForRateLimit only classifies which rate-limit bucket a caller
lands in, not the real authorization decision -- but its session-token DB
read was unguarded, so any driver error there escaped the whole middleware
chain uncaught and surfaced as a bare non-JSON 500 for whatever route was
hit. Wrap it in the same fail-open try/catch already used for the Durable
Object call in this file (#5000).
@JSONbored JSONbored self-assigned this Jul 27, 2026
@superagent-security

Copy link
Copy Markdown
Contributor

Superagent didn't find any vulnerabilities or security issues in this PR.

@JSONbored
JSONbored merged commit 6ab3f04 into main Jul 27, 2026
3 of 4 checks passed
@JSONbored
JSONbored deleted the fix/9223-rate-limit-identity-db-fail-open branch July 27, 2026 08:04
@loopover-orb loopover-orb Bot added the gittensor:bug Gittensor-scored bug fix — scores a 0.05x multiplier. label Jul 27, 2026
@codecov

codecov Bot commented Jul 27, 2026

Copy link
Copy Markdown

❌ 2 Tests Failed:

Tests completed Failed Passed Skipped
22198 2 22196 21
View the top 2 failed test(s) by shortest run time
test/integration/orb-relay.test.ts > POST /v1/orb/relay/pull > REGRESSION (#4995): a DB error inside validateOrbRelayEnrollment's own lookup ALSO returns a clean 503 broker_error, not a framework 500 (the earlier of the two DB-touching calls in this handler)
Stack Traces | 0.00962s run time
AssertionError: expected 500 to be 503 // Object.is equality

- Expected
+ Received

- 503
+ 500

 ❯ test/integration/orb-relay.test.ts:1160:24
test/integration/orb-relay.test.ts > POST /v1/orb/relay/register > REGRESSION (#4995): a DB error inside validateOrbRelayEnrollment's own lookup ALSO returns a clean 503 broker_error, not a framework 500 (the earlier of the two DB-touching calls in this handler)
Stack Traces | 0.104s run time
AssertionError: expected 500 to be 503 // Object.is equality

- Expected
+ Received

- 503
+ 500

 ❯ test/integration/orb-relay.test.ts:155:24

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gittensor:bug Gittensor-scored bug fix — scores a 0.05x multiplier.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(rate-limit): DB error during bearer-identity classification crashes the request with a non-JSON 500

1 participant