Linear의 MCP 서버는 기밀 OAuth 클라이언트에 대한 HTTP:// 리디렉션 URI를 허용합니다.

hackernews | | 🔧 개발도구
#review
원문 출처: hackernews · Genesis Park에서 요약 및 분석

요약

Linear의 원격 MCP 서버는 OAuth 2.1 인증 요구 사항 감사 대상이 되었습니다. 이 서버는 PKCE S256을 강제하는 등 보안 요소를 잘 구현했으나, 기밀 클라이언트의 불안전한 HTTP 리다이렉트 URI 허용 등 스펙 위반 사항을 /register 엔드포인트에서 발견했습니다. 이전 감사 대상인 GitHub와 달리 Linear의 인프라는 최근 구축되어 구조적 결함이 아닌 구현 수준의 문제로 지적되었습니다.

본문

Audit 02. Linear MCP Server. 2026-05-04. Linear's remote MCP server gets the OAuth 2.1 plumbing right and then trips at the registration endpoint. The discovery chain works end-to-end. PKCE is S256-only and behaviorally enforced. CIMD is advertised. The /register endpoint accepts redirect URIs the spec says authorization servers should reject: plain HTTP on a confidential client, and a redirect_uri whose host does not match the registered client_uri . Both registrations returned 201 with live credentials. This is the second in a weekly series auditing remote MCP servers against the OAuth 2.1 authorization requirements of the Model Context Protocol specification. Audit 01 looked at GitHub, where the gap was structural: GitHub's OAuth infrastructure predates the spec by a decade and inherits its pre-2025 constraints. Linear is a different shape. The infrastructure is recent and the gaps are implementation-level rather than structural. All findings link to raw HTTP evidence committed in evidence/ . Methodology is documented in METHODOLOGY.md . Discovery chain. An unauthenticated POST to https://mcp.linear.app/mcp returns HTTP/1.1 401 with a well-formed WWW-Authenticate: Bearer header that includes a resource_metadata link (RFC 9728 §5.1): HTTP/1.1 401 Unauthorized WWW-Authenticate: Bearer realm="OAuth", resource_metadata="https://mcp.linear.app/.well-known/oauth-protected-resource", error="invalid_token", error_description="Missing or invalid access token" The Protected Resource Metadata document at /.well-known/oauth-protected-resource resolves with 200 and points back at mcp.linear.app as the authorization server. The AS metadata document at /.well-known/oauth-authorization-server advertises authorization_endpoint , token_endpoint , registration_endpoint , and code_challenge_methods_supported: ["S256"] . A spec-aware client walks the chain without manual configuration. This is what the spec is asking for. PKCE is correctly advertised and enforced. code_challenge_methods_supported includes only S256 . No plain fallback. The authorization endpoint backs the advertisement with behavior: requests omitting code_challenge get HTTP 400, and requests with code_challenge_method=plain get HTTP 400. CIMD support is advertised. AS metadata sets client_id_metadata_document_supported: true . The 2025-11-25 spec revision marks Client ID Metadata Documents as SHOULD-support and DCR as MAY-support. Linear has the metadata flag in place for clients that adopt CIMD; whether the server-side behavior matches the advertisement was not tested in this audit. Four findings. Ordered by significance, not severity. DCR accepts a plain HTTP redirect URI for a confidential client. The probe registered a confidential client (token_endpoint_auth_method: "client_secret_basic" ) with an http:// redirect: POST /register HTTP/1.1 Host: mcp.linear.app Content-Type: application/json { "client_name": "korrel-cli audit probe", "client_uri": "https://korrel.dev", "redirect_uris": ["http://korrel.dev/callback"], "grant_types": ["authorization_code"], "response_types": ["code"], "token_endpoint_auth_method": "client_secret_basic" } The endpoint returned 201 with a client_secret in the body. OAuth 2.1 §1.5 mandates that all OAuth protocol URLs (URLs exposed by the AS, RS, and Client) use the https scheme except for loopback redirect URIs. A non-loopback http:// redirect is a direct MUST violation. RFC 7591 §5 layers on top: the AS MUST take appropriate steps to mitigate impersonation risk by looking at the entire registration request. Linear took none. A confidential client flowing the authorization code through http:// exposes the code on the wire to anyone in network position between the user and the redirect target. The threat model expands beyond compromise of Linear: a coffee-shop network or a hostile transit hop is enough. The probe issued a single POST. No other interaction with the registration endpoint was required to obtain a usable client_id and client_secret paired to an HTTP callback. DCR accepts a redirect_uri host that does not match client_uri . The probe registered a public client whose client_uri and redirect_uris resolve to different hosts: POST /register HTTP/1.1 Host: mcp.linear.app Content-Type: application/json { "client_name": "korrel-cli audit probe", "client_uri": "https://korrel.dev", "redirect_uris": ["https://other-host.example.com/callback"], "grant_types": ["authorization_code"], "response_types": ["code"], "token_endpoint_auth_method": "none" } 201, again. RFC 7591 §5 mandates that the AS take appropriate steps to mitigate impersonation risk by inspecting the entire registration request, and gives logo_uri / redirect_uris domain mismatch as an illustrative warning trigger. The same principle extends to client_uri / redirect_uris mismatch: the client tells the AS what host it lives on through client_uri , then asks the AS to redirect to a different host. Linear performs no host comparison of either kind. The practical risk is registration-time phishing. A third party can register a Linear MCP client whose name and client_uri look like a legitimate vendor, with redirect_uris pointed at infrastructure they control. Any user who gets steered to the resulting authorization request and approves it has handed the attacker an authorization code. PKCE protects against later token exchange by an unrelated party; PKCE does not undo a redirect to attacker-controlled hosts. This finding is softer than the previous one. Both rest on §5's MUST about metadata scrutiny. The difference is specificity: §5 names logo_uri / redirect_uris host mismatch as the illustrative example, and extending the principle to client_uri is an interpretation rather than a direct rule. The finding is also independently exploitable: a public-client registration with a host-mismatched redirect is enough to mount the phishing scenario above without needing the HTTP-redirect path. Bearer challenge includes an error code on an unauthenticated request. The 401 response to an unauthenticated POST carries error="invalid_token" and error_description : WWW-Authenticate: Bearer realm="OAuth", resource_metadata="...", error="invalid_token", error_description="Missing or invalid access token" RFC 6750 §3.1 says the resource server SHOULD NOT include an error code or other error information when the request lacks any authentication. The probe sent no Authorization header. Linear's response carries an error code and description anyway. Practical impact is small; the information leak is whether the server distinguishes between "no token" and "bad token", which an active probe can determine anyway. Flagged because it's cheap to fix. GitHub's MCP server has the same shape, on infrastructure a decade older. PRM omits the recommended scopes_supported field. The Protected Resource Metadata document does not advertise scopes_supported . RFC 9728 §2 marks this field as RECOMMENDED. Without it, clients have to rely on out-of-band documentation or trial-and-error to determine acceptable scope values. Listed for completeness, not load-bearing. Linear's remote MCP server is current with the 2025-11-25 spec. The discovery chain works, PKCE is S256-only and enforced behaviorally, CIMD is advertised. The implementation reads as if someone walked through the MCP spec top-to-bottom and got the headlines right. The DCR endpoint is where that walk-through ends. /register accepts what's posted to it and returns 201 without applying the validation rules the relevant specs call for. Both DCR findings fall through the same gap: there is no policy on redirect URI shape between "the client posted these strings" and "the client got registered." This is not a structural problem. The OAuth infrastructure here is recent and operated by a team that ships software for a living. The fixes are small. Reject http:// redirect URIs for non-loopback confidential clients, the way OAuth 2.1 §1.5 says to. Compare redirect_uri host to client_uri host, the way RFC 7591 §5 hints at. Both checks are ten lines of code apiece. The shape of the gap matters more than its size. A DCR endpoint that registers attacker-shaped clients on demand is the bootstrap of the phishing flows the spec is trying to design out. Any MCP server that exposes /register without validation logic has the same exposure Linear has here. The hygiene at those endpoints is load-bearing in a way the spec does not yet treat as load-bearing. - 2026-04-23: Findings 1, 3, and 4 disclosed to Linear's security contact. - 2026-04-25: Follow-up disclosing finding 2 (host-mismatched redirect URI). - 2026-04-28: Reply from Jamie at Linear acknowledging receipt and stating Linear is investigating. - 2026-05-04: Final notice email sent to Linear ahead of publication. - 2026-05-04: Publication. Next audit: Supabase's remote MCP server. Different infrastructure shape, similar DCR posture on host-mismatched redirect URIs, but HTTP redirects on confidential clients are correctly rejected. That makes the HTTP-redirect finding here specific to Linear, not a property of every MCP server's DCR endpoint. More on that Monday 11 May. Findings captured using korrel-cli probes 1-5. Replication is welcome; finding-by-finding mirroring is not. If you maintain a remote MCP server and want a pre-publication review, DM @issazangana on X or email [email protected] . I propose a publication date at time of outreach and move it if you ask.

Genesis Park 편집팀이 AI를 활용하여 작성한 분석입니다. 원문은 출처 링크를 통해 확인할 수 있습니다.

공유

관련 저널 읽기

전체 보기 →