VYPR
High severityNVD Advisory· Published Apr 16, 2025· Updated Apr 16, 2025

CVE-2024-53305

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.

PackageAffected versionsPatched versions
whoogle-searchPyPI
< 0.9.10.9.1

Affected products

2

Patches

1
223f00c3c053

Switch from `pickle`->`json` for config encoding

https://github.com/benbusby/whoogle-searchBen BusbyOct 31, 2024via ghsa
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

5

News mentions

0

No linked articles in our index yet.