The core idea
It is not enough to prohibit infrastructure changes and ask an agent not to reveal passwords. Sensitive data must be filtered before the tool result enters the model's context.
Imagine a request: “Check the container before updating it.” The agent calls an infrastructure API, receives a response and reports that the application is running with the required number of replicas. Nothing was changed, and no password appeared in the answer. It seems safe.
But the API response may contain more than a status: environment variables, connection strings, configuration settings or integration credentials may come with it. If the tool passes the entire object to the language model, the secret has already crossed the boundary that should have protected it. Removing it from the final answer is too late.
A secret can enter the context without appearing in the answer
In a conventional application, a developer chooses which fields to return to the caller. An agent introduces another recipient between the external service and the decision: the model. We must therefore define separately what the tool may read and what it may show the model.
The risk is not limited to an obvious field named password. A token may be hidden in an arbitrary environment variable, repository URL, startup argument, error response or log line. Masking a few familiar keys does not cover the other possibilities.
That is why, when designing an infrastructure assistant for Dockhost, the key requirement was to limit the reading result itself rather than sanitize the final answer. The model should not receive extra data simply because the API can return it.
Return a summary, not the entire API response
A container readiness check needs only a small set of facts: its state, replica count, selected numeric limits and whether the required bindings exist. Environment variable values are unnecessary for this check.
A safer approach is to process the original response in a separate process and expose only explicitly allowed fields. For example, return a count instead of the full environment list, a known code instead of arbitrary error text, and “unknown” instead of an unexpected status.
This is allowlist filtering. It is more predictable than searching for words such as “key” and “password”: an unknown field is rejected by default. Raw HTTP responses, credential-bearing URLs and exception messages must also stay out of the output: an error itself may contain a secret.
Permissions solve a different problem
Read-only mode is useful: it reduces the risk of accidentally deleting a container or changing its settings. But it does not determine which values read operations return. An agent without write access can still receive confidential configuration.
These are two independent protections. Permissions limit available actions and resources; the filter limits the data reaching the model. If access covers several projects, restricting the command set alone may not provide project isolation.
A connection therefore needs both minimum privileges and a controlled reading channel. A direct tool call that returns secrets in its own result cannot be made safe by editing the assistant's answer afterward.
A sanitized response is not an update payload
There is a reverse trap. A summary without secrets is suitable for diagnostics, but not for replacing an entire configuration. Using it as an update payload may accidentally remove variables, ports or attached disks that were simply absent from the summary.
To change one setting, prefer a narrow operation that touches only that setting. If a service requires a full configuration, a secure executor should retrieve it inside a protected process, preserve unrelated fields, apply the permitted change and show the agent only a sanitized description of the result.
This separates two different objects: the complete data needed for a correct operation and the minimum data needed for the model to decide. Neither can substitute for the other.
What we can test in practice
Tests with synthetic secrets are useful here: insert values into different API fields, simulate errors, malformed responses and redirects, then inspect the process output. The implemented version included such checks for infrastructure reads and error handling.
But passing tests for one handler does not prove that the external MCP server, the agent's other tools and the entire logging chain are protected. They confirm only the paths tested. No real account operations or independent comparison of the agent's performance with this skill were conducted.
The security boundary comes before the model
The usual advice to “avoid showing secrets to the user” describes a control point that comes too late. With an infrastructure agent, the critical moment happens earlier: when an external response becomes part of the model's context.
The model should see only what it needs for the next decision, not everything its tool can read.
The practical rule is to start with least privilege, pass every sensitive response through a narrow, testable projection, and keep the complete data inside a protected executor only when a change actually requires it. This architecture reduces the surface for disclosure without sacrificing correct operations.
