fix(discovery-index): cap the untrusted response candidate list (#6774) - #6870
Conversation
…bored#6774) normalizeDiscoveryIndexResponse looped over the response's `candidates` array with no length cap. The request side already clamps page size to MAX_PAGE_LIMIT (200), but the response comes from the OPTIONAL, only-partially-trusted hosted discovery-index service (this module's own header frames it as an external boundary). A misbehaving or compromised host could return an arbitrarily large `candidates` array and force unbounded client-side normalization. Caps the array at MAX_PAGE_LIMIT, dropping the overflow with a warning; the retained page and `nextCursor` still round-trip so forward pagination continues from the truncated page. Adds a regression test asserting an oversized (250-candidate) response is truncated to 200 with the warning and a preserved cursor. Closes JSONbored#6774
|
Superagent didn't find any vulnerabilities or security issues in this PR. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #6870 +/- ##
=======================================
Coverage 93.65% 93.65%
=======================================
Files 685 685
Lines 68247 68250 +3
Branches 18707 18709 +2
=======================================
+ Hits 63914 63917 +3
Misses 3348 3348
Partials 985 985
Flags with carried forward coverage won't be shown. Click here to find out more.
|
|
Tip ✅ LoopOver review result - approve/merge recommendedReview updated: 2026-07-17 10:04:41 UTC
Review summary Nits — 4 non-blocking
Decision drivers
Context & advisory signals — never blocks the verdict
Review context
Contributor next steps
Signal definitions
🧪 Chat with LoopOverAsk LoopOver a question about this PR directly in a comment — grounded only in the same cached, public-safe facts shown above, never a new claim.
Full command reference: https://loopover.ai/docs/loopover-commands 🧪 Experimental — new and may change. 🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed 💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →. Checked by LoopOver, a quiet PR intelligence layer for OSS maintainers.
|
Summary
normalizeDiscoveryIndexResponse(packages/loopover-engine/src/discovery-index-contract.ts) looped over theresponse's
candidatesarray with no length cap. The request side already clamps page size toMAX_PAGE_LIMIT(200) viaclampLimit, but the response comes from the OPTIONAL, only-partially-trustedhosted discovery-index service — this module's own header frames it as an external boundary
("NO raw scores / rewards / wallet / hotkey data / source contents crossing the public boundary"). A misbehaving
or compromised host could return an arbitrarily large
candidatesarray and force unbounded client-sidenormalization.
This caps the array at
MAX_PAGE_LIMIT, dropping the overflow with a warning:The retained page and
nextCursorstill round-trip, so forward pagination continues from the truncated page.Consistent with the module's tolerant-parser convention (degrade with a warning, never throw).
Closes #6774
Scope
type(scope): short summaryConventional Commit format.CONTRIBUTING.mdand does not reintroduce GitHub Pages, VitePress,site/, orCNAME.Closes #6774).Validation
git diff --checknpm run typechecknpm run test:coveragelocally — the new cap lines are exercised on both branches (oversized → truncate + warn; the≤ cappath is covered by the existing response test), verified viacoverage-final.json.npx vitest run test/unit/discovery-index-contract.test.ts(17 passing, incl. the new 250→200 truncation regression asserting the warning + preservednextCursor)build+node --test(588 passing) +engine-parity:drift-checkIf any required check was skipped, explain why:
Safety
UI Evidencesection is required.Notes
MAX_PAGE_LIMIT(200) — a well-behaved host can never return more than one page's worth, so this only ever drops data an over-limit/hostile host tried to push.nextCursoris parsed independently of the candidate list, so truncating a page does not break pagination.