Skip to content

Security and permissions

Permission system architecture

agents-fleet resolves a single effective permission profile for every worker spawn. The canonical profile table lives in src/fleet/agentPermissionProfiles.ts; both providers consume the resolved profile so Copilot and Claude enforce the same read/write/shell/meta capabilities.

Resolution happens in FleetManager before provider session creation. Copilot uses the profile in onPermissionRequest and only enables setApproveAll for unrestricted spawnable profiles. Claude translates the same profile into permissionMode, disallowedTools, and canUseTool.

Default agent-type profiles

Agent typeWriteShellMeta/sub-agentsTrust
explorerNoNoNoRead-only
reviewerNoNoNoRead-only
researcherScoped to .plans/, .fleet/NoNoNotes/research
testerNoYesNoTest runner
coderYesYesYesFull trust
general-purposeYesYesYesFull trust
customYesYesYesFull trust

Override precedence

Effective permissions are merged in this order:

  1. Canonical agent-type profile
  2. Config wildcard: permissions["*"]
  3. Config type entry: permissions["explorer"], permissions["tester"], etc.
  4. Per-spawn permissionOverrides

Later entries win. writeScopes replace lower-precedence scopes rather than unioning with them.

Example config:

json
{
  "permissions": {
    "*": { "canShell": false },
    "explorer": { "canShell": true }
  },
  "allowPrivilegeEscalation": false
}

Example per-spawn override:

json
{
  "name": "shell-explorer",
  "agent_type": "explorer",
  "prompt": "Inspect the build output",
  "permissionOverrides": { "canShell": true }
}

SEC-4 escalation guard

By default, overrides cannot elevate restricted profiles in ways that bypass the agent-type trust model. The guard rejects:

  • fullTrust: false becoming true
  • privilegeLevel increasing above the canonical level
  • canMeta: false becoming true

Normal targeted grants such as explorer.canShell=true are allowed because they do not raise fullTrust, privilegeLevel, or meta-agent access.

--allow-privilege-escalation

Use --allow-privilege-escalation only when you intentionally want overrides to elevate restricted profiles. The same setting can be persisted in ~/.fleet/config.json as:

json
{ "allowPrivilegeEscalation": true }

The CLI flag takes precedence over config. When enabled, startup prints a red warning: ⚠️ Privilege-escalation overrides ENABLED — agent permission profile elevation allowed.

Deprecated --yolo and per-SEC acknowledgements

For a step-by-step migration guide, see the --yolo migration guide.

--yolo is deprecated and no longer bypasses any SEC regression by itself. A bare --yolo exits before provider startup with:

text
--yolo requires at least one --acknowledge-* flag. Use --acknowledge-all-sec for legacy full-bypass behavior, or set AGENTS_FLEET_YOLO_LEGACY=1 for CI scripts that cannot change command lines. See docs/yolo-migration.md or docs/security.md for details.

The flag is kept only for trusted autopilot/CI migration. It will be removed in a future major version.

FindingDefault postureAcknowledgement that re-opens itWhat is bypassed
SEC-2Claude restricted types use permissionMode: "default", disallowedTools, and canUseTool.--yolo --acknowledge-sec2Re-enables Claude permissionMode: "bypassPermissions" for yolo sessions.
SEC-4Restricted worker types do not receive unrestricted setApproveAll; per-type gates remain authoritative.--yolo --acknowledge-sec4Re-enables restricted-type approve-all plus write/shell approvals.
MCP allowlistPer-worker MCP allowlists are enforced.--yolo --acknowledge-mcp-bypassRe-enables bypassing MCP allowlist checks.
SEC-R3-2Unknown Copilot permission request kinds fail closed.--yolo --acknowledge-sec-r3-2Re-enables approval of unknown permission kinds.

Convenience flags and config equivalents:

bash
agents-fleet --yolo --acknowledge-sec2
agents-fleet --yolo --acknowledge-sec4
agents-fleet --yolo --acknowledge-mcp-bypass
agents-fleet --yolo --acknowledge-sec-r3-2
agents-fleet --yolo --acknowledge-all-sec   # legacy full-bypass behavior
json
{
  "yolo": true,
  "yoloAcks": {
    "sec2": true,
    "sec4": true,
    "mcpBypass": true,
    "secR3-2": true
  }
}

CLI acknowledgement flags take precedence over config acknowledgements. AGENTS_FLEET_YOLO_LEGACY=1 is a temporary escape hatch for CI scripts that cannot change command lines; it behaves like --yolo --acknowledge-all-sec and is reported as env-legacy by /diagnose.

Migrating from legacy --yolo

Prefer explicit permission config instead of legacy full bypass:

json
{
  "permissions": {
    "*": {
      "fullTrust": true,
      "canShell": true,
      "canWrite": true,
      "canMeta": true,
      "writeScopes": []
    }
  },
  "allowPrivilegeEscalation": true
}

Safer migration path:

  1. If a restricted type only needs shell, configure that capability, for example "permissions": { "explorer": { "canShell": true } }.
  2. If an override intentionally elevates fullTrust, privilegeLevel, or canMeta, use --allow-privilege-escalation or persist "allowPrivilegeEscalation": true.
  3. If legacy all-bypass behavior is truly required, use --yolo --acknowledge-all-sec.
  4. For uneditable CI scripts only, set AGENTS_FLEET_YOLO_LEGACY=1 temporarily and plan to remove it.

/diagnose permission posture

/diagnose now includes a permission posture section in human and JSON output. When locked down it prints:

text
Permission posture: All SEC restrictions in effect. No bypasses active.

When bypasses are active it shows source attribution:

text
Permission posture:
  Effective restrictions: 1 SEC bypasses ACTIVE
  - SEC-2 (Claude bypass): ACTIVE via --yolo --acknowledge-sec2
  - SEC-4 (privilege escalation): NOT ACTIVE (would require --yolo --acknowledge-sec4)
  - MCP allowlist: NOT BYPASSED
  - SEC-R3-2: NOT BYPASSED
  Config overrides: explorer.canShell=true, researcher.writeScopes=[".plans"]

JSON output has a versioned root permissions object with schema_version, redacted config_overrides, allow_privilege_escalation, yolo, yolo_acks, and active_bypasses.