Permission Is Not Unlimited Access: Open Nua's Mental Model for Agent Security
Open Nua Engineering
Agent security discussions often begin with a confirmation dialog: should the user approve this action?
Approval answers only one question. It does not say which files the process can read, whether it inherits local credentials, where it may connect, whether a failed mutation is safe to retry, or which evidence an administrator should be allowed to inspect.
That led us to a simple principle in Open Nua: authorization is not the end of a security control. It is the beginning of governed execution.
Our earlier article on Agent governance focused on execution identity, Capabilities, HITL, recovery, and unknown outcomes. This article takes the next step: once an action is allowed, how does the system keep it inside the approved boundary?
Secure the execution chain, not the model's intentions
Models respond to prompts. Documents can carry injected instructions. Pages and remote responses change. A Skill is text, and a Plugin may be upgraded. If security depends on the Agent correctly understanding and following a rule, final authority sits in the least stable layer.
Open Nua treats prompts, model output, client actions, Skills, Plugins, workspace files, and remote responses as untrusted intent. They may propose work and raise risk signals, but they cannot declare identity, authorization, data scope, or a lower risk level.
The security chain can be summarized as:
untrusted intent
→ trusted facts produce a decision
→ the decision binds a constrained execution environment
→ external access uses short-lived credentials and exact egress leases
→ only minimally sufficient security evidence remains
The important choice is not a particular sandbox technology. It is giving each layer one clear responsibility.
Layer one: who is allowed to decide
Open Nua keeps local authorization facts in Desktop Main. Renderer, model, and Plugin input can express what they want to do. Main combines the authenticated actor and Profile, installed package digest, Capability, target, data scope, current consent, and limits into an immutable decision revision.
Two consequences follow.
First, a security signal may preserve or increase risk, never lower it. A model claiming that an action is safe, a page asking to ignore prior rules, or a Skill saying that approval is unnecessary does not grant authority.
Second, a change in actor, package, Capability, target, data scope, or arguments requires a new decision. One approval is not a universal pass for the rest of the conversation.
This principle appears in the product as three local execution modes:
- Ask for approval returns sensitive local actions to the user before execution;
- Controlled execution is the default, allowing autonomous work inside approved workspace, file, environment, network, and resource boundaries;
- Full access records an explicit higher-risk choice for the current foreground Thread and disables the file and network sandbox, while retaining timeout, process-tree, environment, resource, and output controls.
Full access does not mean that every security control disappears. It does not propagate to Automations, Feishu, or background Plugin work, and high-risk external effects remain independently governed.
Layer two: permission is not host capability
Pointing cwd at a workspace does not confine a process to that workspace. Absolute paths, parent traversal, links, child processes, interpreters, and network sockets can all cross that boundary.
Open Nua separates whether an action is allowed from how it executes:
LocalExecutionPolicyproduces the decision: risk, allow/approve/deny, scope, and required controls;ExecutionEnvironmentconsumes that decision and enforces process, file, environment, network, resource, cancellation, and cleanup limits.
An allow decision still fails if the required execution capability is unavailable. A sandbox startup failure cannot silently fall back to an unrestricted host shell. A platform without a supported adapter cannot pretend that cwd is isolation.
In the current Open Nua Desktop development line, local macOS execution uses real operating-system containment. It defaults to approved workspace access, a clean environment, bounded resources, and no arbitrary network. Timeout, cancellation, and crashes must also close child processes and temporary resources.
The mental model is simple: Policy defines the boundary; Environment proves that the boundary exists.
Layer three: credentials and network are capabilities, not environment
Traditional CLIs rely heavily on ambient authority: tokens in environment variables, login files under the user directory, and unrestricted system networking. That is convenient for a person, but it lets any invoked script inherit more authority than the task requires.
Open Nua removes credentials and network from the workload environment and places them behind a CredentialBroker:
- workloads do not receive long-lived credentials by default;
- raw secrets do not enter the Agent, Plugin, shell, argv, workspace, ordinary logs, or audit;
- remote work receives an opaque reference or a short-lived lease;
- the lease binds actor, Profile, execution, Capability, destination, method, path, and expiry;
- networking is denied by default and exact approved destinations pass through the Gateway;
- redirects, DNS changes, localhost, metadata addresses, and proxy environment variables cannot widen the destination.
“May call this service” is therefore different from “may use the internet,” and the model context does not need to carry a credential for useful work to happen.
Consent is a scoped relationship, not a Boolean
An approved = true flag quickly becomes ambiguous. Was approval for one action or the whole Thread? Does it survive a changed target? Can it be reused after a Plugin upgrade?
Open Nua distinguishes three common forms of consent:
- one-shot consent belongs to one decision and action;
- Thread-scoped consent binds the current Thread, actor, Profile, Capability, target, and policy revision;
- Plugin standing consent is established when the user installs or enables a Plugin with explicitly declared low-risk capabilities.
Standing consent does not make a Plugin permanently trusted. It binds the package version and digest, Capability set, and installation state. Expanded permissions, changed package content, revocation, or uninstall invalidate it. Publishing, deleting, transferring, and other high-risk external effects cannot use installation consent to bypass per-action approval.
This is how the OpenCLI Plugin can own its CLI and Chrome Extension prerequisites without receiving arbitrary shell or network access.
Layer four: audit is evidence, not a copy of the conversation
Another common security failure is logging every prompt, response, argument, absolute path, and identity in the name of auditability. It improves searchability by creating a second sensitive data system.
Open Nua's SecurityAudit accepts an allowlisted projection. It records stable execution and effect references, package and Capability digests, risk, decision, reason code, outcome, duration, and necessary size buckets. It does not store raw prompts, replies, credentials, full arguments, URL query or body data, or external identity.
Desktop first writes to a bounded local queue. Gateway and Backend ingest idempotently. Admin Web then exposes role-separated aggregates, investigation, and redacted export. Investigation reads are themselves audited. Kill switches and rollout controls may tighten or disable a capability, never turn a high-risk action into an unrestricted fallback.
The goal of minimal evidence is not to replay everything the user did. It is to answer: who decided what from which trusted facts, which boundary executed it, and whether the outcome is known.
What happens to one malicious instruction
Our first security tracer bullet is deliberately simple: a malicious document in the workspace instructs the Agent to read a credential outside the workspace and exfiltrate it.
No single classifier is expected to stop the attack. It crosses independent controls:
- the document and model output can express intent but cannot grant a wider data scope;
- Policy rejects the out-of-scope target or requires a new decision;
- even after an upstream mistake, Execution Environment blocks the external file access;
- the workload has neither raw credentials nor default network access;
- Broker will not issue a lease for an undeclared destination;
- Audit records the denial without copying document content, the path, or the secret.
The value comes from independence: no layer assumes that the previous one is always correct.
How the four concepts map to Open Nua
| Mental model | Owner in Open Nua | What the user sees |
|---|---|---|
| Trusted decision | Desktop Main / LocalExecutionPolicy | Three execution modes, HITL, scoped consent, stable reasons |
| Constrained execution | Local Runtime / ExecutionEnvironment | Workspace boundaries, no arbitrary network, cancellation and residue cleanup |
| Controlled external authority | Desktop + Gateway / CredentialBroker | No raw credentials; only approved services and paths |
| Minimal security evidence | Desktop, Gateway, Backend / SecurityAudit | Explainable security states, Admin aggregates, investigation, kill switch, and retention |
These modules are not an attempt to build a giant centralized Policy Service. They keep decision, execution, external authority, and evidence under clear owners. Browser, shell, Plugins, and a future Managed Runtime can use different adapters while preserving the same invariants.
Security is more than saying “we have a sandbox”
We use one machine-readable vector corpus across policy, the real local adapter, Gateway and Backend integration, and development Electron. Positive paths must still complete useful work. Malicious paths must fail at real boundaries. HITL races, replay, timeout, unknown outcomes, cancellation, and residue are security results, not merely reliability concerns.
This implementation belongs to the Open Nua Desktop 1.5 development line. It has completed security acceptance for the current macOS development architecture, cross-service path, and development product flow. That does not mean every platform, packaged candidate, or Managed Runtime has been verified. A platform without a real enforcement adapter must report unavailable instead of running with weaker protection.
We now ask five questions of any Agent system:
- Where does untrusted input lose the ability to grant authority?
- After allow, who proves that file, network, environment, and resource boundaries exist?
- Are credentials and external access still ambient authority?
- Is consent bound to identity, scope, version, and time?
- Does audit prove controls, or copy sensitive content?
When those questions have clear answers, Agent security stops being a collection of prompt rules and confirmation dialogs. It becomes a governed execution chain that can be implemented, tested, operated, and evolved.