CVE-2024-53305
Description
Insecure deserialization in Whoogle Search v0.9.0 allows arbitrary code execution via a crafted search query.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Insecure deserialization in Whoogle Search v0.9.0 allows arbitrary code execution via a crafted search query.
Vulnerability
Overview
The vulnerability resides in the /models/config.py file of Whoogle Search v0.9.0, where user-supplied preferences are deserialized using Python's pickle module [1][3]. Pickle deserialization is inherently unsafe because it can execute arbitrary Python code during the decoding process. The preferences parameter, passed via a search query, is base64-decoded, decompressed with brotli, and then unpickled without any validation [4]. This allows an attacker to craft a malicious pickle payload that, when processed, executes arbitrary commands on the server.
Exploitation
An attacker can exploit this by sending a GET request to the /search endpoint with a preferences parameter containing a specially crafted pickle payload. The payload is constructed using Python's pickle and brotli libraries, then URL-encoded [4]. No authentication is required, as the preferences are processed before any user session check. The exploit is trivial to execute and has been publicly demonstrated [4].
Impact
Successful exploitation results in remote code execution (RCE) with the privileges of the Whoogle process. An attacker can execute arbitrary system commands, potentially leading to full server compromise, data exfiltration, or further lateral movement within the network [2]. Given that Whoogle is often self-hosted and may have access to internal networks, the impact is significant.
Mitigation
The issue has been patched in commit 223f00c, which replaces pickle with json for serialization, eliminating the deserialization vulnerability [3]. Users are strongly advised to update to the latest version or apply the patch immediately. As of April 2025, Whoogle Search is in final release status and may no longer receive updates [1]; users should consider alternative solutions or implement strict input validation.
AI Insight generated on May 20, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
whoogle-searchPyPI | < 0.9.1 | 0.9.1 |
Affected products
2- Whoogle search/Whoogle searchdescription
Patches
1223f00c3c053Switch from `pickle`->`json` for config encoding
2 files changed · +28 −40
app/models/config.py+23 −27 modified@@ -3,13 +3,12 @@ from app.utils.misc import read_config_bool from flask import current_app import os -import re from base64 import urlsafe_b64encode, urlsafe_b64decode -import pickle from cryptography.fernet import Fernet import hashlib import brotli import logging +import json import cssutils from cssutils.css.cssstylesheet import CSSStyleSheet @@ -62,7 +61,7 @@ def __init__(self, **kwargs): self.anon_view = read_config_bool('WHOOGLE_CONFIG_ANON_VIEW') self.preferences_encrypted = read_config_bool('WHOOGLE_CONFIG_PREFERENCES_ENCRYPTED') self.preferences_key = os.getenv('WHOOGLE_CONFIG_PREFERENCES_KEY', '') - + self.accept_language = False self.safe_keys = [ @@ -144,7 +143,7 @@ def preferences(self) -> str: # if encryption key is not set will uncheck preferences encryption if self.preferences_encrypted: self.preferences_encrypted = bool(self.preferences_key) - + # add a tag for visibility if preferences token startswith 'e' it means # the token is encrypted, 'u' means the token is unencrypted and can be # used by other whoogle instances @@ -237,35 +236,32 @@ def _get_fernet_key(self, password: str) -> bytes: return key def _encode_preferences(self) -> str: - encoded_preferences = brotli.compress(pickle.dumps(self.get_attrs())) - if self.preferences_encrypted: - if self.preferences_key != '': - key = self._get_fernet_key(self.preferences_key) - encoded_preferences = Fernet(key).encrypt(encoded_preferences) - encoded_preferences = brotli.compress(encoded_preferences) + preferences_json = json.dumps(self.get_attrs()).encode() + compressed_preferences = brotli.compress(preferences_json) + + if self.preferences_encrypted and self.preferences_key: + key = self._get_fernet_key(self.preferences_key) + encrypted_preferences = Fernet(key).encrypt(compressed_preferences) + compressed_preferences = brotli.compress(encrypted_preferences) - return urlsafe_b64encode(encoded_preferences).decode() + return urlsafe_b64encode(compressed_preferences).decode() def _decode_preferences(self, preferences: str) -> dict: mode = preferences[0] preferences = preferences[1:] - if mode == 'e': # preferences are encrypted - try: + + try: + decoded_data = brotli.decompress(urlsafe_b64decode(preferences.encode() + b'==')) + + if mode == 'e' and self.preferences_key: + # preferences are encrypted key = self._get_fernet_key(self.preferences_key) + decrypted_data = Fernet(key).decrypt(decoded_data) + decoded_data = brotli.decompress(decrypted_data) - config = Fernet(key).decrypt( - brotli.decompress(urlsafe_b64decode( - preferences.encode() + b'==')) - ) - - config = pickle.loads(brotli.decompress(config)) - except Exception: - config = {} - elif mode == 'u': # preferences are not encrypted - config = pickle.loads( - brotli.decompress(urlsafe_b64decode( - preferences.encode() + b'==')) - ) - else: # preferences are incorrectly formatted + config = json.loads(decoded_data) + except Exception: config = {} + return config +
test/test_misc.py+5 −13 modified@@ -4,19 +4,11 @@ from app.models.endpoint import Endpoint from app.utils.session import generate_key, valid_user_session - -JAPAN_PREFS = 'uG-gGIJwHdqxl6DrS3mnu_511HlQcRpxYlG03Xs-' \ - + '_znXNiJWI9nLOkRLkiiFwIpeUYMTGfUF5-t9fP5DGmzDLEt04DCx703j3nPf' \ - + '29v_RWkU7gXw_44m2oAFIaKGmYlu4Z0bKyu9k5WXfL9Dy6YKKnpcR5CiaFsG' \ - + 'rccNRkAPYm-eYGAFUV8M59f8StsGd_M-gHKGS9fLok7EhwBWjHxBJ2Kv8hsT' \ - + '87zftP2gMJOevTdNnezw2Y5WOx-ZotgeheCW1BYCFcRqatlov21PHp22NGVG' \ - + '8ZuBNAFW0bE99WSdyT7dUIvzeWCLJpbdSsq-3FUUZkxbRdFYlGd8vY1UgVAp' \ - + 'OSie2uAmpgLFXygO-VfNBBZ68Q7gAap2QtzHCiKD5cFYwH3LPgVJ-DoZvJ6k' \ - + 'alt34TaYiJphgiqFKV4SCeVmLWTkr0SF3xakSR78yYJU_d41D2ng-TojA9XZ' \ - + 'uR2ZqjSvPKOWvjimu89YhFOgJxG1Po8Henj5h9OL9VXXvdvlJwBSAKw1E3FV' \ - + '7UHWiglMxPblfxqou1cYckMYkFeIMCD2SBtju68mBiQh2k328XRPTsQ_ocby' \ - + 'cgVKnleGperqbD6crRk3Z9xE5sVCjujn9JNVI-7mqOITMZ0kntq9uJ3R5n25' \ - + 'Vec0TJ0P19nEtvjY0nJIrIjtnBg==' +JAPAN_PREFS = 'uG7IBICwK7FgMJNpUawp2tKDb1Omuv_euy-cJHVZ' \ + + 'BSydthgwxRFIHxiVA8qUGavKaDXyiM5uNuPIjKbEAW-zB_vzNXWVaafFhW7k2' \ + + 'fO2_mS5e5eK41XXWwiViTz2VVmGWje0UgQwwVPe1A7aH0s10FgARsd2xl5nlg' \ + + 'RLHT2krPUw-iLQ5uHZSnYXFuF4caYemWcj4vqB2ocHkt-aqn04jgnnlWWME_K' \ + + '9ySWdWmPyS66HtLt1tCwc_-xGZklvbHw==' def test_generate_user_keys():
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
5News mentions
0No linked articles in our index yet.