Skip to content

Hardcoded RSA private key enables user password decryption in PyMammotion #7307

@AidanDalyAus

Description

@AidanDalyAus

Summary

PyMammotion (200 stars, 41 forks, backend for the Mammotion HA integration with 417 stars) contains a hardcoded 1024-bit RSA private key that is used to encrypt user login credentials. Since the key is shared across all installations, any attacker who intercepts a Mammotion login request can decrypt the user's actual username and password.

The library also ships with 4 hardcoded API/OAuth secrets and disables SSL certificate verification.

Mammotion mowers have cameras, GPS tracking, and accounts store credit card information per their privacy policy.

Finding 1: Hardcoded RSA Private Key Enables Password Decryption (CWE-321, High)

pymammotion/http/encryption.py line 15 contains a hardcoded 1024-bit RSA private key (PKCS#8 DER encoded, 635 bytes). This key is part of a keypair used during login:

pymammotion/http/http.py lines 527-536:

"Encrypt-Key": self.encryption_utils.encrypt_by_public_key(),  # RSA-encrypted AES key
"username": self.encryption_utils.encryption_by_aes(account),   # AES-encrypted username
"password": self.encryption_utils.encryption_by_aes(password),  # AES-encrypted password
"client_id": self.encryption_utils.encryption_by_aes(MAMMOTION_CLIENT_ID),
"client_secret": self.encryption_utils.encryption_by_aes(MAMMOTION_CLIENT_SECRET),
"grant_type": self.encryption_utils.encryption_by_aes("password"),


The login flow works like this:

An AES key is generated and encrypted with the RSA public keysent as Encrypt-Key header
Username and password are AES-encrypted with that key
Server decrypts the AES key using its copy of the private key, then decrypts the credentials
Since the RSA private key is hardcoded in the open-source library, any attacker can:

Intercept a login request (the library also disables SSL verificationFinding 3)
Decrypt the Encrypt-Key header using the hardcoded private key to recover the AES key
Decrypt the username and password fields using the recovered AES key
Access the victim's Mammotion accountcamera feeds, GPS location, mower control, billing data
Finding 2: Hardcoded OAuth and API Secrets (CWE-798, High)
pymammotion/const.py lines 3-13:

APP_KEY = "34231230"
APP_SECRET = "1ba85698bb10e19c6437413b61ba3445"
MAMMOTION_CLIENT_ID = "MADKALUBAS"
MAMMOTION_CLIENT_SECRET = "GshzGRZJjuMUgd2sYHM7"
MAMMOTION_OUATH2_CLIENT_ID = "GxebgSt8si6pKqR"
MAMMOTION_OUATH2_CLIENT_SECRET = "JP0508SRJFa0A90ADpzLINDBxMa4Vj"

Six hardcoded secrets enabling Aliyun IoT authentication and Mammotion OAuth token exchange.


Finding 3: SSL Verification Disabled (CWE-295, Medium)
pymammotion/aliyun/tea/core.py line 130:

verify = False

TLS certificate validation is unconditionally disabled in one code path. Combined with Finding 1, this enables network-level interception of login requests without certificate warnings.

Finding 4: Weak PRNG for Security Values (CWE-330, Low)
pymammotion/aliyun/cloud_gateway.py line 105:

return "".join(random.choice(characters) for _ in range(length))

Python's random module (not secrets) used for generating security-relevant strings.

Impact
Mammotion mowers include cameras, GPS, and property mapping. Per Mammotion's privacy policy, accounts also store credit card information, shipping addresses, and phone numbers. With decrypted credentials an attacker gains access to:

Camera feeds (real-time yard surveillance)
GPS location and property boundary maps
Remote mower control (start, stop, change patterns)
Account PII (email, address, phone)
Billing data (credit card information per privacy policy)
Password reuse against other services
Fix PR
https://github.com/mikey0000/PyMammotion/pull/118

Affected code
Private key: https://github.com/mikey0000/PyMammotion/blob/main/pymammotion/http/encryption.py#L15
Password encryption: https://github.com/mikey0000/PyMammotion/blob/main/pymammotion/http/http.py#L527
Secrets: https://github.com/mikey0000/PyMammotion/blob/main/pymammotion/const.py#L3
SSL disabled: https://github.com/mikey0000/PyMammotion/blob/main/pymammotion/aliyun/tea/core.py#L130

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions