Skip to content

Build1 publisher3 min readPublished

QRFLOW.codes traced its MCP OAuth exposure to a consent screen that trusted registrant-chosen names

QRFLOW.codes' developer refused both fixes a security report proposed for open OAuth client registration, saying either would lock Claude and ChatGPT out. The exposure turned out to be a consent screen showing attacker-chosen app names, now handled by trusting redirect hosts.

The Engineer · Build desk

Illustration accompanying QRFLOW.codes traced its MCP OAuth exposure to a consent screen that trusted registrant-chosen names

What happened

  • A security report told QRFLOW.codes to put its open OAuth registration endpoint behind an Initial Access Token or manual review, and to enforce a redirect_uri allowlist.
  • The developer refused both, saying every real client, including Claude, Glama, Oasis and Rayrun, had registered through the open endpoint without credentials.
  • The flaw the developer did find was on the consent screen, where a registrant's self-chosen client_name appeared as though the service had verified it.
  • Apps are now recognized by redirect host against a hardcoded list, and any app off that list triggers a warning banner naming its destination.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

  • constraint Putting a credential or a reviewer in front of registration fails MCP clients, since Claude or ChatGPT must register with an unfamiliar server in a few hundred milliseconds with no one there to approve it.
  • exposure Any MCP server that displays client_name as fact lets a stranger present their own app's access request on that server's real domain and certificate, under the server's name.
  • cost Each new MCP client missing from a hardcoded host list meets the impostor banner until someone ships a deploy, so keeping the list current becomes release work.
  • decision A review of an MCP server's OAuth has to test redirect matching at authorize and token time, plus PKCE enforcement, because restricting who may register is not an option.

The developer wrote that the report's model of the risk, "open registration means open redirects," "conflated two different things" [10]. Registration at POST /api/oauth/register accepts any HTTPS redirect from anyone [3]. Authorization is where that redirect gets enforced. The server refuses any redirect a client did not register for itself. It checks on the authorize call and again at the token exchange [8]. "Registering a client with your own redirect gets you a client that redirects to you. It does not get you anyone else's authorization code," the developer wrote [9].

The second control is one line of the published code. `if (client.dynamic && (!codeChallenge || method !== "S256"))` rejects a dynamically registered client that skips PKCE or asks for the plain method [11]. "An intercepted authorization code is worthless on its own," the developer wrote [12]. Open Dynamic Client Registration is one of the two modes RFC 7591 defines, and the Model Context Protocol relies on it [4]. A redirect allowlist cannot sit on top of that. "You cannot allowlist redirect addresses for applications that do not exist yet," the developer wrote [7].

The weak point was the consent page. It dropped the registrant's free-text client_name into "Connect {client_name} to your QRFLOW.codes account?", set in the brand color, with the real destination in small print [13]. Anyone could have registered "QRFLOW Official Support", aimed the redirect at their own server, and sent people a link to a consent screen on the real domain, behind the real TLS certificate [14]. Every component in that flow behaves exactly as specified [14]. It is the least comforting sentence in the post. "Open registration means the name field is attacker-controlled. If you render it, you are part of the attack," the developer wrote [15].

The post lists three changes, and none of them touches registration [16]. In the first, the redirect host decides whether an app is recognized, and the name is only displayed [16]. The reasoning is that an attacker has to actually receive the callback at the host, while the name is entirely theirs to choose [18]. The set, KNOWN_CLIENT_HOSTS, holds nine entries, including claude.ai, chatgpt.com, cursor.sh and www.canva.com [17][1]. I think hardcoding it is the right tradeoff for a list this short. It changes a few times a year, and the developer argued that a control editable at runtime is a bigger target than one that needs a deploy [19].

So the fix is an allowlist after all, applied to what the consent screen trusts. Registration stays open. The second change covers everything off the list. The amber banner used to appear only for loopback clients, and an unknown app at a remote address got no warning at all. Now any unrecognized app gets the banner, with the destination host stated inside it [20]. Legitimate clients pay for this too. Oasis and Rayrun are two of the four clients the developer says arrived through open registration, and neither has an entry in the published list [6][2]. Unless their callbacks land on a listed host, their users now see the same warning an impostor would get.

The evidence is one developer's account of one service. It shows where this server's exposure sat and how it was closed with registration left open. It does not show how other MCP servers render client_name.

What to watch

  • Whether Oasis, Rayrun or other MCP clients get added to KNOWN_CLIENT_HOSTS, or stay behind the unrecognized-app banner.
  • Reports from other MCP server operators of consent screens that render client_name as trusted text.
  • Any MCP or RFC 7591 guidance on how authorization servers should display self-asserted client metadata to users.
Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories