Skip to content

Blind SSRF in `/home/testdiscord` endpoint

Moderate
medariox published GHSA-3hph-6586-qv9g Dec 18, 2023

Package

medusa/notifiers/discord.py

Affected versions

<1.0.19

Patched versions

1.0.19

Description

GitHub Security Lab (GHSL) Vulnerability Report, Medusa: GHSL-2023-202

The GitHub Security Lab team has identified potential security vulnerabilities in Medusa.

We are committed to working with you to help resolve these issues. In this report you will find everything you need to effectively coordinate a resolution of these issues with the GHSL team.

If at any point you have concerns or questions about this process, please do not hesitate to reach out to us at securitylab@github.com (please include GHSL-2023-202 as a reference).

If you are NOT the correct point of contact for this report, please let us know!

Summary

Medusa contains an unauthenticated blind server-side request forgery (SSRF).

Project

Medusa

Tested Version

1.0.17

Details

Issue 2: Blind SSRF in /home/testdiscord endpoint (GHSL-2023-202)

The testDiscord request handler in medusa/server/web/home/handler.py does not validate the user-controlled discord_webhook variable and passes it to the notifiers.discord_notifier.test_notify method, then _notify_discord and finally _send_discord_msg method, which sends a POST request to the user-controlled URL on line 64 in /medusa/notifiers/discord.py, which leads to a blind server-side request forgery.

def _send_discord_msg(self, title, msg, webhook=None, tts=None, override_avatar=None):
    """Collect the parameters and send the message to the discord webhook."""
    webhook = app.DISCORD_WEBHOOK if webhook is None else webhook
    tts = app.DISCORD_TTS if tts is None else tts
    override_avatar = app.DISCORD_OVERRIDE_AVATAR if override_avatar is None else override_avatar

    log.debug('Discord in use with API webhook: {webhook}', {'webhook': webhook})

    headers = {'Content-Type': 'application/json'}
    payload = {
        'username': app.DISCORD_NAME,
        'content': '',
        'tts': tts,
        'embeds': [{
            'type': 'rich',
            'title': '',
            'description': msg,
            'footer': {
                'text': title
            }
        }]
    }

    if override_avatar:
        payload['avatar_url'] = app.DISCORD_AVATAR_URL

    success = False
    try:
        r = requests.post(webhook, json=payload, headers=headers)
        r.raise_for_status()
        message = 'Discord message sent successfully.'
        success = True
    except RequestException as error:
        message = 'Unknown IO error: %s' % error
        if hasattr(error, 'response') and error.response is not None:
            error_message = {
                400: 'Missing parameter(s). Double check your settings or if the channel/user exists.',
                401: 'Authentication failed, check your webhook url',
                420: 'Too many messages.',
                500: 'Server error. Please retry in a few moments.',
            }
            if error.response.status_code in error_message:
                message = error_message.get(error.response.status_code)
            else:
                message = http_status_code.get(error.response.status_code, message)
    except Exception as error:
        message = 'Error while sending Discord message: {0} '.format(error)
    finally:
        log.info(message)
    return success, message

This issue was found with the CodeQL query Full server-side request forgery.

Impact

This issue allows for crafting POST requests on behalf of the Medusa server.

Proof of Concept

  1. Start a simple python web server, f.ex. this one. This code will start a web server on http://127.0.0.1:9000
  2. Start Medusa. We assume that it is running on http://localhost:8081.
  3. Send the following request:
curl -X GET 'http://localhost:8081/home/testDiscord?discord_webhook=http://127.0.0.1:9000/'

Based on the response, we can infer if the request succeeded (returned HTTP status 2xx). If it did, we will receive a response:
Discord notification succeeded. Check your Discord channels to make sure it worked

If the request resulted in an error, it will raise an exception and we will receive an error message depending on the HTTP status.

Remediation

If possible, use an allowlist with allowed domains to limit the possibility to send POST requests on behalf of Medusa.

GitHub Security Advisories

We recommend you create a private GitHub Security Advisory for these findings. This also allows you to invite the GHSL team to collaborate and further discuss these findings in private before they are published.

Credit

These issues were discovered and reported by GHSL team member @sylwia-budzynska (Sylwia Budzynska).

Contact

You can contact the GHSL team at securitylab@github.com, please include a reference to GHSL-2023-201 or GHSL-2023-202 in any communication regarding these issues.

Disclosure Policy

This report is subject to a 90-day disclosure deadline, as described in more detail in our coordinated disclosure policy.

Severity

Moderate
5.3
/ 10

CVSS base metrics

Attack vector
Network
Attack complexity
Low
Privileges required
None
User interaction
None
Scope
Unchanged
Confidentiality
Low
Integrity
None
Availability
None
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N

CVE ID

CVE-2023-50258

Weaknesses

Credits