Skip to content

Bug: allow_shell_exec cannot be persisted — missing in auto_start_bots, UpdateBotRequest, and _apply_payload #534

@xuhao0080

Description

@xuhao0080

Description

allow_shell_exec is a security-sensitive flag in BotConfig that controls whether the TutorBot can execute shell commands via the exec tool. However, it cannot be persistently set to true due to three separate code omissions in the current v1.4.2 codebase.

Bugs Found

1. auto_start_bots does not pass allow_shell_exec to BotConfig

File: deeptutor/services/tutorbot/manager.py (around line 985)

When the server starts and auto_start_bots() runs, it reads config.yaml from disk but creates a BotConfig without passing allow_shell_exec. The field defaults to False even if the YAML file has allow_shell_exec: true.

# Current code — allow_shell_exec is missing:
config = BotConfig(
    name=data.get("name", bid),
    description=data.get("description", ""),
    persona=data.get("persona", ""),
    channels=data.get("channels", {}),
    model=data.get("model"),
    llm_selection=data.get("llm_selection"),
    # ⚠️ allow_shell_exec not passed — defaults to False
)

This means any bot with auto_start: true will always start with allow_shell_exec: false, regardless of what the config file contains. Saving the config later persists the false value back to disk, overwriting the user's intended setting.

2. UpdateBotRequest does not include allow_shell_exec

File: deeptutor/api/routers/tutorbot.py (line 80-86)

class UpdateBotRequest(BaseModel):
    name: str | None = None
    description: str | None = None
    persona: str | None = None
    channels: dict | None = None
    model: str | None = None
    llm_selection: dict[str, str] | None = None
    # ⚠️ allow_shell_exec is missing

The PATCH endpoint accepts the field (Pydantic silently ignores unknown fields) but never applies it.

3. _apply_payload does not handle allow_shell_exec

File: deeptutor/api/routers/tutorbot.py (line 327-341)

Even if the request model included the field, the function that applies PATCH payloads to the bot config does not handle it:

def _apply_payload(target, payload):
    cfg = getattr(target, "config", target)
    if payload.name is not None: cfg.name = payload.name
    if payload.description is not None: cfg.description = payload.description
    if payload.persona is not None: cfg.persona = payload.persona
    if payload.channels is not None: cfg.channels = payload.channels
    if payload.model is not None: cfg.model = payload.model
    if "llm_selection" in payload.model_fields_set: cfg.llm_selection = ...
    # ⚠️ allow_shell_exec not handled

Impact

  • Users who manually edit config.yaml to set allow_shell_exec: true will find it reset to false after every container restart or bot restart.
  • The exec tool cannot be enabled through the API (PATCH endpoint ignores the field).
  • Skills that depend on shell execution (deep-question, deep-research, deep-solve, notebook, knowledge-base via CLI commands) remain inaccessible through TutorBot's chat interface.

Expected Behavior

  1. auto_start_bots() should pass allow_shell_exec=data.get("allow_shell_exec", False) to the BotConfig constructor.
  2. UpdateBotRequest should include allow_shell_exec: bool | None = None.
  3. _apply_payload() should handle allow_shell_exec (e.g., if payload.allow_shell_exec is not None: cfg.allow_shell_exec = payload.allow_shell_exec).

Environment

  • DeepTutor version: 1.4.2
  • Docker image: ghcr.io/hkuds/deeptutor:latest (built 2026-05-28)
  • Deployment: Docker with bind mount for data volume

Related

This is similar in spirit to the config-wipe bug fixed in #331 / #332 (v1.1.1), which addressed the same overwrite problem for the channels field.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions