Skip to content

feat(security): allowlist Superhuman MCP OAuth authorization endpoint - #5967

Closed
mndoci wants to merge 1 commit into
kirodotdev:mainfrom
mndoci:fix/superhuman-oauth-endpoint
Closed

feat(security): allowlist Superhuman MCP OAuth authorization endpoint#5967
mndoci wants to merge 1 commit into
kirodotdev:mainfrom
mndoci:fix/superhuman-oauth-endpoint

Conversation

@mndoci

@mndoci mndoci commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Problem / Motivation

Reconnecting the Superhuman Mail MCP server fails at the OAuth consent banner
with superhuman-mail authentication failed: URL contained credential or exfiltration pattern. The connection worked while its token was valid, then
broke once the token expired and a fresh authorization was required.

Why it matters

Superhuman is a shipped MCP integration. With this gate rejecting its consent
URL, the server cannot be (re-)authorized at all — every user whose Superhuman
token expires is locked out until a code change lands. It is the exact
regression class the consent-URL security gate documents: "A launch provider
missing from this set cannot be connected at all."

What changed (motivation → approach → change)

  • Symptom: the ACP OAuth banner is rejected for Superhuman.
  • Root cause: oauth_url_contains_credential() only waives the generic
    credential/exfiltration heuristics for high-entropy OAuth state/PKCE values
    when the consent URL's exact (host, path) is in the code-owned allowlist
    _OAUTH_AUTHORIZATION_ENDPOINTS. Superhuman's MCP authorization server —
    mcp.auth.mail.superhuman.com + /oauth2/authorize (from its published
    RFC 8414 metadata) — is not in that set, so its opaque state is scanned as a
    credential and the URL is rejected.
  • Change: add ("mcp.auth.mail.superhuman.com", "/oauth2/authorize") to the
    builtin allowlist, matching the existing MCP-server authorization endpoints
    (Stripe, GitLab, Linear, Notion, Vercel). No change to the scan logic or the
    exemption's shape — the exemption stays bound to the exact host+path, and
    fixed-credential detection is unaffected.

Tests

  • test/oauth_url_corpus.py: added a superhuman-mail-mcp entry to
    LEGIT_OAUTH_URLS, so the existing corpus contract test asserts a realistic
    Superhuman consent URL is never flagged and renders as a live banner.
  • test/test_mcp_oauth_banner.py: four targeted tests —
    the endpoint passes with high-entropy state; the SAME state at a look-alike
    host (…superhuman.com.attacker.example) is still rejected (no suffix/spoof
    match); a fixed AWS-key signature in a param is still rejected at the approved
    endpoint (the exemption covers entropy only, not fixed credentials); and the
    (host, path) pair is present in _OAUTH_AUTHORIZATION_ENDPOINTS.

Manual verification

Verified against the real security.oauth_url_contains_credential by importing
the module directly: the endpoint is in the allowlist (True); a realistic
Superhuman consent URL is allowed (returns False); a look-alike host is rejected
(True); an AWS key in state is rejected (True). N/A for UI — backend-only.

Related Issues

no linked issue: found while reconnecting Superhuman MCP; no tracked issue filed.

Checklist

  • At most two commits (one is the norm), with a Conventional Commits title (feat|fix|docs|refactor|perf|test|chore|ci|build|revert: ...)
  • Existing tests pass and new tests added for new functionality
  • Self-review completed; code follows project style guidelines
  • Documentation updated (if applicable)
  • No secrets, credentials, or internal references in the diff

Superhuman's MCP authorization server (mcp.auth.mail.superhuman.com,
/oauth2/authorize) was not in _OAUTH_AUTHORIZATION_ENDPOINTS, so its
consent URL's high-entropy state/PKCE values were scanned as credentials
and the banner was rejected with 'URL contained credential or
exfiltration pattern' — blocking reconnect after the OAuth token expired.

Add the endpoint to the builtin allowlist, a corpus entry, and targeted
tests asserting: the real endpoint passes, a look-alike host still
rejects, and a fixed credential in a param is still caught at the
approved endpoint.
@mndoci
mndoci requested a review from a team as a code owner August 26, 2026 01:14
@mndoci
mndoci requested a review from CrysisDeu August 26, 2026 01:14
@github-actions github-actions Bot added fork Pull request from a fork (external contributor) readiness: checking Automated validation is still running labels Aug 26, 2026
@github-actions

github-actions Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Design Review (Fable 5, fork) — 🟡 CONCERNS

Design-level review of 02c94312044a0a5146a10f2cbc994557d3349e81 via the fork AI-review pipeline — updated in place on each push. A BLOCK verdict blocks PR readiness; PASS/CONCERNS are advisory.

Superhuman appears nowhere else in the repo — not in the Connections registry (src/kiro_crew/connections/registry.json), which the allowlist's own comment defines as the membership criterion for the builtin set. And the docs show a designed operator escape hatch (oauth_endpoints.json) for exactly this situation. That's the core design signal here.

Design-Verdict: CONCERNS

The builtin allowlist is documented as the Connections-registry launch set; Superhuman isn't in that registry, and the operator extension file already covers this case.

Watch

  • The set's own comment (security.py:8111-8122) defines membership as "Every entry added to the Connections registry needs its MCP authorization server here too" — but connections/registry.json has no Superhuman entry and grep -ri superhuman src/ returns nothing. Baking in a non-registry provider erodes the set's stated invariant and sets the precedent that any user-connected server gets a code-owned trust entry, which is precisely what the operator-owned oauth_endpoints.json extension (security.md §Operator OAuth consent-endpoint extension) was built to absorb.
  • Description↔reality mismatch: "Superhuman is a shipped MCP integration" and "locked out until a code change lands" are both untrue in this repo — nothing ships Superhuman, and the operator file fixes reconnect today with no release. The PR's justification quotes the launch-set comment ("A launch provider missing from this set cannot be connected at all") for a provider that isn't a launch provider.

Suggestions

  • Either add Superhuman to the Connections registry in the same PR (restoring the pairing invariant), or close this and document oauth_endpoints.json as the remedy for user-added MCP servers.

[DESIGN-REVIEWED] 02c9431

@github-actions

github-actions Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

First Principles Review (Fable 5, fork) — 🔴 BLOCK

Premise-level review of 02c94312044a0a5146a10f2cbc994557d3349e81 via the fork AI-review pipeline — why this exists and whether the shipped surface is the smallest honest version. Updated in place on each push. A BLOCK verdict blocks PR readiness; PASS/CONCERNS are advisory.

All evidence is in. The base tree settles this: Superhuman appears nowhere in the repo (grep superhuman, case-insensitive: 0 matches), the Connections registry ships 7 providers with no Superhuman entry, and the spec (docs/system-specs/modules/security.md:169) names an existing operator-owned mechanism — oauth_endpoints.json — built precisely for consent endpoints outside the launch set.

First-Principles-Verdict: BLOCK

A builtin trust-widening for a provider this product does not ship, whose exact harm the documented operator extension already removes with one JSON entry.

What this change ships

Intent: let a user re-authorize their Superhuman Mail MCP server after token expiry — a FIX.

  1. Superhuman consent URLs now pass the banner gate on every install — duplicate of oauth_endpoints.json; zero consumers
  2. Corpus entry plus four tests pinning the endpoint — rides along with item 1
  3. No Connections registry entry accompanies it — undeclared gap in the fix's own premise

Blockers

The allowlist entry duplicates the operator extension and has zero in-tree consumers. The description claims "Superhuman is a shipped MCP integration" and invokes "A launch provider missing from this set cannot be connected at all" — but grep for superhuman across the base returns 0 matches, and src/kiro_crew/connections/registry.json lists 7 providers (Notion, GitHub, Linear, Atlassian, Stripe, Vercel, GitLab), none Superhuman. All five existing MCP entries in _OAUTH_AUTHORIZATION_ENDPOINTS correspond to registry providers; the set's own comment derives membership from "the registry's mcp_url." For everything outside that launch set, security.md:169 names the remedy: the keystone oauth_endpoints.json (_approved_oauth_authorization_endpoint, security.py:8371), which grants the identical exemption, takes effect without a restart, and SEL-audits each use. The zero option costs the reporter one hand-edited JSON entry and costs everyone else nothing.

Subtractions

  • Delete the ("mcp.auth.mail.superhuman.com", "/oauth2/authorize") entry in security.py and the four tests plus corpus entry pinning it; the reconnect is unblocked today via oauth_endpoints.json. Defer a builtin entry until a Superhuman registry entry lands, which is what would make it derived.

[FIRST-PRINCIPLES-REVIEWED] 02c9431

@github-actions

github-actions Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Opus 4.8 Review (fork) — ✅ no blocking findings

Reviewed 02c94312044a0a5146a10f2cbc994557d3349e81 via the fork AI-review pipeline; updated in place on each push.

Review details

The change adds one exact-match (host, path) tuple to the code-owned frozenset, consulted via exact tuple membership at line 8381-8382. No suffix/port/scheme relaxation, HTTPS enforcement stays at call sites, fixed-credential signatures remain unconditional. The remaining hunks are test additions. Nothing survives falsification, and I found no new grounded defect in Step 2.

No findings.

[OPUS-REVIEWED] 02c9431

@github-actions

github-actions Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

GPT 5.6 Review (fork) — ⚠️ review incomplete

Reviewed 02c94312044a0a5146a10f2cbc994557d3349e81 via the fork AI-review pipeline; updated in place on each push.

No completed GPT verdict for this commit; see the Fork GPT 5.6 Review job logs.

@github-actions github-actions Bot added readiness: action required A blocking check or review needs attention and removed readiness: checking Automated validation is still running labels Aug 26, 2026
@bolichen97
bolichen97 enabled auto-merge August 30, 2026 00:01
@iamwhatever iamwhatever added the needs-pr-triage PR scanner: awaiting automated triage label Aug 31, 2026
@bolichen97 bolichen97 added drive-to-green PR claimed by drive-to-green pipeline and removed needs-pr-triage PR scanner: awaiting automated triage labels Aug 31, 2026
@bolichen97

Copy link
Copy Markdown
Collaborator

🤖 Kiro Crew [operator: bolichen97#bb3ad1ca]: This PR has been inactive for 7+ days with failing CI. I've assessed the blockers and they appear resolvable — I'll push fixes directly to this branch as a co-author.

Assessment: All CI is green and GPT 5.6 passed; the sole readiness blocker is the fork Opus 4.8 review lane ending 'review incomplete' (fork review-lane infra failure, not a code defect). Plan: rebase onto current main and re-push to re-trigger the fork review lanes, then answer any findings.

If you'd prefer I don't touch this PR, add the pr-no-autofix label.

@bolichen97

Copy link
Copy Markdown
Collaborator

🤖 Kiro Crew [operator: bolichen97#bb3ad1ca]: Drive-to-green escalation — maintainer decision required. No pushes made; branch untouched at 02c9431.

Why: This drive was dispatched on a stale assessment ("readiness blocked only by the fork Opus lane's infra failure"). The 03:16–03:23Z review wave changed the state: Opus 4.8 is now ✅ PASS, UX ✅, Design 🟡 CONCERNS (advisory) — but First Principles posted a 🔴 BLOCK on the current head, and its objection is to the allowlist entry itself, not the implementation. Pipeline policy: when a reviewer raises the entry's existence as a policy question, we escalate rather than argue policy.

The policy question (facts independently verified against current main):

  • src/kiro_crew/connections/registry.json ships 7 providers; Superhuman is not among them. Repo-wide code search for "superhuman": 0 hits outside this PR.
  • The builtin set's own comment defines membership as Connections-registry-derived; all 5 existing MCP entries correspond to registry providers.
  • The documented operator extension oauth_endpoints.json (security.md §Operator OAuth consent-endpoint extension; _approved_oauth_authorization_endpoint) already grants the identical exemption for user-added servers, with no code change or release.

Maintainer options:

  1. Accept the subtraction — close this PR and document oauth_endpoints.json as the remedy for user-added MCP servers (First Principles' recommendation; also Design's second suggestion). Closing a contributor's PR is a human call, not the pipeline's.
  2. Make the entry derived — add Superhuman to the Connections registry so the builtin entry satisfies the set's stated membership invariant (Design's first suggestion). That is a product/scope decision beyond this PR's diff and outside this pipeline's mandate (we never expand a contributor PR's scope).
  3. Override — decide the builtin entry is desirable as-is and clear the First Principles verdict via the repo's review-override process.

Why no rebase/push: a push would re-arm all five review lanes, voiding the converged Opus/Design/UX verdicts on this head and re-burning the full CI matrix — without changing the outcome, because the BLOCK is grounded in main-tree facts a rebase does not alter. (The GPT 5.6 lane shows "review incomplete" on this head — its run failed before producing a verdict; immaterial here since the First Principles BLOCK alone blocks readiness.)

Labels: needs-human applied; drive-to-green left in place per pipeline convention.

@CrysisDeu

Copy link
Copy Markdown
Collaborator

Closing as superseded by #8239 (merged as b9a65be) — thank you @mndoci for tracking this down and for the fix.

Your diagnosis was exactly right: the MCP OAuth banner refused Superhuman's reconnect because mcp.auth.mail.superhuman.com/oauth2/authorize was not a known authorization endpoint. The reason this PR stalled in review was the shape of the fix rather than its substance — the First Principles lane blocks a bare allowlist entry for a provider that is not in the Connections registry, since oauth_endpoints.json already exists as the operator-side extension point for exactly that case.

#8239 takes the registry-derived route instead: Superhuman Mail is now a Connections provider (src/kiro_crew/connections/registry.json, launch-gated until someone with a Business/Enterprise account can walk the consent + revoke flow), and the allowlist entry follows from that. Everything from this PR landed with it, credited to you as co-author:

  • the ("mcp.auth.mail.superhuman.com", "/oauth2/authorize") allowlist line in security.py — identical to yours
  • the superhuman-mail-mcp corpus entry in test/oauth_url_corpus.py (scope adjusted to email+offline_access, which is what Superhuman's RFC 8414 metadata actually advertises)
  • your four banner tests in test/test_mcp_oauth_banner.py
  • plus a new registry test that pins every registry provider's authorization server to the builtin allowlist, so this class of bug cannot recur for future providers

If you are on a Superhuman Business plan and want to help un-gate it, the checklist is in the #8239 description. Thanks again.

@CrysisDeu CrysisDeu closed this Sep 4, 2026
auto-merge was automatically disabled September 4, 2026 00:00

Pull request was closed

@dwu96 dwu96 removed the drive-to-green PR claimed by drive-to-green pipeline label Sep 4, 2026
@github-actions github-actions Bot removed the readiness: action required A blocking check or review needs attention label Sep 4, 2026
@bolichen97

Copy link
Copy Markdown
Collaborator

Open PR relationship audit

This is a consolidated, point-in-time code-level audit note. It compares complete merge-base diffs and current/merged code; it does not treat a shared topic as duplication or partial coverage as completion.

Relationship findings

  • PR #7621 is OVERLAPPING relative to this PR. The goals differ or the implementations can complement each other; this is not a duplicate claim. Recommended action for PR #7621: MERGE_DISCUSSION. Different providers, additive entries: not a duplicate. Only worth noting as a merge-order hazard in the shared frozenset and corpus list, and as the review bar PR #7621 sets itself against (PR #5967 ships per-provider banner tests, PR #7621 does not). Files: src/kiro_crew/security.py, test/oauth_url_corpus.py.

No PR, Issue, label, branch, or review state was changed by the relationship-note portion of this audit.

NicholasRBowers pushed a commit to psantus/KiroCrew that referenced this pull request Sep 8, 2026
Reconnecting the Figma MCP server fails at the OAuth consent banner with
"authentication failed: URL contained credential or exfiltration pattern":
its authorization endpoint is absent from the code-owned
`_OAUTH_AUTHORIZATION_ENDPOINTS` allowlist, so the generic
credential/exfiltration heuristic fires on the high-entropy PKCE
state/code_challenge params of an otherwise-normal consent URL.

Figma is a shipped/common MCP provider, so until this lands users must
hand-edit the operator keystone `oauth_endpoints.json` to connect it.

Add the (host, path) pair, taken from the provider's RFC 8414 metadata
reached via RFC 9728 protected-resource discovery on its MCP url:
- Figma: www.figma.com/oauth/mcp (issuer https://api.figma.com)

Cover it with a LEGIT_OAUTH_URLS corpus entry (real consent-URL shape),
mirroring the pattern established for Superhuman in kirodotdev#5967.

This PR originally also covered Miro; that entry landed separately on
main via kirodotdev#7739 and was dropped here during rebase.

Original change by Paul SANTUS (psantus).

Co-authored-by: Kiro Crew <noreply@kirodotdev.github.io>
NicholasRBowers pushed a commit to psantus/KiroCrew that referenced this pull request Sep 8, 2026
Reconnecting the Figma MCP server fails at the OAuth consent banner with
"authentication failed: URL contained credential or exfiltration pattern":
its authorization endpoint is absent from the code-owned
`_OAUTH_AUTHORIZATION_ENDPOINTS` allowlist, so the generic
credential/exfiltration heuristic fires on the high-entropy PKCE
state/code_challenge params of an otherwise-normal consent URL.

Figma is a shipped/common MCP provider, so until this lands users must
hand-edit the operator keystone `oauth_endpoints.json` to connect it.

Add the (host, path) pair, taken from the provider's RFC 8414 metadata
reached via RFC 9728 protected-resource discovery on its MCP url:
- Figma: www.figma.com/oauth/mcp (issuer https://api.figma.com)

Cover it with a LEGIT_OAUTH_URLS corpus entry (real consent-URL shape),
mirroring the pattern established for Superhuman in kirodotdev#5967.

This PR originally also covered Miro; that entry landed separately on
main via kirodotdev#7739 and was dropped here during rebase.

Also trim the date from the neighboring Miro comment: main outgrew the
comment-history baseline for this file after kirodotdev#7739 landed (issues kirodotdev#9384,
kirodotdev#9385), so any PR touching it failed the gate. Dropping the one dated
narration span returns the file to its baselined count; the verification
claim itself stays.

Original change by Paul SANTUS (psantus).

Co-authored-by: Kiro Crew <noreply@kirodotdev.github.io>
NicholasRBowers pushed a commit to psantus/KiroCrew that referenced this pull request Sep 8, 2026
Reconnecting the Figma MCP server fails at the OAuth consent banner with
"authentication failed: URL contained credential or exfiltration pattern":
its authorization endpoint is absent from the code-owned
`_OAUTH_AUTHORIZATION_ENDPOINTS` allowlist, so the generic
credential/exfiltration heuristic fires on the high-entropy PKCE
state/code_challenge params of an otherwise-normal consent URL.

Figma is a shipped/common MCP provider, so until this lands users must
hand-edit the operator keystone `oauth_endpoints.json` to connect it.

Add the (host, path) pair, independently corroborated by the drive
operator via live RFC 9728 protected-resource discovery and the
provider's RFC 8414 metadata
reached via RFC 9728 protected-resource discovery on its MCP url:
- Figma: www.figma.com/oauth/mcp (issuer https://api.figma.com)

Cover it with a LEGIT_OAUTH_URLS corpus entry (real consent-URL shape),
mirroring the pattern established for Superhuman in kirodotdev#5967.

This PR originally also covered Miro; that entry landed separately on
main via kirodotdev#7739 and was dropped here during rebase.

Also trim the date from the neighboring Miro comment: main outgrew the
comment-history baseline for this file after kirodotdev#7739 landed (issues kirodotdev#9384,
kirodotdev#9385), so any PR touching it failed the gate. Dropping the one dated
narration span returns the file to its baselined count; the verification
claim itself stays.

Original change by Paul SANTUS (psantus).

Co-authored-by: Kiro Crew <noreply@kirodotdev.github.io>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fork Pull request from a fork (external contributor) needs-human PR flagged for human review by drive-to-green pipeline

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants