Skip to content

orb(security): maintainer-packet route skips the MCP repo allowlist its three sibling routes enforce (IDOR) #9045

Description

@JSONbored

GET /v1/repos/:owner/:repo/pulls/:number/maintainer-packet (src/api/routes.ts ~3432-3433) gates only with requireStaticProtectedApiToken, which admits any static identity including mcp (~6447-6453). It never checks isMcpReadRepoAllowed.

All three sibling routes using the same gate DO check it:

Route allowlist check
/pulls/:number/maintainer-packet (~3432) missing
/pulls/:number/reviewability (~3456) present (~3460)
/gate-config/effective (~3526) present
/live-gate-thresholds (~3554) present

The MCP tool this route explicitly mirrors is scoped — src/mcp/server.ts ~3724-3734 calls canAccessRepoisMcpReadRepoAllowed (~4106-4116). So this is precisely the failure the codebase names elsewhere: the HTTP surface silently grants what the MCP surface denies for the same token (routes.ts ~6462-6464).

Impact if reached: the full maintainer packet — all repo issues, all PRs, per-PR files, reviews, check summaries, recent merged PRs. Amplified because MCP_READ_REPO_ALLOWLIST is fail-closed by default (unset ⇒ deny all, src/auth/security.ts ~224-229), so the intended posture is "deny everything" while this route allows everything. The shipped CLI proxies this exact route (packages/loopover-mcp/bin/loopover-mcp.ts ~1764).

Current exposure: LOW — not remotely reachable. Verified: the Cloudflare tunnel exposes only ^/loopover/shot.*$; this path returns 404 from the internet, and 8787 is bound to 127.0.0.1. Exploitation requires the shared MCP token AND network access to the box (tailnet/localhost).

Why fix it anyway: the token is documented as a shared, end-user-obtainable CLI credential, and the planned hosted Orb removes the network isolation that is currently doing all the work. This is a one-line omission that becomes critical the moment the API is exposed.

Fix

Copy the allowlist check from the reviewability route into this handler. Better: fold it into requireStaticProtectedApiToken via an optional repoFullName argument so a future route cannot forget it.

Metadata

Metadata

Assignees

Labels

maintainer-onlyOwner-only work — yields no Gittensor points.orbGittensory Orb related - maintainer self-hosting analytics.

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions