Skip to content

Require confirmation before running a function-call-proposed shell command - #794

Open
carfeii wants to merge 1 commit into
TheR1D:mainfrom
carfeii:fix/function-call-confirmation
Open

carfeii wants to merge 1 commit into
TheR1D:mainfrom
carfeii:fix/function-call-confirmation

Conversation

@carfeii

@carfeii carfeii commented Aug 5, 2026

Copy link
Copy Markdown

Fixes #793.

Summary

Handler.handle_function_call (sgpt/handlers/handler.py) executed any
function the model's tool-call response named immediately, with only a
one-line notice printed and no confirmation prompt. Since function-calling
is enabled by default (OPENAI_USE_FUNCTIONS=true), and the bundled
execute_shell_command function runs its argument via
subprocess.Popen(shell=True, ...), this meant any tool call naming it
ran with no chance to review or decline, unlike the tool's own --shell
mode, which correctly requires an [E]xecute/[M]odify/[D]escribe/[A]bort
confirmation before running an LLM-proposed command.

Piping untrusted content into sgpt (git diffs, log output, source
files) is the tool's own advertised primary workflow, and any such
content is a route for a prompt-injection payload to reach the model's
context and steer it toward calling execute_shell_command.

Fix

Adds a FUNCTION_CALL_CONFIRM config key, defaulting to "true", and
gates the actual function execution in handle_function_call behind a
typer.confirm prompt when set. The prompt is printed to stderr
(err=True) so it doesn't collide with the Rich Live-rendered response
stream on stdout. This mirrors the confirmation the tool already requires
for --shell mode's equivalent action, rather than introducing a new
pattern.

Testing

  • Manually reproduced the issue against an unpatched build: drove
    Handler.handle_function_call directly with a crafted tool-call
    payload naming execute_shell_command (this doesn't require a live
    API call, since the method only processes an already-received tool
    call), and confirmed a marker command executed immediately with no
    confirmation step.
  • Repeated against this branch using a real interactive session (tmux, so
    the prompt genuinely blocks on stdin, not a mocked confirmation):
    confirmed declining (n) leaves the marker file absent and yields a
    > Function call aborted. message, and confirming (y) lets it run as
    before.
  • Ran the existing test suite (pytest tests/): 23 passed. Note that
    main currently has 3 pre-existing failures unrelated to this change
    (a UsageError exit-code mismatch for mutually-exclusive CLI flags,
    present on a completely clean, unpatched checkout of main), and a
    pre-existing test-collection error from cfg.get("DEFAULT_TEMPERATURE")
    treating the float default 0.0 as falsy in Config.get's if not value check (also reproduced on a clean main checkout, also
    unrelated to this change). Neither is introduced or touched by this
    PR; flagging them here in case they aren't already known.

…mmand

Handler.handle_function_call executed any function the model's tool-call
response named immediately, with only a one-line notice printed and no
confirmation prompt. Since function-calling is enabled by default
(OPENAI_USE_FUNCTIONS=true), and the bundled execute_shell_command
function runs its argument via subprocess.Popen(shell=True, ...), this
meant any tool call naming it ran with no chance to review or decline,
unlike the tool's own --shell mode, which correctly requires an
[E]xecute/[M]odify/[D]escribe/[A]bort confirmation before running an
LLM-proposed command. Piping untrusted content into sgpt (git diff, log
output, source files) is the tool's own advertised primary workflow, and
any such content is a route for a prompt-injection payload to reach the
model's context.

Add a FUNCTION_CALL_CONFIRM config key, defaulting to "true", and gate
the actual function execution in handle_function_call behind a
typer.confirm prompt (printed to stderr, so it doesn't collide with the
Rich Live-rendered response stream on stdout) when set. This mirrors the
confirmation already required for --shell mode's equivalent action,
rather than introducing a new pattern.

See TheR1D#793.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Function-calling feature executes LLM-proposed shell commands with no confirmation, unlike the tool's own --shell mode

1 participant