browserpilot icon indicating copy to clipboard operation
browserpilot copied to clipboard

Vulnerability Report: Code Injection Vulnerability in gpt_selenium_agent.py due to Flawed _check_danger and exec() Execution in __step_through_instructions

Open ybdesire opened this issue 10 months ago • 2 comments

Description

The __step_through_instructions method in the gpt_selenium_agent.py file is vulnerable to CWE - 94: Code Injection. This method uses the exec() function to execute the action code, which is obtained from the instruction_compiler.step() method and is potentially user - inputted or generated by an LLM based on user input.

impacted code : https://github.com/handrew/browserpilot/blob/0c76ea73e78ade022b401ad1698de23221e29c38/browserpilot/agents/gpt_selenium_agent.py#L366

Although the code includes a call to self._check_danger(action) to try to detect and prevent dangerous code execution, the _check_danger function is inadequately implemented. It relies on simple string matching techniques, such as checking for the presence of the import keyword and specific black - listed libraries. This makes it easy for attackers to bypass the security check. For example, attackers can use string concatenation, code obfuscation, or dynamic import techniques to avoid being detected by the _check_danger function.

If an attacker manages to inject malicious Python code into the action input, the exec() function will execute this code within the context of the running program. This can lead to a wide range of security issues, including unauthorized access to system resources, data leakage, and even complete system compromise.

Exploit

An attacker can exploit this vulnerability by following these steps:

  1. Identify the Input Pathway: First, the attacker needs to determine how the input is provided to the instruction_compiler. This could be through an API endpoint, a user interface, or a configuration file.

  2. Craft Malicious Code: The attacker creates malicious Python code that can achieve their desired objectives. For example, to read sensitive files on the system:

import os; print(os.popen('cat /etc/passwd').read())

To bypass the _check_danger function, the attacker can use techniques like string concatenation:

lib = "os"; mod = __import__(lib); mod.system('ls')
  1. Inject the Malicious Code: The attacker inserts the crafted malicious code into the input that is ultimately processed by the instruction_compiler. When the __step_through_instructions method is called, the action variable will contain the malicious code.

  2. Trigger Execution: The exec(action, globals(), ldict) statement will execute the malicious code. Since the _check_danger function can be bypassed, the malicious code will run without being blocked, allowing the attacker to gain unauthorized access to system resources, modify data, or perform other malicious actions depending on the permissions of the running process.

Impacted version

all versions

ybdesire avatar Apr 16 '25 14:04 ybdesire

Thank you for submitting. Do you have any suggestions on how to remedy? My idea to embed a bunch of string checks doesn't seem robust... Any sandboxing you'd recommend?

handrew avatar Apr 16 '25 15:04 handrew

Thank you for submitting. Do you have any suggestions on how to remedy? My idea to embed a bunch of string checks doesn't seem robust... Any sandboxing you'd recommend?

sandbox is necessary :) you can try such tool : https://github.com/vndee/llm-sandbox

ybdesire avatar Apr 30 '25 13:04 ybdesire