Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions pandasai/core/code_execution/code_executor.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,27 @@
import logging
import warnings
from typing import Any

from pandasai.config import Config
from pandasai.core.code_execution.environment import get_environment
from pandasai.exceptions import CodeExecutionError, NoResultFoundError


logger = logging.getLogger(__name__)


_SANDBOX_WARNING = (
"pandas-ai is about to execute LLM-generated Python code on this host "
"without a sandbox. This is the historical default but it is unsafe: "
"if the LLM is influenced by untrusted input (a malicious prompt, a "
"crafted CSV column, a poisoned tool response) the generated code can "
"read files, exfiltrate environment variables, and run arbitrary "
"subprocesses. Configure a Sandbox (e.g. pandasai_docker.DockerSandbox) "
"via Agent(..., sandbox=...) to mitigate this. Pass "
"Config(suppress_unsandboxed_warning=True) to silence this warning."
)


class CodeExecutor:
"""
Handle the logic on how to handle different lines of code
Expand All @@ -14,6 +31,7 @@ class CodeExecutor:

def __init__(self, config: Config) -> None:
self._environment = get_environment()
self._config = config

def add_to_env(self, key: str, value: Any) -> None:
"""
Expand All @@ -24,7 +42,28 @@ def add_to_env(self, key: str, value: Any) -> None:
"""
self._environment[key] = value

def _emit_sandbox_warning_once(self) -> None:
"""Warn (once per process) that code is about to run without a sandbox.

``exec(code, env)`` where ``env`` has no ``__builtins__`` key causes
Python to silently insert the full ``builtins`` module, including
``__import__``, ``open``, ``eval``, ``exec``. LLM-generated code
therefore has unrestricted access to the host. The DockerSandbox
extension (or any subclass of :class:`pandasai.sandbox.Sandbox`)
is the supported mitigation; this warning makes the unsandboxed
default explicit so that users who haven't configured a sandbox
notice and choose intentionally.
"""
if getattr(self._config, "suppress_unsandboxed_warning", False):
return
if getattr(CodeExecutor, "_warned_unsandboxed", False):
return
CodeExecutor._warned_unsandboxed = True
warnings.warn(_SANDBOX_WARNING, RuntimeWarning, stacklevel=3)
logger.warning(_SANDBOX_WARNING)

def execute(self, code: str) -> dict:
self._emit_sandbox_warning_once()
try:
exec(code, self._environment)
except Exception as e:
Expand Down