Baike.dev
All toolsAI codingTrendingOpen sourceNewsSubmit
Log in
Back to tool/Back to issues
#14607·AutoGPT

fix(backend): a schedule that survives workflow removal keeps firing, because nothing at execution checks expert-workflow membership

Author: PwutsCreated Sep 15, 2026Updated Sep 15, 2026

Removing a workflow from an expert pauses the triggers it left behind (suspend_workflow_triggers, autogpt_platform/backend/backend/api/features/experts/scheduling.py:314). When an individual pause_schedule call raises, the failure is logged and the removal still completes — the ExpertWorkflow row is deleted and the caller is told what was stopped, which does not include the survivor. That schedule keeps firing the removed workflow under the expert's attribution, spending the owner's money on a cadence the user believes they cancelled.

The code says the run-time gate catches this, and for the archive case it does: detach_expert_triggers leaves the expert archived, and resolve_private_expert_tenancy filters isArchived: False, so add_graph_execution raises ExpertNotFoundError on the next fire. Workflow removal is different — the expert is still active, and nothing on the execution path checks ExpertWorkflow membership. _enforce_expert_credential_scope and the tenancy check both run there, so the survivor cannot reach an ungranted credential and cannot outlive the expert; what it can do is run a workflow that is no longer on the allow-list.

The same absence is what makes a retained AgentPreset executable through POST /library/presets/{id}/execute after removal: the preset is deactivated (isActive: False) by the same function, and that route does not filter on isActive. That path is owner-authenticated and the run is still held to the expert's grants, so it is not an escalation — but it is the same missing check.

Two candidate fixes, and the choice is a real trade-off:

  • Enforce membership at execution. In _add_graph_execution, when expert_id is set, refuse a graph that is not an installed workflow of that expert. This makes "installed workflows are a hard allow-list" true on every path rather than only in the copilot tools, and a revoke takes effect on the next fire, the way credential revocation already does. It is a change to a shared hot path and needs care over install_saved_agent (an agent built in chat installs itself) and over owner-initiated runs.
  • Treat a failed suspension as a failed removal. Raise out of suspend_workflow_triggers instead of logging, so the route returns the retryable 503 it already has for a cleanup failure and the ExpertWorkflow row survives. Cheaper and consistent, but it makes removal depend on scheduler availability, which the current code deliberately avoids.

A test that proves either: install a workflow on an expert, create a schedule for it, make pause_schedule raise, call remove_workflow, then fire the scheduled job and assert it does not create an execution (fix 1) or assert the removal failed and the row survives (fix 2).

Found by CodeRabbit while reviewing #14415; deliberately not fixed there, because both fixes are design changes outside that PR's diff.

Source: Significant-Gravitas/AutoGPT

View original on GitHubView discussion on GitHub