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 type | Write | Shell | Meta/sub-agents | Trust |
|---|---|---|---|---|
explorer | No | No | No | Read-only |
reviewer | No | No | No | Read-only |
researcher | Scoped to .plans/, .fleet/ | No | No | Notes/research |
tester | No | Yes | No | Test runner |
coder | Yes | Yes | Yes | Full trust |
general-purpose | Yes | Yes | Yes | Full trust |
custom | Yes | Yes | Yes | Full trust |
Override precedence
Effective permissions are merged in this order:
- Canonical agent-type profile
- Config wildcard:
permissions["*"] - Config type entry:
permissions["explorer"],permissions["tester"], etc. - Per-spawn
permissionOverrides
Later entries win. writeScopes replace lower-precedence scopes rather than unioning with them.
Example config:
{
"permissions": {
"*": { "canShell": false },
"explorer": { "canShell": true }
},
"allowPrivilegeEscalation": false
}Example per-spawn override:
{
"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: falsebecomingtrueprivilegeLevelincreasing above the canonical levelcanMeta: falsebecomingtrue
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:
{ "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:
--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.
| Finding | Default posture | Acknowledgement that re-opens it | What is bypassed |
|---|---|---|---|
| SEC-2 | Claude restricted types use permissionMode: "default", disallowedTools, and canUseTool. | --yolo --acknowledge-sec2 | Re-enables Claude permissionMode: "bypassPermissions" for yolo sessions. |
| SEC-4 | Restricted worker types do not receive unrestricted setApproveAll; per-type gates remain authoritative. | --yolo --acknowledge-sec4 | Re-enables restricted-type approve-all plus write/shell approvals. |
| MCP allowlist | Per-worker MCP allowlists are enforced. | --yolo --acknowledge-mcp-bypass | Re-enables bypassing MCP allowlist checks. |
| SEC-R3-2 | Unknown Copilot permission request kinds fail closed. | --yolo --acknowledge-sec-r3-2 | Re-enables approval of unknown permission kinds. |
Convenience flags and config equivalents:
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{
"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:
{
"permissions": {
"*": {
"fullTrust": true,
"canShell": true,
"canWrite": true,
"canMeta": true,
"writeScopes": []
}
},
"allowPrivilegeEscalation": true
}Safer migration path:
- If a restricted type only needs shell, configure that capability, for example
"permissions": { "explorer": { "canShell": true } }. - If an override intentionally elevates
fullTrust,privilegeLevel, orcanMeta, use--allow-privilege-escalationor persist"allowPrivilegeEscalation": true. - If legacy all-bypass behavior is truly required, use
--yolo --acknowledge-all-sec. - For uneditable CI scripts only, set
AGENTS_FLEET_YOLO_LEGACY=1temporarily 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:
Permission posture: All SEC restrictions in effect. No bypasses active.When bypasses are active it shows source attribution:
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.