Skip to content

Instantly share code, notes, and snippets.

@mala
Last active August 24, 2023 14:04
Show Gist options
  • Save mala/c2ef4b49e7d71490de22bd8e9c3f962f to your computer and use it in GitHub Desktop.
Save mala/c2ef4b49e7d71490de22bd8e9c3f962f to your computer and use it in GitHub Desktop.
Disclosure of a vulnerability that allows the theft of visitors' email addresses using Medium's custom domain feature / Mediumの独自ドメインプランを使って訪問者のメールアドレスが窃取できる脆弱性の開示

Disclosure of a vulnerability that allows the theft of visitors' email addresses using Medium's custom domain feature

Author: mala

Introduction

  • This article describes a vulnerability in a web service called Medium that allows you to steal visitors' e-mail addresses by using custom domain plan of Medium.
  • This is done as my personal activity and is not related to my organization.
  • I'm not a zero-day guy and this is simply the result of a failure of coordinated disclosure.

Important

  • This vulnerability has not been fixed as of the time this article is published (2023-07-13).
  • I have notified Medium with sufficient time for disclosure, but have not received a response, and a reasonable period of time that would be required for a fix has passed, and I believe it is in the greater public interest to disclose this information.
  • The purpose is to alert the public and to discuss this type of issue, not to suggest abuse.

Status

  • 2023-07-22 New applications for custom domains have been suspended (also mentioned in email reply from Medium)
  • 2023-08-17 I confirm that the local part of the email address is masked except for the first two characters

Although Medium has implemented some mitigations, the issue has not been fully fixed and Medium's logged-in users are still at risk.

The email address is now masked, but the auto-login for the custom domain remains the same, and the visitor's Medium account can still be identified. As such, it is still possible to identify a visitor if the owner of a custom domain that has already been set up is malicious. Also, the domain part and the first two characters of the email address are not masked, so the full email address may be inferred or the mask may not work. eg: [email protected]

How to reproduce

  • Pay $5/month to Medium and subscribe to Medium Membership.
  • Set up your own domain as a custom domain e.g.: Set medium.example.com as a custom domain on the Medium side, and specify the IP address of the Medium server in the A record in the DNS settings.
  • Confirm that you can connect to your blog with the custom domain.
  • Change the A record of medium.example.com to the IP address of your own server and set up a proxy server.
  • The Proxy server will keep the request header from the client and the Host header of medium.example.com, and specify the IP address of the Medium server as upstream to relay the request.
  • The Proxy server can steal the response content received by the visitor.
  • When a visitor logs into medium.example.com, the response of the graphql endpoint includes the visitor's e-mail address and so on.

Self-protection measures on the user side

  • Log out of Medium.
  • Since it is not known in advance which sites are using Medium, and logging in to Medium may automatically log you in to custom domains, you cannot protect yourself unless you log out of Medium beforehand.
  • Complain to Medium

Timeline (Timezone: GMT+9)

  • 2022-12-24 Reported to [email protected] that a custom domain's graphql endpoint is returning emails, etc.
  • 2022-12-30 Medium replies that they are not accepting any potential problems and that the DNS servers are under Medium's control.
  • 2022-12-31 mala to Medium: reply that it is not a potential problem but a low-cost problem to collect emails from medium users and that the DNS servers can be changed by the domain owner at any time.
  • 2023-01-02 mala to Medium: create and send demo and video
  • 2023-01-17 mala to Medium: urged to reply. Medium replied saying they would let me know if they had any additional information.
  • 2023-05-12 mala to Medium: informing them that if there are no effective fixes, mitigations, or user clarifications within a month, I will disclose them.
  • 2023-06-12 Due date but no reply from Medium.
  • I was busy.
  • 2023-07-13 No reply from Medium, confirms that graphql endpoint on own domain continues to return responses including visitor's email address, discloses vulnerability
  • 2023-07-18 Medium to mala: Received a notification that it was being treated as an invalid bug and they asked if it was possible to delete Tweets and this gist.
  • 2023-07-19 Medium to mala: They says that test and fix will be completed in few days.
  • 2023-07-19 I temporarily unpublished this gist (assuming it will be resolved in a few days)
  • 2023-07-22 Medium to mala: They says that they has stopped accepting new custom domain and some solution will be rolled out soon.
  • 2023-07-27 mala to Medium: I asked when "soon" and "few days"
  • 2023-07-28 Medium to mala: They says investigation and fix in progress, will be deployed when ready
  • 2023-08-15 I got $1500 from Medium
  • 2023-08-17 I confirm that the local part of the email address is masked except for the first two characters. I published this gist again

Mediumの独自ドメインプランを使って訪問者のメールアドレスが窃取できる脆弱性の開示

文責: mala

前置き

  • MediumというWebサービスで独自ドメインプランを利用することで訪問者のメールアドレスを窃取することができる脆弱性について解説します。
  • 個人の活動として行っており所属組織とは関係ない。
  • これはゼロデイではなく調整に失敗した結果です。

重要

  • この脆弱性は、この記事を公開する時点(2023-07-13)で修正されていません。
  • 開示についてMedium社に十分な期限を設けて通知をしましたが返事がなく、修正に必要であろう妥当な期間も経過しており、開示することがより公共の利益にかなうと判断するものです。
  • 注意喚起や、この種の問題についての議論を目的としており、悪用を教唆するものではありません。

修正状況

  • 2023-07-22 カスタムドメインの新規申し込みが停止されている (Mediumからのメール返信でも言及あり)
  • 2023-08-17 メールアドレスのローカルパート部分が先頭2文字を除いてマスクされるようになっているのを確認する

Mediumはいくつかの緩和策を実施していますが、問題は完全に修正されておらず、Mediumのログインユーザーには引き続きリスクがあります。

メールアドレスがマスクされるようになりましたが、custom domainに対して自動ログインする部分は変わらず、訪問ユーザーのMediumアカウントを特定することはできます。 そのため、既にセットアップ済みの custom domainのオーナーに悪意がある場合、訪問者を特定することが引き続き可能です。 また、メールアドレスのドメイン部分と先頭2文字はマスクされないため、フルのメールアドレスが推定されたり、マスクが機能しないことがあります。 eg: [email protected]

再現手順

  1. Mediumに月5ドルのお金を払ってMedium Membershipに加入する
  2. 自分の保有するドメインをcustom domainとして設定する 例: Medium側にcustom domainとして medium.example.com を設定し、DNSの設定で Aレコードに MediumのサーバーのIPアドレスを指定する
  3. custom domainで自分のブログに正常に接続できるのを確認する
  4. medium.example.com のAレコードを自前のサーバーのIPアドレスに変更してProxyサーバーを立てる。let's encryptなどで自前での証明書を取得する。
  5. Proxyサーバーはクライアントからのリクエストヘッダや medium.example.com のHostヘッダを維持したまま、MediumのサーバーのIPアドレスをupstreamとして指定して中継する。
  6. Proxyサーバーは訪問者が受け取る応答内容を窃取することができる。
  7. 訪問者が medium.example.com にログイン状態になると、graphqlエンドポイントの応答には訪問者のメールアドレス等も含まれている。

ユーザー側での自衛策

  • Mediumからログアウトしておく。
  • どのサイトがMediumを使っているのかは事前には分からないし、Mediumにログインしているとcustom domainに対しても自動でログインすることもあるため、予めMediumからログアウトしないと自衛することができない。
  • Medium社に文句を言う

タイムライン (Timezone: GMT+9)

  • 2022-12-24 [email protected] 宛に報告。custom domainのgraphqlエンドポイントでEmailなどを返しているといった内容。
  • 2022-12-30 Mediumより返信 潜在的な問題は受け付けてないとかDNSサーバーはMediumの制御下にあるといった返事が来る
  • 2022-12-31 malaからMedium: 潜在的な問題ではなく低コストでmediumユーザーのemailを収集できる問題であり、DNSサーバーはドメイン所有者がいつでも変更できると返信
  • 2023-01-02 malaからMedium: デモと動画を作成して送りつける。
  • 2023-01-17 malaからMedium: 返信を催促。その後、Mediumから用意したデモに対してアクセスがあったことも確認。Mediumからは追加情報があれば知らせると返信あり。
  • 2023-05-12 malaからMedium: 一ヶ月以内に実効性のある修正、緩和策、またはユーザーへの説明がない場合は開示予定であると伝える。
  • 2023-06-12 期日になるが返事がない
  • 忙しかった
  • 2023-07-13 返信がないこと、独自ドメインでのgraphqlエンドポイントで引き続き訪問者のメールアドレスも含むレスポンスを返していることを確認、脆弱性の開示
  • 2023-07-18 Mediumからmala: 連絡が再開される。無効なバグとして取り扱われていたことの連絡と、Tweetとgistを削除できないかという打診を受ける
  • 2023-07-19 Mediumからmala: few daysのうちにテストと修正が完了すると連絡を受ける。
  • 2023-07-19 (few daysで解決する前提で) このgistを一時的に非公開にする
  • 2023-07-22 Mediumからmala: カスタムドメイン機能の新規申し込みを停止したことと、何らかの解決を近いうち(soon)に展開予定と連絡を受ける
  • 2023-07-27 malaからMedium: soonとか few daysって具体的にいつだよと質問
  • 2023-07-28 Mediumからmala: 調査と修正は進行中であり、準備ができたら展開される
  • 2023-08-15 Mediumから $1500 が届く
  • 2023-08-17 メールアドレスのローカルパート部分が先頭2文字を除いてマスクされるようになっているのを確認する。gistを再度公開する

Hi, I'm a Japanese web engineer.

I found an authentication flaw in medium's custom domain feature a few hours ago.

my medium account is https://medium.com/@bulkneets I'm sorry, but I haven't used it much, so I'm not familiar with medium's features. If there is any mistake in my understanding, please point it out.

Vulnerability Summary

Authors using medium's custom domain feature can read users' private information. The ViewerQuery operation for graphql contains the viewer's email address.

The graphql response contains an email address registered for medium. I didn't intend to make my email address public. Also, email is not a visible item in other users' public profile information.

How to reproduce

When you visit a medium that uses a custom domain, a request is sent to the graphql endpoint like below.

https://custom-domain-for-medium.example.com/_/graphql

payload like this

[{"operationName":"ViewerQuery","variables":{},"query":"query
ViewerQuery {\n viewer {\n __typename\n id\n username\n name\n
imageId\n mediumMemberAt\n hasPastMemberships\n
isPartnerProgramEnrolled\n email\n unverifiedEmail\n createdAt\n
isAuroraVisible\n isEligibleToViewNewResponses\n
isMembershipTrialEligible\n isSuspended\n
styleEditorOnboardingVersionSeen\n
allowEmailAddressSharingEditorWriter\n hasSubdomain\n
dismissableFlags\n hasGroupGiftingEnabled\n twitterScreenName\n
geolocation {\n country\n __typename\n }\n atsQualifiedAt\n
postSubscribeMembershipUpsellShownAt\n hightowerTermsAcceptedAt\n
isEligibleToImportEmails\n }\n}\n"}]

response like this (my information)

[
{
"data": {
"viewer": {
"__typename": "User",
"id": "cc22fbe5f640",
"username": "bulkneets",
"name": "mala",
"imageId": "0*IQerQa9DDSVYufwh.png",
"mediumMemberAt": 0,
"hasPastMemberships": false,
"isPartnerProgramEnrolled": false,
"email": "■■■■■■@ma.la",
"unverifiedEmail": "",
"createdAt": 1475845601586,
"isAuroraVisible": true,
"isEligibleToViewNewResponses": true,
"isMembershipTrialEligible": true,
"isSuspended": false,
"styleEditorOnboardingVersionSeen": 0,
"allowEmailAddressSharingEditorWriter": false,
"hasSubdomain": false,
"dismissableFlags": [
"FIRST_USE_GLOBAL_NAV_TOOLTIP"
],
"hasGroupGiftingEnabled": false,
"twitterScreenName": "bulkneets",
"geolocation": {
"country": "JP",
"__typename": "Geolocation"
},
"atsQualifiedAt": 0,
"postSubscribeMembershipUpsellShownAt": 0,
"hightowerTermsAcceptedAt": null,
"isEligibleToImportEmails": false
}
}
}
]

If you use a custom domain on medium, it will usually be processed by the medium server, including the graphql endpoint.

However, the domain owner can change the A record at any time, so A medium author using a custom domain can steal the viewer's valid authentication cookie.

Also, users of custom domains may be able to read cookies through the proxy. For example, as far as I have checked, these domains seem to be hosting medium via cloudflare.

... snip ...

If the author of the custom domain relays the request on the server prepared by himself and sets it to display medium, the author can collect the viewer's profile and email address without being noticed by the viewer.

Solutions

  • Sessions issued for custom domains should not be able to see user's private information.
  • Even if you restrict the acquisition of private information, if you do not completely remove the common header, the username of the viewer may still be collected from the author using the custom domain.
  • Auto-login functionality for custom domains should have enough warnings and options to disable.
  • Simply, it would be safer to disable auto-login for custom domains by default and only log in by explicit user action.

Reference information

In 2020, I reported a similar vulnerability to a medium-like blog service provided in Japan, and recently disclosed the report.

I received a comment that medium also has a similar custom domain function, so I investigated medium. This issue may be easy to discover or exploit.

2022-12-31 mala to Medium

Hi,
This isn't a potential problem, it's a real bug that allows you to
collect medium user emails with low cost.

I have confirmed that the graphql endpoint is valid on the custom domain.
and I have already included the necessary information enough for
medium team to verify in the first email.
Please check the Fetch/XHR response when displaying the custom domain
article while logged in.

I'll attach screenshots to this mail.

you said "DNS servers are under Medium's control" but
DNS server is not maintained by medium and is configured by each DNS
provider as explained the manual you created.
there are configuration examples using GoDaddy, Namecheap, Google Domains
- https://help.medium.com/hc/en-us/articles/115003053487-Setting-up-a-custom-domain-for-your-profile-or-publication

Therefore medium user who has custom domains can change the A record
anytime. (it means can steal authentication cookie for custom domain.)
I don't want to pay money just for verification because I'm worried
about medium's security, but I'll make a demo if necessary.
Since it is a holiday, I may be late in contacting you, but I will
contact you again.

Regards,

2023-05-12 mala to Medium

Hi,

It's been a long time since the report, is there any progress on this issue?
I have confirmed that Medium still includes the email address in
graphql responses on custom domain.

Because the fix is too slow and it's not just a problem with Medium,
I plan to disclose this issue for the public interest, security alert,
and community discussion.
If by June 12th no progress has been made with an effective fix,
mitigation, or explanation to users, I will be disclosing this issue.
If you have any plans to fix it, please let me know and I will adjust
the disclosure schedule.

Thanks.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment