# Infrastructure plugin guardrails > **Historical audit:** the inventory below was audited on July 31, 2026 against Docker 1.0.2 and Kubernetes 1.0.3. It is preserved from the README for reference. Check the current plugin source and installed versions before relying on it. [Back to the product overview](../README.md) · [Current security guide](https://github.com/risa-labs-inc/BossConsole/wiki/Security-and-Privacy) Scoped deliberately: this covers the **Docker and Kubernetes plugins only**, because they reach real infrastructure and because their gating was audited against source. It is not a statement about BOSS's whole tool surface - other tools have their own posture, and nothing here should be read as a claim about them. > ⚠️ **Read this first: if your user is an admin, RBAC permissions stop nothing.** `McpToolRegistryCore.permitted()` short-circuits on `isAdmin` before checking any permission. This is **by design, not an oversight** - it mirrors the host-wide rule in `pluginAccessAllowed` ("Admins implicitly hold every permission"), so it is an RBAC semantic to plan around rather than a fix to wait for. For an admin operator - the common case on a single-user desktop - every tool in the "permission-gated" list below is exactly as reachable as the ungated ones. The **[per-tool kill-switch](../README.md#you-decide-what-your-agents-can-touch) is not bypassed by admin** (enforced at call time, not just when listing tools) and is therefore the only boundary that holds for an admin user. Treat permissions as meaningful for non-admin roles, and the kill-switch as the control that always applies. > > How that kill-switch behaves when its own persistence goes wrong ([#85](https://github.com/risa-labs-inc/BossConsole/issues/85) - both paths used to fail *open*, in silence; they now **fail closed, keep your list, and say so**). Toggles apply live, and the set is persisted to `~/.boss/mcp-disabled-tools.json`, re-read only at startup - so a hand-edit of that file takes effect on the next launch, and: > > - **Read side.** A file that exists but doesn't parse no longer reads as "nothing disabled": **every tool is withheld** - and shown switched off in **Toolbox → MCP**, so turning the ones you want back on is what rebuilds the file. Names still legible in the damaged text (truncation, the usual corruption, leaves nearly all of them readable) stay off through that rebuild, and the damaged bytes are copied to `mcp-disabled-tools.json.corrupt` before anything overwrites them. An *absent* file still means "nothing disabled", as it should. > - **Write side.** The file is written first, and the in-memory set changes only where doing so cannot re-expose something the saved file withholds. A **disable** that can't be persisted still applies to this session - restricting is the safe direction - and you're told it won't survive a restart; undoing that unsaved disable is allowed, since it only converges back on what the file says. **Re-enabling a tool the saved file records as disabled is refused** while writes are failing. A toggle that changes nothing is reported as changing nothing, rather than as a decision that didn't stick. > - **Either way you are told.** An ERROR in the log, plus a warning that stays in the status bar until a write succeeds (wherever the status bar is showing - focus mode hides it along with everything else there). A transient toast cannot carry a fail-closed state: the next message cancels it, and one raised during startup is gone before you look. > > The file is also plaintext, and an agent holding `run_command` or `codebase_write` can rewrite it: truncating or corrupting it now withholds every tool instead of re-enabling them, but writing a *valid* empty list still clears your choices at the next launch. This is the strongest control available here, not a sandbox. **Confirmation dialogs never apply to agents.** Destructive actions taken by hand in the sidebar raise a confirm dialog, but that lives in the panel UI - an agent calling an MCP tool never sees it. **Permission-gated for non-admin roles:** `docker_rm`, `docker_stop`, `docker_compose_down` (`docker.manage`); `k8s_delete`, `k8s_scale`, `k8s_rollout_restart` (`kubernetes.manage`); `helm_install`, `helm_upgrade`, `helm_rollback`, `helm_uninstall`, `helm_test` (`kubernetes.manage`); `helm_push` (`helm.publish`). **Not permission-gated at all** - exhaustive for *mutating* tools as of writing, and split by how much reach they actually have. Read-only tools (`docker_ps`, `k8s_pods`, `k8s_logs`, the `helm_get_*` family) are also ungated and are not listed; note `k8s_logs` can surface secret material regardless of the redaction below. - **Real reach - disable unless needed:** `k8s_exec`, `k8s_apply`, `k8s_port_forward`, `docker_compose_up`, `docker_build`, `docker_start`, `docker_restart`, `helm_repo_add`, `helm_repo_update`, `helm_repo_remove`, `helm_package`, `helm_dependency_update` - **`k8s_use_context` - also real reach, for a less obvious reason.** It only flips an in-memory selection, but that selection decides which cluster *every* subsequent `k8s_*` / `helm_*` call targets. Switching to a prod context and then calling ungated `k8s_apply` or `k8s_exec` is not local by any useful definition. - **Local-only - open a tab, or stop something BOSS started:** `docker_open_service`, `k8s_open_resource`, `k8s_port_forward_stop`, `helm_open_release` > ⚠️ **`k8s_exec` and `k8s_apply` are the two to disable first.** `k8s_exec` is arbitrary in-cluster command execution - it opens a pod shell an agent can then drive - so it **bypasses the Secret protections below** entirely (read a mounted Secret or the service-account token directly). `k8s_apply` is the same class: apply a pod that mounts the Secret. **Scope of the other claims.** Ports BOSS publishes itself bind to `127.0.0.1`; ports declared in your own `docker-compose.yml` bind as written, since the plugin runs your file unmodified - both a `"8080:8080"` mapping and `network_mode: host` bypass the loopback binding. The Kubernetes plugin never modifies your kubeconfig - context selection is local to BOSS, so your shells' `kubectl` default is untouched - though `helm repo` commands do write your local Helm config (`~/.config/helm/repositories.yaml`). Secret values are redacted two specific ways: `k8s_yaml` is refused for Secrets, and rendered Helm manifests have `data:`/`stringData:` blocks stripped - subject to the `k8s_exec` caveat above. Audited 2026-07-31 against **boss-plugin-docker 1.0.2** and **boss-plugin-kubernetes 1.0.3**; compare against your installed versions, since the plugins release independently of BOSS and nothing in CI relates this list to them. Plugin source is authoritative. Closing the ungated gaps is tracked in [boss-plugin-docker#3](https://github.com/risa-labs-inc/boss-plugin-docker/issues/3) and [boss-plugin-kubernetes#3](https://github.com/risa-labs-inc/boss-plugin-kubernetes/issues/3).