Audit finding from #300 (commit 679f9fe)
Severity: medium
Category: auth / authorization defaults
File: crates/agent/src/main.rs:155
Obvious fix: yes
Description
serve_http(client, &cli.bind, Default::default(), token) passes TokenScope::default() which is TokenScope::Full — every tool (kick_member, create_server, delete_message, …) is reachable from any client that holds the bearer token. There is no --scope flag exposed in Cli, so an operator deploying the HTTP transport has no way to restrict to e.g. Messaging or ReadOnly short of editing the binary.
Impact / Threat
Operators reasonably assume "default = least privilege"; in fact default = full admin. Combined with SEC-A-01 (timing-attackable token compare) and SEC-A-08 (world-readable identity), the blast radius of any one compromise is the entire agent identity's authority on the server.
Suggested fix
Add --scope readonly|messaging|full|admin (default messaging or readonly) to Cli, parse into TokenScope, pass through. Document the per-scope tool list.
Verify
rg -n "Default::default\(\)" crates/agent/src/main.rs
Resolved by #389 (merged 2026-04-26): adds --scope {messaging,read,full} clap flag, default Messaging, threaded into serve_http. Auto-close keyword chain (closes #301 #304 #305 #311) only fired for the first id, leaving this issue stuck open. Manually closing now.
admin CLI variant + regression test pinning the default were proposed in #412 but the maintainer chose to drop the increment. PR #412 closed.
Audit finding from #300 (commit 679f9fe)
Severity: medium
Category: auth / authorization defaults
File: crates/agent/src/main.rs:155
Obvious fix: yes
Description
serve_http(client, &cli.bind, Default::default(), token)passesTokenScope::default()which isTokenScope::Full— every tool (kick_member,create_server,delete_message, …) is reachable from any client that holds the bearer token. There is no--scopeflag exposed inCli, so an operator deploying the HTTP transport has no way to restrict to e.g.MessagingorReadOnlyshort of editing the binary.Impact / Threat
Operators reasonably assume "default = least privilege"; in fact default = full admin. Combined with SEC-A-01 (timing-attackable token compare) and SEC-A-08 (world-readable identity), the blast radius of any one compromise is the entire agent identity's authority on the server.
Suggested fix
Add
--scope readonly|messaging|full|admin(defaultmessagingorreadonly) toCli, parse intoTokenScope, pass through. Document the per-scope tool list.Verify
rg -n "Default::default\(\)" crates/agent/src/main.rsResolved by #389 (merged 2026-04-26): adds
--scope {messaging,read,full}clap flag, defaultMessaging, threaded intoserve_http. Auto-close keyword chain (closes #301 #304 #305 #311) only fired for the first id, leaving this issue stuck open. Manually closing now.adminCLI variant + regression test pinning the default were proposed in #412 but the maintainer chose to drop the increment. PR #412 closed.