Run Shell/Bash in prompt #108

Closed
opened 2025-11-11 14:06:01 -06:00 by GiteaMirror · 3 comments
Owner

Originally created by @DrM4CH1N3 on GitHub (Dec 19, 2023).

Hi !

Run sh/bash from Webui :

I'll try to explain ...

1- My prompt :
Give me the first 4 characters of this text: !bash curl ifconfig.io

2-The main.py python script recognizes the !bash command and executes it:
The result of the command stored in a variable

3-The python script returns the request + the variable:
Give me the first 4 characters of this text: 192.168.1.6

Here: 192.168.1.6 is the result of the "curl ifconfig.io" command

Docker container :
Need to install : curl or whatever you need to run in your prompt.

docker exec -it ollama-webui /bin/bash
apt update
apt install blablabla

First try with modified ollama_chat.py from :
https://github.com/jmorganca/ollama/blob/main/examples/python-simplechat/client.py

Result :
image

Code :

`import json
import requests
import shlex
import subprocess
import os 

# NOTE: ollama must be running for this to work, start the ollama app or run `ollama serve`
model = "codelama"  # TODO: update this for whatever model you wish to use


def chat(messages):
    r = requests.post(
        "http://0.0.0.0:11434/api/chat",
        json={"model": model, "messages": messages, "stream": True},
    )
    r.raise_for_status()
    output = ""

    for line in r.iter_lines():
        body = json.loads(line)
        if "error" in body:
            raise Exception(body["error"])
        if body.get("done") is False:
            message = body.get("message", "")
            content = message.get("content", "")
            output += content
            # the response streams one token at a time, print that as we receive it
            print(content, end="", flush=True)


        if body.get("done", False):
            message["content"] = output
            return message


def main():
    messages = []
    
    while True:
        user_input = input("Enter a prompt: ")
        print()
        if "!bash" in user_input:
            parts = user_input.split('!bash')
            text = parts[0].strip()

            # Executing Bash command
            command = parts[1].strip()
            try:
                output = subprocess.check_output(command, shell=True, text=True)
                result = f"{text} : {output.strip()}"
                messages.append({"role": "user", "content": result})
            except subprocess.CalledProcessError as e:
                print(f"Error executing command: {e}")
        else:
            messages.append({"role": "user", "content": user_input})

        # Send 
        message = chat(messages)
        messages.append(message)
        print("\n\n")


if __name__ == "__main__":
    main()
`

Now i need to convert the main.py from /app/ollama/main.py to do the same.
... Need Help... Please.

Originally created by @DrM4CH1N3 on GitHub (Dec 19, 2023). Hi ! **Run sh/bash from Webui :** I'll try to explain ... 1- My prompt : Give me the first 4 characters of this text: _!bash_ curl ifconfig.io 2-The main.py python script recognizes the _!bash_ command and executes it: The result of the command stored in a variable 3-The python script returns the request + the variable: Give me the first 4 characters of this text: 192.168.1.6 Here: **192.168.1.6** is the result of the "curl ifconfig.io" command **Docker container :** Need to install : curl or whatever you need to run in your prompt. ``` docker exec -it ollama-webui /bin/bash apt update apt install blablabla ``` First try with modified ollama_chat.py from : https://github.com/jmorganca/ollama/blob/main/examples/python-simplechat/client.py Result : ![image](https://github.com/ollama-webui/ollama-webui/assets/104561613/c5e3587a-b99c-4958-928c-8019cbea1157) **Code :** ``` `import json import requests import shlex import subprocess import os # NOTE: ollama must be running for this to work, start the ollama app or run `ollama serve` model = "codelama" # TODO: update this for whatever model you wish to use def chat(messages): r = requests.post( "http://0.0.0.0:11434/api/chat", json={"model": model, "messages": messages, "stream": True}, ) r.raise_for_status() output = "" for line in r.iter_lines(): body = json.loads(line) if "error" in body: raise Exception(body["error"]) if body.get("done") is False: message = body.get("message", "") content = message.get("content", "") output += content # the response streams one token at a time, print that as we receive it print(content, end="", flush=True) if body.get("done", False): message["content"] = output return message def main(): messages = [] while True: user_input = input("Enter a prompt: ") print() if "!bash" in user_input: parts = user_input.split('!bash') text = parts[0].strip() # Executing Bash command command = parts[1].strip() try: output = subprocess.check_output(command, shell=True, text=True) result = f"{text} : {output.strip()}" messages.append({"role": "user", "content": result}) except subprocess.CalledProcessError as e: print(f"Error executing command: {e}") else: messages.append({"role": "user", "content": user_input}) # Send message = chat(messages) messages.append(message) print("\n\n") if __name__ == "__main__": main() ` ``` Now i need to convert the main.py from /app/ollama/main.py to do the same. ... Need Help... Please.
Author
Owner

@DrM4CH1N3 commented on GitHub (Dec 20, 2023):

I'm trying to modify the /app/ollama/main.py file to run shell/bash when !bash is detected:

... Need Help Please.

Code :

from flask import Flask, request, Response, jsonify
from flask_cors import CORS
import requests
import subprocess
import shlex
import os

from apps.web.models.users import Users
from constants import ERROR_MESSAGES
from utils.utils import extract_token_from_auth_header
from config import OLLAMA_API_BASE_URL, WEBUI_AUTH

app = Flask(__name__)
CORS(app)

TARGET_SERVER_URL = OLLAMA_API_BASE_URL

@app.route("/", defaults={"path": ""}, methods=["GET", "POST", "PUT", "DELETE"])
@app.route("/<path:path>", methods=["GET", "POST", "PUT", "DELETE"])
def proxy(path):
    # Combine the base URL of the target server with the requested path
    target_url = f"{TARGET_SERVER_URL}/{path}"
    print("Received path:", path)  # Log the received path for debugging

    data = request.get_data()
    headers = dict(request.headers)

    if WEBUI_AUTH:
        if "Authorization" in headers:
            token = extract_token_from_auth_header(headers["Authorization"])
            user = Users.get_user_by_token(token)
            if user:
                if user.role in ["user", "admin"]:
                    if path in ["pull", "delete", "push", "copy", "create"]:
                        if user.role == "admin":
                            pass
                        else:
                            return (
                                jsonify({"detail": ERROR_MESSAGES.ACCESS_PROHIBITED}),
                                401,
                            )
                    else:
                        pass
                else:
                    return jsonify({"detail": ERROR_MESSAGES.ACCESS_PROHIBITED}), 401
            else:
                return jsonify({"detail": ERROR_MESSAGES.UNAUTHORIZED}), 401
        else:
            return jsonify({"detail": ERROR_MESSAGES.UNAUTHORIZED}), 401
    else:
        pass

    try:
        # Make a request to the target server
        target_response = requests.request(
            method=request.method,
            url=target_url,
            data=data,
            headers=headers,
            stream=True,
        )

        target_response.raise_for_status()

        # Proxy the target server's response to the client
        def generate():
            for chunk in target_response.iter_content(chunk_size=8192):
                yield chunk

        response = Response(generate(), status=target_response.status_code)

        # Copy headers from the target server's response to the client's response
        for key, value in target_response.headers.items():
            response.headers[key] = value

        return response
    except Exception as e:
        error_msg = "Server Connection Error" + str(e)
        print(error_msg)  # Log the error for debugging
        return jsonify({"detail": error_msg}), 400

@app.route("/", methods=["POST"])
def process_prompt():
    data = request.get_json()
    user_input = data.get("prompt", "")

    # Split the prompt to check for the presence of !bash
    lex = shlex.shlex(user_input, posix=True)
    lex.whitespace_split = True
    lex.whitespace = ' !'
    parts = list(lex)

    if "!bash" in parts:
        idx = parts.index("!bash")
        text = ' '.join(parts[:idx]).strip()

        # Execution of the Bash command
        command = ' '.join(parts[idx+1:]).strip()
        try:
            output = subprocess.check_output(command, shell=True, text=True)
            result = f"{text} : {output.strip()}"
            return jsonify({"processed_prompt": result})
        except subprocess.CalledProcessError as e:
            return jsonify({"error": f"Error executing command: {e}"}), 400
    else:
        # If the !bash command is not present, directly return the request
        return jsonify({"processed_prompt": user_input})

if __name__ == "__main__":
    app.run(debug=True)
@DrM4CH1N3 commented on GitHub (Dec 20, 2023): I'm trying to modify the /app/ollama/main.py file to run shell/bash when !bash is detected: ... Need Help Please. Code : ``` from flask import Flask, request, Response, jsonify from flask_cors import CORS import requests import subprocess import shlex import os from apps.web.models.users import Users from constants import ERROR_MESSAGES from utils.utils import extract_token_from_auth_header from config import OLLAMA_API_BASE_URL, WEBUI_AUTH app = Flask(__name__) CORS(app) TARGET_SERVER_URL = OLLAMA_API_BASE_URL @app.route("/", defaults={"path": ""}, methods=["GET", "POST", "PUT", "DELETE"]) @app.route("/<path:path>", methods=["GET", "POST", "PUT", "DELETE"]) def proxy(path): # Combine the base URL of the target server with the requested path target_url = f"{TARGET_SERVER_URL}/{path}" print("Received path:", path) # Log the received path for debugging data = request.get_data() headers = dict(request.headers) if WEBUI_AUTH: if "Authorization" in headers: token = extract_token_from_auth_header(headers["Authorization"]) user = Users.get_user_by_token(token) if user: if user.role in ["user", "admin"]: if path in ["pull", "delete", "push", "copy", "create"]: if user.role == "admin": pass else: return ( jsonify({"detail": ERROR_MESSAGES.ACCESS_PROHIBITED}), 401, ) else: pass else: return jsonify({"detail": ERROR_MESSAGES.ACCESS_PROHIBITED}), 401 else: return jsonify({"detail": ERROR_MESSAGES.UNAUTHORIZED}), 401 else: return jsonify({"detail": ERROR_MESSAGES.UNAUTHORIZED}), 401 else: pass try: # Make a request to the target server target_response = requests.request( method=request.method, url=target_url, data=data, headers=headers, stream=True, ) target_response.raise_for_status() # Proxy the target server's response to the client def generate(): for chunk in target_response.iter_content(chunk_size=8192): yield chunk response = Response(generate(), status=target_response.status_code) # Copy headers from the target server's response to the client's response for key, value in target_response.headers.items(): response.headers[key] = value return response except Exception as e: error_msg = "Server Connection Error" + str(e) print(error_msg) # Log the error for debugging return jsonify({"detail": error_msg}), 400 @app.route("/", methods=["POST"]) def process_prompt(): data = request.get_json() user_input = data.get("prompt", "") # Split the prompt to check for the presence of !bash lex = shlex.shlex(user_input, posix=True) lex.whitespace_split = True lex.whitespace = ' !' parts = list(lex) if "!bash" in parts: idx = parts.index("!bash") text = ' '.join(parts[:idx]).strip() # Execution of the Bash command command = ' '.join(parts[idx+1:]).strip() try: output = subprocess.check_output(command, shell=True, text=True) result = f"{text} : {output.strip()}" return jsonify({"processed_prompt": result}) except subprocess.CalledProcessError as e: return jsonify({"error": f"Error executing command: {e}"}), 400 else: # If the !bash command is not present, directly return the request return jsonify({"processed_prompt": user_input}) if __name__ == "__main__": app.run(debug=True) ```
Author
Owner

@justinh-rahb commented on GitHub (Dec 20, 2023):

Implementing the ability to execute arbitrary bash commands through the Ollama web UI raises extremely serious security concerns. Allowing such functionality could potentially open the door to severe vulnerabilities, including the execution of malicious scripts, data breaches, and system compromises. It's crucial to understand the far-reaching implications of such a feature. I strongly advise against proceeding with this proposal.

could_should_do_it

@justinh-rahb commented on GitHub (Dec 20, 2023): Implementing the ability to execute arbitrary bash commands through the Ollama web UI raises extremely serious security concerns. Allowing such functionality could potentially open the door to severe vulnerabilities, including the execution of malicious scripts, data breaches, and system compromises. It's crucial to understand the far-reaching implications of such a feature. I strongly advise against proceeding with this proposal. ![could_should_do_it](https://github.com/ollama-webui/ollama-webui/assets/52832301/7ab8ba01-21e8-4496-8f21-47e467fda160)
Author
Owner

@DrM4CH1N3 commented on GitHub (Dec 21, 2023):

@justinh-rahb
I am well aware of the problems it could bring in certain cases. The danger isn't one if it's controlled.
But thank you for taking the time to warn.

@DrM4CH1N3 commented on GitHub (Dec 21, 2023): @justinh-rahb I am well aware of the problems it could bring in certain cases. The danger isn't one if it's controlled. But thank you for taking the time to warn.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/open-webui#108