Network permission rule sets never match; explicit permission objects also bypass the documented merge-over-default
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 4.6k
- Forks
- 251
- Avg merge
- 2d 15h
- Merged PRs (30d)
- 34
Description
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 documentedpatterns: ["api.example.com"]example). - Partial permission objects merge over the documented secure default, or the docs are corrected.
bindingauto-grant behavior is consistent between the no-permissions and explicit-permissions paths.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with agentos-core/dist/agent-os.js and the Core AgentOs.create() path. Run the supplied permission probe on the listed Node and macOS setup, comparing scope-allow, rules-exact-host, and deny-control. Done means matching network rules permit the connection and explicit permission policies have behavior consistent with the documented merge and binding auto-grant expectations, or the documentation clearly reflects the actual behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- node.js, typescript
- Domain
- networking, security
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100