Problem
A network permission rule set ({ default: 'deny', rules: [...] }) never allows anything — every outbound connection fails with EACCES even when a rule explicitly allows the host, while the plain scope string 'allow' works. This makes the documented per-host egress allowlist (the recommended posture for agent VMs) unusable:
ERR TypeError: fetch failed Error: EACCES: EACCES: permission denied,
tcp://api.openai.com:443: blocked by network.http policy
Reproduced on 0.2.15 and 0.2.16-rc.1, macOS arm64, Node 25, via the Core path (AgentOs.create(), no actor layer involved).
Reproduction
Exit codes: 42 = HTTP reached (any status), 43 = blocked.
import { AgentOs } from '@rivet-dev/agentos';
const PROBE = `fetch('https://api.openai.com/v1/models')
.then(() => process.exit(42)).catch(() => process.exit(43));`;
const CASES: [string, unknown][] = [
['scope-allow', 'allow'],
['rules-exact-host', { default: 'deny', rules: [{ mode: 'allow', patterns: ['api.openai.com'] }] }],
['deny-control', 'deny'],
];
for (const [name, network] of CASES) {
const vm = await AgentOs.create({
permissions: { fs: 'allow', childProcess: 'allow', process: 'allow', env: 'allow', binding: 'allow', network } as never,
});
await vm.filesystem.writeFile('/tmp/t.js', PROBE);
const r = await vm.process.exec('node /tmp/t.js', { captureStdio: true });
console.log(name, '→', r.exitCode);
await vm.dispose();
}
Observed:
scope-allow → 42 (reached)
rules-exact-host → 43 (blocked — should be 42)
deny-control → 43 (blocked, correct)
Also tried: patterns: ['api.openai.com:443'], patterns: ['*'], patterns: ['**'], explicit operations: ['fetch','http','dns','connect'] — all blocked identically.
Related: explicit permission objects skip the documented merge and the binding auto-grant
The permissions docs say a partial policy is "merged over a secure default" and that binding is auto-granted when bindings are registered. In agentos-core/dist/agent-os.js the actual behavior is wholesale replacement:
const hostPermissions = options?.permissions ?? { ...allowAll, binding: "allow" };
Any explicit permissions object replaces the default entirely — so { network: 'allow' } alone silently denies fs/childProcess/process/env, and registering bindings while passing any explicit policy leaves binding undefined→denied. Either the merge should be implemented as documented, or the docs should state replacement semantics.
Expected behavior
- A matching
mode: 'allow' rule permits the connection (at minimum for a bare-host pattern, per the documented patterns: ["api.example.com"] example).
- Partial permission objects merge over the documented secure default, or the docs are corrected.
binding auto-grant behavior is consistent between the no-permissions and explicit-permissions paths.
Problem
A
networkpermission rule set ({ default: 'deny', rules: [...] }) never allows anything — every outbound connection fails withEACCESeven when a rule explicitly allows the host, while the plain scope string'allow'works. This makes the documented per-host egress allowlist (the recommended posture for agent VMs) unusable:Reproduced on
0.2.15and0.2.16-rc.1, macOS arm64, Node 25, via the Core path (AgentOs.create(), no actor layer involved).Reproduction
Exit codes: 42 = HTTP reached (any status), 43 = blocked.
Observed:
Also tried:
patterns: ['api.openai.com:443'],patterns: ['*'],patterns: ['**'], explicitoperations: ['fetch','http','dns','connect']— all blocked identically.Related: explicit permission objects skip the documented merge and the
bindingauto-grantThe permissions docs say a partial policy is "merged over a secure default" and that
bindingis auto-granted when bindings are registered. Inagentos-core/dist/agent-os.jsthe actual behavior is wholesale replacement:Any explicit
permissionsobject replaces the default entirely — so{ network: 'allow' }alone silently deniesfs/childProcess/process/env, and registering bindings while passing any explicit policy leavesbindingundefined→denied. Either the merge should be implemented as documented, or the docs should state replacement semantics.Expected behavior
mode: 'allow'rule permits the connection (at minimum for a bare-host pattern, per the documentedpatterns: ["api.example.com"]example).bindingauto-grant behavior is consistent between the no-permissions and explicit-permissions paths.