Reported issues for infrabroker
Pod holds 17 of 45 problems reported by people outside the maintainer team. Issues filed by the project's own owners, members and collaborators are excluded entirely — a maintainer's release checklist is not a warning to a prospective user.
Back to infrabroker.
Most discussed
merge the three broker frontends (broker, mcp-broker, mcp-broker-http) into one binary with transport subcommands
File references are against a28ca75.
Context
Three of the seven binaries are thin wrappers around the same broker.Engine + internal/mcpserver, differing only in transport:
cmd/broker(~140 lines) — HTTP + mTLS,POST /v1/ssh_runcmd/mcp-broker(~66 lines) — MCP stdiocmd/mcp-broker-http(~166 lines) — MCP Streamable HTTP + OAuth/OIDC
Each main repeats the same wiring (LoadConfig → NewEngine → monitor.Serve → serve/run loop), and every release artifact, Doc
Read the thread · 2026-07-09 · closed · 2 comments
install.sh --bindir is ignored by the shipped systemd units
audit-id: a409f4c31c61
Category: logic · Severity: low — see description
Location: deploy/install.sh:48
Description: --bindir DIR installs signer/control-plane/mcp-broker-http to $BINDIR, but the units copied in step 5 hard-code ExecStart=/usr/local/bin/.... A non-default bindir yields enabled units that exec missing binaries. install-shim.sh handles --bindir correctly.
Proposed fix & verification: Rewrite ExecStart to ${BINDIR}/
Read the thread · 2026-08-13 · closed · 1 comment
install.sh never heals existing *.env or broker-ctl.json modes
audit-id: e406c27d8510
Category: security · Severity: medium — see description
Location: deploy/install.sh:176
Description: The installer claims re-run heals, never widens. Service JSON is converged to 0640 on every run, but two secret-adjacent files are left as-is:
- /etc/infrabroker/{signer,control-plane,mcp-http}.env (EnvironmentFile for AZURE_* / OIDC / webhook tokens). A 0644 file is readable by every infrabroker-* user because /etc/infrabroker is 0750 root:infrabroker —
Read the thread · 2026-08-13 · closed · 1 comment
reload() is not serialized with writeMu, so a concurrent policy narrowing can be reverted in memory
audit-id: c805ca866a5d
Category: security · Severity: medium — see description
Location: cmd/signer/main.go:771
Description: writeMu serializes POST/DELETE /v1/policy mutations (mutateAllow reads, edits, writes, then swaps s.local). reload() — SIGHUP, POST /v1/reload, and the mtime watcher — reads signer.json and later swaps s.local under s.mu only. buildState can take seconds (CA/AKV). Sequence: reload reads v1 → mutateAllow writes and applies v2 (DELETE last dangerous allow)
Read the thread · 2026-08-13 · closed · 1 comment
Command-policy wrapper gate misses versioned interpreters, ash, and /usr/bin/time
audit-id: 1427d5fdc887
Category: security · Severity: high — see description
Location: internal/signer/cmdpolicy.go:351
Description: After #371 the wrapper set is still an exact path.Base map. A live Decide() against denylist ^rm still allows:
- python3.12 -c / python3.11 -c / /usr/bin/python3.12 -c (Ubuntu/Debian default interpreter name; python3 is listed, python3.12 is not)
- ash -c 'rm …' (Alpine's shell when invoked by that name; sh/dash/bash are listed)
- /usr/bin/time
Read the thread · 2026-08-13 · closed · 1 comment
Deploy skill still teaches obsolete empty _default callers and omits agent CA custody
audit-id: dcafd283e94a
Category: documentation · Severity: medium — see description
Location: .agents/skills/deploy/SKILL.md:76
Description: #338 fixed install.sh/checklist: a non-empty callers table is already default-deny without requiring "_default": {"allowed_groups": []}. The deploy skill still requires empty _default and later expects {} when callers._default is default-deny — wrong post-v2.0.0. Skill CA custody section also lists only akv|pem and says those are the
Read the thread · 2026-08-12 · closed · 1 comment
main is red: the go-sdk v1.7.0 bump (#314) breaks in-conversation approvals — SEP-2322 forbids server-initiated elicitation during tools/call
audit-id: d43e5a27e54a
Category: logic · Severity: high — see description
Location: internal/mcpserver/tools.go:454
Description: chore(deps): bump github.com/modelcontextprotocol/go-sdk (de4bba1, #314) moved the SDK from v1.6.1 to v1.7.0 and landed on main with a FAILING "Build Go Project" check — main has been red since 2026-08-01T07:05Z and build is a required check, so every PR is blocked.
go test -race ./internal/mcpserver fails:
--- FAIL: TestApprovalDeclinedV
Read the thread · 2026-08-01 · closed · 1 comment
Control plane drops allow_file_transfer when forwarding GET /v1/hosts, so every host behind it advertises file_transfer=false
audit-id: f848933a1873
Category: logic · Severity: medium — see description
Location: cmd/control-plane/main.go:660
Description: The signer serves allow_file_transfer on GET /v1/hosts (cmd/signer/main.go:1115), and signer.Remote.FetchHosts maps it into HostInfo.AllowFileTransfer (internal/signer/remote.go:435). But when a broker talks to the SIGNER THROUGH THE CONTROL PLANE, handleHosts re-marshals the result into a fresh signer.WireHostInfo and copies only Addr/User
Read the thread · 2026-08-01 · closed · 1 comment
Most recent
docs/USAGE.md opens with 'the seven MCP tools' but documents thirteen (the six k8s_* tools have their own section)
audit-id: b83a3a7006c9
Category: documentation · Severity: low — see description
Location: docs/USAGE.md:3
Description: The guide's first sentence says it 'covers practical usage of the seven MCP tools exposed by cmd/mcp-broker (stdio) and cmd/mcp-broker-http'. Thirteen tools ship and the same file documents all of them: the seven ssh_* tools plus the six k8s_* tools (k8s_list_clusters, k8s_get, k8s_list, k8s_logs, k8s_apply, k8s_delete) in section 10, added with the Kubernete
Read the thread · 2026-07-24 · closed · 1 comment
Elicitation (#118) approve/decline outcome is not distinctly audited; an elicitation-approved exec is indistinguishable from a non-gated one
audit-id: e8f2340c7124
Category: logic · Severity: low — see description
Location: internal/mcpserver/tools.go:238
Description: With approval_via_elicitation, a require_approval command triggers an in-conversation elicitation. The approval REQUEST is audited (the first Execute withholds the cert and audits Outcome:error,'requires human approval'), but: (1) the DECLINE path (tools.go:238) returns 'approval declined' with NO audit write — the log cannot distinguish 'human asked
Read the thread · 2026-07-14 · closed · 1 comment
Redaction can inflate an audit entry past the 256 KiB reader buffer, bricking fail-closed startup (no write-time entry-size cap)
audit-id: 0503a78eb63b
Category: security · Severity: high — see description
Location: internal/audit/log.go:396
Description: Redaction runs on every Append (log.go:392-401) and EXPANDS free-text: the env-assignment default rule (internal/redact/defaults.go) turns AUTH=a (6 bytes) into AUTH=[REDACTED:env-assignment] (30 bytes). The sign request body is capped at 64 KiB (cmd/signer/main.go:589) but there is NO cap on command length, and no cap on the serialized entry size. Ever
Read the thread · 2026-07-14 · closed · 1 comment
Command-policy deny/require_approval bypass via shell quoting/encoding: extractCommands matches the re-printed (quote-preserving) command, not its decoded literal
audit-id: 0f3773740cd1
Category: security · Severity: high — see description
Location: internal/signer/cmdpolicy.go:197
Description: extractCommands re-prints each parsed simple command with printer.Print (cmdpolicy.go:197), which PRESERVES quoting/encoding, and PolicySet.decideOne matches deny/require_approval regexes against that printed form (policyset.go:145,157). On a denylist host (no allowlist) a non-matching command default-allows (policyset.go:187-189). The target she
Read the thread · 2026-07-14 · closed · 1 comment
infrabroker init --register-mcp writes a broker config with CWD-relative paths, so the registered MCP server never starts
audit-id: c82cfe6f18b8
Category: logic · Severity: medium — see description
Location: internal/initcmd/config.go:122
Description: infrabroker init emits config.json (and signer.json) with paths relative to the init directory: the broker's mTLS client cert/key/CA (pki/broker.crt, pki/broker.key, pki/mtls_ca.crt), the audit key (pki/audit.seed) and audit log (audit.log). The broker resolves these against the PROCESS working directory: broker.LoadConfig (internal/brok
Read the thread · 2026-07-14 · closed · 1 comment
GET /v1/revocations returns Reason and FrozenBy to any authenticated caller, unfiltered by callers-RBAC (a default-denied broker still reads the whole freeze ledger)
audit-id: b7e69dd303ca
Category: security · Severity: low — see description
Location: cmd/signer/main.go:1002
Description: handleRevocations authenticates the mTLS caller then returns s.freezes.List() unconditionally. List() includes each entry's Value (broker CNs / end-user ids), Reason (free-text operator notes, e.g. 'employee under investigation'), FrozenBy (admin CN) and FrozenAt. The handler comment justifies this as 'like GET /v1/hosts', but /v1/hosts is group-filtered (
Read the thread · 2026-07-10 · closed · 1 comment
Broker revocation poll (kill switch) degrades silently: repeated FetchRevocations failures emit only a log line, no metric/liveness signal
audit-id: a9f984f658f9
Category: security · Severity: medium — see description
Location: internal/broker/engine.go:687
Description: startRevocationPoll is the broker half of the kill switch (#126): it force-closes live sessions matching the signer freeze set. On FetchRevocations error it does 'log.Printf(warning: revocation poll failed ...); continue' with NO counter, gauge, or last-success timestamp. Every frontend exposes Prometheus via monitor.Serve, so /metrics is the moni
Read the thread · 2026-07-10 · closed · 1 comment
k8s path: audit dry-run decisions and stop leaking the API-server URL to the model
Summary
Two independent gaps on the Kubernetes broker path:
- Dry-run decisions are not audited. The SSH dry-run path audits
dry_run_allowed/dry_run_denied, butK8sExecutereturns on dry-run with no audit entry — an agent can enumerate the whole k8s ActionPolicy surface (allowed/approval-gated verbs/resources/namespaces) leaving no trace in the broker audit log. - API-server URL leaks to the model on transport errors, violating the stated invariant that the broker never expose
Read the thread · 2026-07-10 · closed · 0 comments
Kill-switch freeze coverage gaps: forwarder on_behalf_of bypass and unchecked /v1/clusters
Summary
The signer's freeze check runs on the resolved caller, so a trusted forwarder acting via on_behalf_of is never freeze-checked on its own mTLS CN — freezing a compromised forwarder/control-plane is a near no-op. Separately, GET /v1/clusters has no freeze check at all.
Where
cmd/signer/main.go:610reassignscallerto theon_behalf_ofvalue (viaresolveCaller,main.go:506) before the freeze check atcmd/signer/main.go:630(`s.freezes.Frozen(caller, req.E
Read the thread · 2026-07-10 · closed · 0 comments
The remaining reports are on the project's issue tracker.