Skip to content

Dangerous mode: let your agent run commands, when only you can give it work - #810

Merged
robzolkos merged 5 commits into
mainfrom
dangerous-mode
Oct 1, 2026
Merged

robzolkos merged 5 commits into
mainfrom
dangerous-mode

Conversation

@robzolkos

@robzolkos robzolkos commented Sep 30, 2026 •

Copy link
Copy Markdown
Collaborator

Your agent can read and change files in the folder you start it in, and that's all. It can't run anything: not your linter, not your tests, not git. So "fix this and make sure the tests pass" isn't something it can do. It edits the code and you run the tests.

This adds a dangerous mode you can switch on for your own agent:

basecamp connect setup -P agent --dangerous

With it on, the agent can run any command on your computer, as you. It can run the linter and tests, fix what fails, and commit. Turn it off with --dangerous=false.

Why it's called dangerous

The agent reads the whole thread it's working in, including other people's comments and attachments. With a shell, text anywhere in that thread could steer it into running something on your machine. Everything you can reach, it can reach: your files, SSH keys, your Basecamp login, cloud tokens, the network. So it's off by default, and switching it on is deliberate:

  • You have to type yes. Setup explains what it means and asks you at the terminal. With no terminal (a script, or an AI running the command) it refuses, so an agent can never switch this on for itself.
  • Only for an agent you alone can give work to. If others can give it work (--trust project or --allow), setup refuses and explains why. It gives the one command that makes it possible (--trust operator --dangerous). Letting people in while it's on is refused the same way, and so is changing who the operator is.
  • It's hard to miss. Setup's summary, connect status, connect doctor and the connector's first log line all say it's on.

Why not for shared agents yet

If anyone in a project could give your agent work, anyone in that project could get your computer to run something, as you. Keeping it to you alone means the only person making those requests is you. It will stay off for shared agents until the agent's work can run in a box that holds only the project, with nothing of yours in it to reach.

Making sure it only ever runs your requests

  • The connector reads trust once, when it starts. A connector started while others could give it work never uses dangerous mode, whatever the file says later.
  • If requests from other people are still waiting from when they could give the agent work, the connector starts with dangerous mode off and says so. Those requests run as usual, never with a shell. Once they're done, a restart turns it on.
  • Turning it off applies from the very next decision: the connector reads the setting fresh before every launch and follow-up. A worker already running in dangerous mode finishes what it's doing and is handed nothing more, not even new messages in its thread mid-turn. Once off, it stays off for that run: turning it back on takes a restart. Setup says so, and says how to stop it now if you want to. The off switch works with Basecamp unreachable, and with BASECAMP_TOKEN set.
  • --dangerous=false on its own is the off switch, and it's saved without asking Basecamp anything, so it works offline or with a credential Basecamp no longer takes.
  • Dangerous mode only applies while connect.json names the operator the connector started with, so turning it back on can never hand a previous operator a shell before a restart.
  • If the connector started with dangerous mode off for that run, connect status says so, rather than claiming it's on.
  • Turning it on while a connector is running asks you to restart it.
  • A connect.json edited by hand to be both dangerous and shared is refused when it's read, by setup, status and the running connector alike.

How it works

  • Claude Code workers get every built-in tool, Bash included, and --permission-mode bypassPermissions instead of acceptEdits.
  • Codex workers run without a sandbox, with the network on. The driver checks the session Codex reports is the unsandboxed one it asked for, as it already does for the sandboxed one.
  • Everything else is unchanged: your own Claude and Codex settings are still ignored, only the Basecamp tools are connected, and the worker's environment is still an allow-list.

…t work

basecamp connect setup --dangerous lets the agent run any command on this
computer, as you: tests, linters, git. It asks you to type yes at a terminal,
so a script or an AI can't turn it on, and it's refused while other people can
give the agent work, with the reasons and the one command that makes it
possible. Setup, doctor, status and the connector's first line say while it's
on, and --dangerous=false turns it off at the next task.
…t is needed

- A run only uses dangerous mode if nobody else's request is still waiting from
  when others could give the agent work; those run without it.
- A worker started in dangerous mode gets nothing more once it's turned off.
- The operator can't change while dangerous mode is on.
- Setup says when a running connector needs a restart, and that a task already
  running finishes as it started.
Copilot AI balanced review requested due to automatic review settings September 30, 2026 23:56
@github-actions github-actions Bot added commands CLI command implementations tests Tests (unit and e2e) labels Sep 30, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

… the operator

- Dangerous mode is read fresh for every launch and follow-up, not from the
  two-second cache, so turning it off reaches the very next decision.
- It applies only while connect.json names the operator the connector started
  trusting, so turning it back on can't hand a previous operator a shell.
- --dangerous=false on its own is saved with nothing asked of Basecamp: the off
  switch works offline, or with a credential Basecamp no longer takes.
- Status says when the running connector isn't using dangerous mode.
- Refusals print commands that run as printed.
Copilot AI balanced review requested due to automatic review settings October 1, 2026 01:33

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Status can incorrectly report dangerous mode as active for safe or shadow connectors.

Review effort: Balanced
Findings: 1 Medium severity

Open (1)

Comment thread internal/commands/connect_operator.go Resolved

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 23 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread internal/commands/connect_dangerous.go Resolved
Comment thread internal/commands/connect.go Resolved
Comment thread internal/commands/connect_operator.go Resolved
Comment thread internal/connector/ledger_status.go Resolved
Comment thread internal/commands/connect_operator.go Resolved
Comment thread internal/commands/connect.go Resolved
Comment thread internal/connector/setup/apply.go Resolved
…and tell status the truth

Turning dangerous mode off stopped follow-ups between turns, but a new message
could still join the task mid-turn and be fetched by the running worker. Now
nothing joins a task started in dangerous mode once the mode is off; the
message runs as its own task, without it, after this one ends.

Status no longer says dangerous mode is in use when the running connector
started without it, and turning it off no longer promises a folder boundary
that ordinary mode doesn't have.
Copilot AI balanced review requested due to automatic review settings October 1, 2026 01:46

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Dangerous mode can reactivate without restart, bypass driver validation, and be reported inaccurately after lifecycle transitions.

Review effort: Balanced
Findings: 1 High severity · 2 Medium severity

Open (3)
Previously missed (2)

In code that hasn't changed since last review

Medium severity Reject dangerous mode with unsupported ACP driver override

internal/​commands/​connect_run.go:402

This enables dangerous policy without checking the effective driverName. Although File.Validate requires the stored driver to be spawn, basecamp connect --driver acp overrides it after the file is loaded; ACP has no ModeAnything mapping, so startup succeeds but every worker launch is unusable and work enters the start-failure hold. Refuse the ACP override when dangerous mode is effective before constructing the dispatcher.

Low severity Emit dangerous-mode notice before any other startup logs

internal/​commands/​connect_run.go:455

This is not always the connector's first log line as promised in the PR description: --hold logs at line 297, and an existing hold logs at line 302, both before this switch. Emit the dangerous-mode notice immediately after dangerousAllowedThisRun is decided so every startup path leads with it.

Comment thread internal/commands/connect_dangerous.go Resolved
Comment thread internal/commands/connect_operator.go Resolved

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 6 files (changes from recent commits).

Requires human review: Auto-approval blocked because this review re-detected 1 unresolved issue already reported by Cubic.

Re-trigger cubic

Comment thread internal/commands/connect_operator.go Resolved
…us honest

- Once it reads off, it stays off for the run, so off-then-on can't skip the
  restart or feed a worker that was cut off.
- A request from someone else that's blocked is judged again under today's
  trust, so it no longer keeps dangerous mode off for good. One whose worker
  failed to start still counts.
- The off switch works with BASECAMP_TOKEN set.
- Status keeps the run's dangerous-mode note when work is taken again after a
  hold, says nothing about it for --shadow, and the summary keeps its caveat.
- Turning it on for a new operator in one run is allowed; only a swap while
  it's already on is refused.
- Guided setup shows it even with no projects.
Copilot AI balanced review requested due to automatic review settings October 1, 2026 02:07

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🔵 Needs a closer look

Revocation can be missed across an off→on toggle, while status and machine-readable setup output also have correctness issues.

Review effort: Balanced
Findings: None

Resolved since last review (3)
Previously missed (2)

In code that hasn't changed since last review

Medium severity Confirmation prose corrupts JSON output

internal/​commands/​connect.go:479

The confirmation prose is written to stdout before the normal app.OK response. With --json (or auto format on a pipe), a successful enable therefore emits several plain-text paragraphs followed by JSON, so consumers cannot parse the command's output. Send the interactive warning to stderr, as refusedChange already does, and reserve stdout for the selected output format.

Medium severity Dangerous setting shortcut bypasses structured output

internal/​commands/​connect_dangerous.go:171

This shortcut bypasses the output writer entirely, so connect setup --dangerous=false --json (and auto output when piped) returns plain English rather than the repository's JSON success envelope; the already-off branch has the same problem. Keep direct prose only for styled output and use app.OK for machine-readable formats.

@robzolkos
robzolkos merged commit ed9592b into main Oct 1, 2026
31 checks passed
@robzolkos
robzolkos deleted the dangerous-mode branch October 1, 2026 02:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

commands CLI command implementations tests Tests (unit and e2e)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants