Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork36.2k
SSL validation for outgoing requests in core and used libs not correct
Package
Affected versions
Patched versions
Description
Summary
Problem: Potential man-in-the-middle attacks due to missing SSL certificate verification in the project codebase and used third-party libraries.
Details
In the past,aiohttp-session/request had the parameterverify_ssl to control SSL certificate verification. This was a boolean value. Inaiohttp 3.0, this parameter was deprecated in favor of thessl parameter. Only whenssl is set toNone or provided with a correct configured SSL context the standard SSL certificate verification will happen.
When migrating integrations in Home Assistant and libraries used by Home Assistant, in some cases theverify_ssl parameter value was just moved to the newssl parameter. This resulted in these integrations and 3rd party libraries usingrequest.ssl = True, which unintentionally turned off SSL certificate verification and opened up a man-in-the-middle attack vector.
Example:
| ssl=verify_ssl, |
When you scan the libraries used by the integrations in Home Assistant, you will find more issues like this.
The general handling in Home Assistant looks good, ashomeassistant.helpers.aoihttp_client._async_get_connector handles it correctly.
PoC
- Check that expired.badssl.com:443 gives an SSL error in when connecting with curl or browser.
- Add the integration adguard with the setting
host=expired.badssl.com,port=443,use-ssl=true,verify-ssl=true. - Check the logs - you get a HTTP 403 response.
Expected behavior:
- The integration log shows an
ssl.SSLCertVerificationError.
The following code shows the problem withssl=True. No exception is raised whenssl=True (Python 3.11.6).
import asynciofrom ssl import SSLCertVerificationErrorimport aiohttpBAD_URL = "https://expired.badssl.com/"async def run_request(verify_ssl, result_placeholder: str): async with aiohttp.ClientSession() as session: exception_fired: bool = False try: await session.request("OPTIONS", BAD_URL, ssl=verify_ssl) except SSLCertVerificationError: exception_fired = True except Exception as error: print(error) else: exception_fired = False print(result_placeholder.format(exception_result=exception_fired))# Case 1: ssl=False --> expected result: No exceptionasyncio.run(run_request(False, "Test case 1: expected result: False - result: {exception_result}"))# Case 2: ssl=None --> expected result: Exceptionasyncio.run(run_request(None, "Test case 2: expected result: True - result: {exception_result}"))# Case 3: ssl=True --> expected result: No Exceptionasyncio.run(run_request(True, "Test case 3: expected result: False - result: {exception_result}"))Severity
CVSS v3 base metrics
CVE ID
Weaknesses
Credits
ReneNulschDEReporter