feat(security): allowlist the Figma MCP OAuth authorization endpoint - #7621
feat(security): allowlist the Figma MCP OAuth authorization endpoint#7621psantus wants to merge 1 commit into
Conversation
|
👋 Hi! This PR's description is missing some required sections from our PR template. Workflow runs won't be auto-approved until the description is updated. Missing sections:
Please update your PR description to include these sections, then push or re-save the description. The workflows will be approved on the next cycle. |
1 similar comment
|
👋 Hi! This PR's description is missing some required sections from our PR template. Workflow runs won't be auto-approved until the description is updated. Missing sections:
Please update your PR description to include these sections, then push or re-save the description. The workflows will be approved on the next cycle. |
Open PR relationship auditThis 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
No PR, Issue, label, branch, or review state was changed by the relationship-note portion of this audit. |
|
👋 Hi! This PR's description is missing some required sections from our PR template. Workflow runs won't be auto-approved until the description is updated. Missing sections:
Please update your PR description to include these sections, then push or re-save the description. The workflows will be approved on the next cycle. |
1 similar comment
|
👋 Hi! This PR's description is missing some required sections from our PR template. Workflow runs won't be auto-approved until the description is updated. Missing sections:
Please update your PR description to include these sections, then push or re-save the description. The workflows will be approved on the next cycle. |
|
🤖 Kiro Crew [operator: NicholasRBowers#a942f9ca]: 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: The merge conflict is mechanical — merged #7739 already landed the Miro allowlist entry ( If you'd prefer I don't touch this PR, add the |
dfcaa12 to
0b0b460
Compare
|
🤖 Drive-to-green (operator NicholasRBowers#a942f9ca) Rebased this PR onto current 1. Dropped the Miro hunks during rebase. Main already carries the exact Miro allowlist entry and 2. Ported the Figma allowlist pair into 3. Kept the 4. Rewrote the PR body onto the current template. The old body had a 5. Commit authorship. @psantus (Paul SANTUS) remains the commit author, moved to his GitHub noreply address; a Local verification before push: isort / flake8 / black / mypy clean; |
Opus 4.8 Review (fork) — ✅ no blocking findingsReviewed |
Design Review (Fable 5, fork) — ✅ PASSDesign-level review of Design-Verdict: PASS Narrow, reversible data addition to a code-owned exact-match allowlist, following the established Superhuman/Miro precedent, with the accept decision pinned by the corpus contract test. [DESIGN-REVIEWED] f1849e0 |
First Principles Review (Fable 5, fork) — 🟡 CONCERNSPremise-level review of All verification is done. The comment-history gate claim checks out (baseline 4, base file carries 5 spans, the trim restores 4), the corpus test genuinely consumes the new entry and would fail on base, the connections-registry mechanism doesn't cover Figma, and the base code's own comment documents the fail-closed regression class. The one thing I could not verify is the external claim itself — Figma's real First-Principles-Verdict: CONCERNS The Not justified as shipped
What this change shipsIntent: make the Figma MCP server connectable without hand-editing the operator keystone. FIX.
WatchThe allowlist row is a claim about Figma's live RFC 8414 metadata that nothing in this repo or its tests can corroborate — [FIRST-PRINCIPLES-REVIEWED] f1849e0 |
GPT 5.6 Review (fork) — ✅ no blocking findingsReviewed Review detailsNo findings. |
|
self-added: no 🤖 Disposition (operator NicholasRBowers#a942f9ca) — rebutted (corroboration now on the record)
The scope note also holds: a wrong pair is inert (Figma stays fail-closed), and the exemption is path-exact — |
0b0b460 to
d759bad
Compare
|
🤖 Drive-to-green round 2 (operator NicholasRBowers#a942f9ca) Pushed CI red triaged: Fix, per the #9384 policy ("fix the drift on main, never raise an entry"): dropped the one dated narration span — Local gates re-verified on |
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>
d759bad to
f1849e0
Compare
|
self-added: no 🤖 Disposition (operator NicholasRBowers#a942f9ca) — fixed in
|
|
self-added: no 🤖 Disposition (operator NicholasRBowers#a942f9ca) — fixed
|
|
🤖 Drive-to-green round 3 (operator NicholasRBowers#a942f9ca) Pushed 1. Recorded the corroboration in the Figma entry's comment ( 2. Retitled the PR and commit to Figma-only per the Design suggestion — the Miro entry landed separately on main. Local gates re-verified on |
|
self-added: no 🤖 Disposition (operator NicholasRBowers#a942f9ca) — rebutted (the clearing condition is already met on this PR's record)
|
|
🤖 Drive-to-green complete (operator NicholasRBowers#a942f9ca) This PR is review-ready at Drive summary: rebased over ~2.3k commits of base drift (three rebases as main moved), dropped the Miro hunks (landed via #7739), ported the Figma pair into Remaining gate is human maintainer review. Auto-merge is not armed. |
|
@psantus Thanks for this, and for the rebase. I am reading head State on Your current head already matches what we would have asked for: the Miro entries dropped, the Figma pair re-targeted from the deleted Two small things before review:
Note this does not close #7578: the RFC 8414 auto-discovery half of that request is still unimplemented on Posted from the 2026-09-08 open-PR relationship audit (read-only, one auditor per PR); reply here if any of this is wrong. |
|
🤖 Closing as superseded (operator NicholasRBowers#a942f9ca) Main now carries everything this PR set out to do: #9429 (Connections industry-baseline batch 1, merged 2026-09-08) added the Figma MCP OAuth allowlist coverage — both Full credit to @psantus: this PR identified the Figma gap first (2026-09-01, a week before the batch), did the RFC 9728/RFC 8414 discovery work that pinpointed the exact consent-host pair, and was driven to fully review-ready (68/68 checks green, all five AI review lanes clean) before the batch landed. The independent live corroboration of the pair is on this PR's record. Thank you for the contribution and the careful endpoint verification — the fix users get on main is the one you scoped. Closing without merge; the branch is untouched on the fork. |
Problem / Motivation
Reconnecting the Figma MCP server fails at the OAuth consent banner with:
Root cause:
oauth_url_contains_credential()only waives the generic credential/exfiltration heuristics for the high-entropy OAuthstate/PKCE values when the consent URL's exact(host, path)is in the code-owned allowlist_OAUTH_AUTHORIZATION_ENDPOINTS(now insrc/kiro_crew/security/exfil.py). Figma is absent, so its normal consent URL fails closed — the exact regression class the gate's own comment documents: "A launch provider missing from this set cannot be connected at all."Why it matters
Figma is a shipped/common MCP integration. Until this lands, every user has to hand-edit the operator keystone
oauth_endpoints.jsonto connect it (undocumented; see #7578). Adding it to the builtin set makes it work out of the box.What changed (motivation → approach → change)
The Figma MCP consent URL is rejected by the banner gate. The fix adds one
(host, path)pair to the code-owned allowlist.The pair comes from Figma's own RFC 8414 metadata, reached via RFC 9728 protected-resource discovery on its MCP url:
www.figma.com+/oauth/mcp(issuerhttps://api.figma.com; the consent page is hosted onwww.figma.com, discovered fromhttps://mcp.figma.com/mcp).The diff also trims the date from the neighboring Miro comment in
exfil.py: main outgrew the comment-history baseline for this file after #7739 landed (tracked in #9384/#9385), so any PR touching it failed theBackend Lint & Type Checkgate. Dropping the one dated narration span returns the file to its baselined count; the verification claim itself stays.A matching
figma-mcpentry in theLEGIT_OAUTH_URLScorpus (a real consent-URL shape with fake identifiers) locks in that the banner-safety contract accepts it under default config, mirroring the pattern established for Superhuman in #5967.Tests
test/oauth_url_corpus.pygains thefigma-mcpentry; the existing parametrized contract tests (test_corpus_url_not_flagged_as_credential,test_corpus_url_renders_bannerintest/test_mcp_oauth_banner.py) now cover it: the URL passesoauth_url_contains_credentialand renders a live auth banner, not a rejection.test/test_security.py+test/test_mcp_oauth_banner.py: 1066 passed locally.flake8/isort/black/mypyclean on the changed files.Manual verification
N/A — unit coverage sufficient: the corpus contract test exercises the exact accept/reject decision the banner takes on this URL shape.
Screenshots / video
N/A — backend-only diff, no user-visible UI change.
Related Issues
Refs #7578 (opaque error / undocumented allowlist) — not closed by this PR: its asks (name the offending host in the error, RFC 8414 auto-discovery) are broader and remain valuable.
no linked issue: this is the per-provider unbreak step following the #5967 pattern; the broader tracking issue #7578 stays open by design.
Pattern harvest
Not generalizable: one-off data addition to a code-owned allowlist; the recurring class (each new provider needs a code change) is already tracked as #7578.
Checklist
feat|fix|docs|refactor|perf|test|chore|ci|build|revert: ...)