Skip to content

feat: add interactive network approval and domain rejection#698

Open
klassm wants to merge 91 commits into
nolabs-ai:mainfrom
klassm:network_permission_handling
Open

feat: add interactive network approval and domain rejection#698
klassm wants to merge 91 commits into
nolabs-ai:mainfrom
klassm:network_permission_handling

Conversation

@klassm

@klassm klassm commented Apr 17, 2026

Copy link
Copy Markdown
Contributor

When a sandboxed process requests access to a blocked host, the user is now prompted via an OS dialog to approve or deny the request. Approved hosts are allowed for the session; optionally persisted to the active profile for permanent access.

  • OS-native dialogs: macOS (choose from list), Linux (notify-rust with XDG action buttons), Windows (PowerShell WPF dialog)
  • Four choices: Allow once, Always allow, Deny once, Always deny
  • Always allow/deny persists the decision to the profile config file
  • New reject_domain config field with wildcard support (e.g. *.ad.com) takes priority over allow_domain, enabling explicit host blacklisting
  • Approval is off by default; opt in via --network-approval ask, NONO_NETWORK_APPROVAL=ask, or approval_mode in config/profile

@klassm klassm force-pushed the network_permission_handling branch from db2ec7c to 29e89e2 Compare April 17, 2026 19:17

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a network approval feature, allowing users to interactively approve or deny network requests to unknown hosts via OS-level notifications. The implementation includes cross-platform support (Linux, macOS, Windows), a runtime-mutable host filter, and persistence logic for user decisions. I have identified several issues: the approval backend creates a new Tokio runtime on every call, which is inefficient; persistence errors are handled inconsistently; JSON manipulation in the config writer is prone to panics; and the timeout logic is missing or ignored in the notification backends.

Comment thread crates/nono-cli/src/network_approval.rs Outdated
Comment thread crates/nono-cli/src/network_approval.rs
Comment thread crates/nono-cli/src/network_approval.rs
Comment thread crates/nono-cli/src/notification/linux.rs Outdated
Comment thread crates/nono-cli/src/notification/macos.rs
@klassm klassm force-pushed the network_permission_handling branch from 29e89e2 to 2282f15 Compare April 17, 2026 19:30
@klassm

klassm commented Apr 17, 2026

Copy link
Copy Markdown
Contributor Author

All review comments done. Would be cool to have this - this makes maintaining the allow list a lot easier.

@lukehinds

Copy link
Copy Markdown
Contributor

This is a really good idea @klassm - I am away this weekend, but will take a good look first thing Monday - out of interest , it might be good to rig this up to the Approval backend on linux (unless you already have), but that could be a follow up patch.

@klassm

klassm commented Apr 20, 2026

Copy link
Copy Markdown
Contributor Author

Great, thanks @lukehinds :-). Approval backend on linux also sounds nice - I would not do it directly, though. I don't have a Linux system, so that's hard to test :-)

@tho

tho commented Apr 20, 2026

Copy link
Copy Markdown

Interesting feature! One small UX thought: "allow once" might be ambiguous since it actually allows for the whole session, not just a single request. Maybe something like:

  1. [Allow/Deny] once (single request)
  2. [Allow/Deny] session
  3. [Allow/Deny] always (persist to profile)

Also, what do you think about a dropdown with those three options plus Allow/Deny buttons instead of four (or more) separate buttons?

@klassm klassm force-pushed the network_permission_handling branch 3 times, most recently from f2586e1 to 10c4c23 Compare April 20, 2026 15:53
@klassm

klassm commented Apr 20, 2026

Copy link
Copy Markdown
Contributor Author

@tho I changed the buttons to distinguish between once, session and always.
For MacOS you get a dropdown, for Windows I guess as well. For Linux I did not figure out how to do that.

@klassm klassm force-pushed the network_permission_handling branch 2 times, most recently from 1bb15a3 to 273f6a7 Compare April 20, 2026 15:58
@klassm

klassm commented Apr 21, 2026

Copy link
Copy Markdown
Contributor Author

@lukehinds Did you have a chance to have a look again? 😇

@klassm klassm force-pushed the network_permission_handling branch 2 times, most recently from 3ec989e to 8912421 Compare April 24, 2026 07:14
@lukehinds

Copy link
Copy Markdown
Contributor

hi @klassm , I have and I promise I am keeping an eye on this, its just a big change which commits a lot to the supervisor backend arch, so i need to make sure its malable to other planned changes.

@klassm klassm force-pushed the network_permission_handling branch from 8912421 to 170d100 Compare April 27, 2026 13:08
@klassm klassm force-pushed the network_permission_handling branch 3 times, most recently from 82926e1 to 6b1d919 Compare May 9, 2026 16:03
@klassm klassm force-pushed the network_permission_handling branch from 6b1d919 to fc7b7e9 Compare May 28, 2026 06:40
@github-actions

github-actions Bot commented May 28, 2026

Copy link
Copy Markdown
Contributor

PR Review Summary

Size

Metric Value
Lines added +15116
Lines removed -3254
Total changed 18370
Classification Large (> 300 lines)

Affected crates

  • crates/nono (core library) — careful review required. This is the security-critical sandbox primitive. A bug here bypasses OS-level isolation for every downstream user.
  • crates/nono-proxydownstream consumers depend on this crate. API or behaviour changes will affect external callers; treat any breaking change with extra scrutiny.
  • crates/nono-cli — CLI changes. Verify argument parsing, flag documentation, and UX behaviour across supported platforms.
  • bindings/c (C FFI) — ABI changes can silently break C callers. Confirm header and symbol compatibility.

Blast radius — Broad

This PR touches: source code,documentation,CI / build tooling,configuration / policy files


Updated automatically on each push to this PR.

connrg and others added 28 commits July 3, 2026 09:53
The page opened straight on the proxy modes table, so the commands most people actually want — allow a domain, block the net, inject a key — were buried halfway down. Pull them up into a short "Common cases" block at the top.

Signed-off-by: connrg <conor@alwaysfurther.ai>
…-ai#1177)

The custom_credentials schema table linked the `proxy` field to
#proxy-side-overrides, but the section heading is "Proxy Overrides"
(#proxy-overrides). The link resolved to nothing. Point it at the
correct anchor and match the link text to the heading.

Signed-off-by: connrg <conor@alwaysfurther.ai>
…ns (nolabs-ai#1163)

Delay version-update PRs until dependencies are at least three days old,
reducing the risk of pulling a freshly compromised release into a tagged
build. Security updates are unaffected and still bypass cooldown.

Signed-off-by: Aleksy Siek <aleksy@alwaysfurther.ai>
--allow-cwd doesn't always grant read+write. The access level comes from
the active profile's workdir setting, defaulting to read-only when no
profile sets one, and granting nothing under the default profile
(workdir "none").

The Developer Workflows guide claimed it always grants read+write, which
only holds for readwrite profiles and contradicts the flag reference.
Align the guide with it and note the none case on the Working Directory
section.

Signed-off-by: connrg <conor@alwaysfurther.ai>
Bumps [which](https://github.com/harryfei/which-rs) from 8.0.2 to 8.0.3.
- [Release notes](https://github.com/harryfei/which-rs/releases)
- [Changelog](https://github.com/harryfei/which-rs/blob/master/CHANGELOG.md)
- [Commits](harryfei/which-rs@8.0.2...8.0.3)

---
updated-dependencies:
- dependency-name: which
  dependency-version: 8.0.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [cbindgen](https://github.com/mozilla/cbindgen) from 0.29.3 to 0.29.4.
- [Release notes](https://github.com/mozilla/cbindgen/releases)
- [Changelog](https://github.com/mozilla/cbindgen/blob/main/CHANGES)
- [Commits](mozilla/cbindgen@0.29.3...0.29.4)

---
updated-dependencies:
- dependency-name: cbindgen
  dependency-version: 0.29.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…1173)

* fix(policy) Allow go_runtime to readwrite go-build cache

Signed-off-by: Raphael Nestler <raphael.nestler@renuo.ch>

* Also add macOS go build cache

Signed-off-by: Raphael Nestler <raphael.nestler@renuo.ch>

* fix(policy): split go_runtime cache into platform-specific groups

Extract the go build cache paths from go_runtime into separate
go_runtime_linux and go_runtime_macos groups, each gated by their
respective platform field. This ensures only the correct cache path
(~/.cache/go-build vs ~/Library/Caches/go-build) is granted per OS.

Signed-off-by: Aleksy Siek <aleksy@alwaysfurther.ai>

---------

Signed-off-by: Raphael Nestler <raphael.nestler@renuo.ch>
Signed-off-by: Aleksy Siek <aleksy@alwaysfurther.ai>
Co-authored-by: Aleksy Siek <aleksy@alwaysfurther.ai>
…abs-ai#1048) (nolabs-ai#1091)

The TLS intercept upstream leg (used for credential injection) always
connected directly to the target host, ignoring the configured
upstream_proxy / external_proxy. In enterprise environments where the
target is only reachable through a corporate proxy, this caused the
intercepted request to hang or fail.

- Added InterceptUpstreamProxy struct and upstream_proxy field to
  InterceptCtx so the intercept code can select
  UpstreamStrategy::ExternalProxy when a proxy is configured.
- server.rs now checks the bypass matcher and passes the resolved
  proxy info into InterceptCtx, mirroring the existing transparent
  CONNECT path.
- Auth-not-implemented check (config.auth.is_some()) fails early
  and consistently with the external proxy handler.
- 3 unit tests for strategy selection (ExternalProxy vs Direct).

Signed-off-by: Caio Silva <caio@cdcs.dev>
Co-authored-by: Luke Hinds <lukehinds@gmail.com>
Co-authored-by: Aleks <121458075+SequeI@users.noreply.github.com>
…l catch-all (nolabs-ai#1132)

* fix(proxy): stop _ep_ route from shadowing credential catch-all

A credential catch-all (custom_credentials with no endpoint_rules) was
shadowed by a credential-less _ep_ endpoint-authorization route on the
same upstream: on a path the _ep_ route authorized, selection picked the
credential-less _ep_ match ahead of the catch-all and forwarded the
request without injecting the managed credential.

Partition candidate routes into four buckets (matched_cred,
matched_passthrough, catchall_cred, catchall_passthrough). The active
credential layer is matched_cred when any credential route matched,
otherwise catchall_cred, so a credential catch-all stays in play when only
credential-less _ep_ routes matched. Selection then prefers, in order:
(1) the single credential route from the active layer, (2) a matched
credential-less route (bare endpoint authorization), (3) a credential-less
catch-all (passthrough). This injects the token on authorized paths instead
of dropping it, and also makes two credential catch-alls for one upstream
ambiguous (403) rather than a silent pick. The _ep_ hard-deny gate is
unchanged, so non-matching paths are still hard-denied (default-deny
preserved) and the host gate is untouched.

Extract the selection logic (gate + ambiguity + priority) from
tls_intercept/handle.rs into select_route + RouteSelection in route.rs so
the decision has a single source of truth shared with its unit tests; the
prior test was a hand-copied mirror that did not model the _ep_ gate.
Derive Default on RouteConfig so test fixtures can use ..Default::default()
(no serde change: prefix/upstream remain required on deserialize).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Leonardo Zanivan <leonardo.zanivan@gmail.com>

* chore: trigger CI

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Leonardo Zanivan <leonardo.zanivan@gmail.com>

---------

Signed-off-by: Leonardo Zanivan <leonardo.zanivan@gmail.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Luke Hinds <lukehinds@gmail.com>
Co-authored-by: Aleks <121458075+SequeI@users.noreply.github.com>
* refactor(audit): move attestation logic to core library

Move audit attestation signing and verification implementation
from `nono-cli` into the `nono` core library.

- Consolidate `AuditAttestationVerificationResult` struct,
  `AuditAttestationPredicate` structs, and related constants.
- Extract `write_audit_attestation` and `verify_audit_attestation`
  implementations into new `sign_audit_attestation_bundle` and
  `verify_audit_attestation_bundle` functions in `nono::audit`.
- `nono-cli` now serves as a thin wrapper around these core functions.

This change centralizes the core logic, making it reusable and
improving the separation of concerns between the CLI and library.

Signed-off-by: Luke Hinds <lukehinds@gmail.com>

* refactor(audit): improve attestation statement parsing

Streamlines the `extract_audit_attestation_statement` function by
directly accessing the DSSE envelope from the Sigstore bundle's `content`
field. This eliminates redundant JSON serialization and deserialization
steps, making the extraction process more efficient and leveraging the
`SignatureContent` enum.

The `zeroize::Zeroizing` wrapper is also removed from `scrubbed_command`.
Command arguments are not treated as sensitive secrets requiring zeroization.

Signed-off-by: Luke Hinds <lukehinds@gmail.com>

---------

Signed-off-by: Luke Hinds <lukehinds@gmail.com>
Co-authored-by: Aleks <121458075+SequeI@users.noreply.github.com>
…-ai#1178)

* feat(output): show blocked macos grants in capability summary

Previously, macOS user-granted paths that were silently blocked by deny groups were logged as individual warnings. This could lead to a large number of warnings when a broad user grant (e.g., `~/Library`) overlapped with multiple deny groups.

This commit refactors the logic to collect these blocked grants and present them in the capability summary. The new display is collapsed into a single line by default, indicating the number of paths blocked. Using the `-v` (verbose) flag expands the summary to list each specific path and the deny rule that blocks it, along with a hint about how to use `--bypass-protection`. This significantly improves readability and user experience by folding multiple related warnings into a concise summary.

Signed-off-by: Luke Hinds <lukehinds@gmail.com>

* refactor(output): improve path display and string allocations

- Use `Path::to_string_lossy` for displaying paths in `print_blocked_grants`. This provides more robust handling of non-UTF-8 characters and avoids unnecessary `String` allocations compared to `Path::display().to_string()`.
- Optimize string handling when grouping blocked grants by deferring `.to_string()` calls until group names are inserted into the `groups` vector, reducing temporary allocations.
- Reorder test module imports in `output.rs` for minor style consistency.

Signed-off-by: Luke Hinds <lukehinds@gmail.com>

---------

Signed-off-by: Luke Hinds <lukehinds@gmail.com>
Signed-off-by: Aleksy Siek <aleksy@alwaysfurther.ai>
* fix(cli): use XDG config paths consistently

Route user config (config.toml, trusted-keys cache) through
resolve_user_config_dir() instead of dirs::config_dir(), so macOS
matches ~/.config/nono like profiles and packages already did.

Add $NONO_CONFIG profile expansion, display path helpers for CLI
output, and update schema/docs/scripts to prefer XDG variables in
machine-readable paths while keeping ~/.config/nono in user-facing
docs and --help.

Signed-off-by: Aleksy Siek <aleksy@alwaysfurther.ai>

* fix

Signed-off-by: Aleksy Siek <aleksy@alwaysfurther.ai>

---------

Signed-off-by: Aleksy Siek <aleksy@alwaysfurther.ai>
* AWS: Implement aws_auth config

This adds the aws_auth struct to customCredentials, with optional
subkeys: profile, region, and service. If the aws_auth subkey is present
at all, the route will be signed with AWS credentials in the future

The subkey is mutually exclusive with credential_key and auth.

The routes with aws_auth are wired through to the proxy, where a 501 not
implemented is returned for any route using the config

Signed-off-by: Anil Kulkarni <anil@terminal.space>

* PR feedback

Signed-off-by: Anil Kulkarni <anil@terminal.space>

---------

Signed-off-by: Anil Kulkarni <anil@terminal.space>
This function does many different things, from parsing the body headers,
choosing what config matches the route, handling the implementation, and
logging/auditing.

Splitting this into helper functions is better for readability, scope
of purpose, and will make the future aws auth implementation easier to
implement

Signed-off-by: Anil Kulkarni <anil@terminal.space>
* Create failing tests for the proxy activating under the presence of customCredentials

Signed-off-by: Anil Kulkarni <anil@terminal.space>

* Ensure the proxy starts when customCredentials are passed in by itself

Signed-off-by: Anil Kulkarni <anil@terminal.space>

---------

Signed-off-by: Anil Kulkarni <anil@terminal.space>
* feat(update-check): discover ci environments on update

The update check now includes a coarse classification of the CI environment.
This helps us understand how nono well (or not) recent versions are used in automated
workflows versus local development.

- Detection relies solely on well-known environment variable names (e.g., GITHUB_ACTIONS, CI).
- Raw environment variable values are never collected or transmitted.
- The update service's privacy assurances remain unchanged: no personally identifiable information is collected.
- Updated the `test-update-server.py` script to log the new CI fields.

Signed-off-by: Luke Hinds <lukehinds@gmail.com>

* refactor(update_check): simplify ci environment detection

The `CiEnvironment` struct has been removed to streamline the representation of CI detection.

The `detect_ci_environment` function has been renamed to `detect_ci_provider` and now directly returns an `Option<&'static str>` representing the detected CI provider. This simplifies the API by removing the need for an explicit `is_ci` boolean, as its presence can be inferred from `ci_provider.is_some()`.

New tests have been added to:
- Ensure that environment variables with "falsey" values (e.g., empty string, "0") do not inadvertently trigger CI detection.
- Validate that no CI is detected when no relevant environment variables are present.

Signed-off-by: Luke Hinds <lukehinds@gmail.com>

---------

Signed-off-by: Luke Hinds <lukehinds@gmail.com>
Co-authored-by: Aleks <121458075+SequeI@users.noreply.github.com>
…clients (nolabs-ai#1171)

* feat(diagnostics): expose structured diagnostics for library and FFI clients

Add stable diagnostic codes, remediations, and session reports in nono and
nono-proxy; render CLI footers from structured data with --diagnostics-json.
Extend C FFI with diagnostic codes and JSON helpers. Refactor diagnostic
module and ignore local diagnostics.json output.

Signed-off-by: Aleksy Siek <aleksy@alwaysfurther.ai>

* fix: review fix + deduplicate oauth block

Signed-off-by: Aleksy Siek <aleksy@alwaysfurther.ai>

* fix: review comments

Signed-off-by: Aleksy Siek <aleksy@alwaysfurther.ai>

---------

Signed-off-by: Aleksy Siek <aleksy@alwaysfurther.ai>
* fix(pty): suspend Ctrl-Z manually in orphaned PTY sessions (nolabs-ai#989)

setsid() in setup_child_pty orphans the child process group, preventing
kernel delivery of SIGTSTP. PtyProxy now intercepts Ctrl-Z (0x1A), sends
uncatchable SIGSTOP to the child, restores terminal, then SIGTSTP-stops
nono. On fg: raw mode restored, SIGCONT + SIGWINCH forwarded.

Signed-off-by: Caio Silva <caio@cdcs.dev>

* fix(pty): retry suspension waitpid on EINTR

Signed-off-by: Caio Silva <caio@cdcs.dev>

* fix(pty): send SIGWINCH to the foreground process group on resume

Signed-off-by: Caio Silva <caio@cdcs.dev>

* refactor(pty): expose PTY master fd through a getter

Signed-off-by: Caio Silva <caio@cdcs.dev>

* fix(pty): detect CSI-u Ctrl-Z and handle nested jobs

TUI apps using the kitty keyboard protocol (opencode/opentui) send Ctrl-Z
as a CSI-u escape (\x1b[122;5u or \x1b[90;5u) rather than raw 0x1A. Detect
both for terminal clients by reusing the existing enhanced-key matcher
(control_key_candidates(0x1a) is already [90, 122]); socket-client detach
behavior is unchanged.

Distinguish nested jobs from the orphaned direct child in
handle_pty_suspension: a nested job (e.g. vim under bash -i) is not
orphaned, so forward a plain SIGTSTP and let the inner shell drive
suspend/resume; only the direct child gets the manual SIGSTOP + self-suspend
dance. This fixes a hang where waitpid() blocked on a stopped process that
was not nono's child.

On resume, repaint the alternate screen from nono's captured vt100 state
(mirroring the client re-attach replay) instead of emitting a bare
alt-screen-enter and relying on SIGWINCH, which opencode ignores. Use the
clearing terminal restore on suspend so repeated Ctrl-Z/fg cycles do not
accumulate cursor drift on the normal screen.

Signed-off-by: Caio Silva <caio@cdcs.dev>

---------

Signed-off-by: Caio Silva <caio@cdcs.dev>
Co-authored-by: Luke Hinds <lukehinds@gmail.com>
* refactor(proxy): separate proxy intent from activation

Replace the flat `ProxyLaunchOptions` struct with focused intent structs:
`DomainFilterIntent`, `EndpointFilterIntent`, `CredentialProxyIntent`,
`UpstreamProxyIntent`, `TlsInterceptIntent`, and `OpenUrlIntent`.

Remove the stored `active: bool` field. Proxy activation is now derived
via `is_active()`, which returns true when any activating intent struct
is `Some`. `WithEndpoints` allow-domain entries are split from plain
CONNECT-tunnel entries at prepare time, making the TLS-intercept
requirement explicit in the type.

Infra-only flags (`--proxy-port`, `--proxy-ca-validity`, `--trust-proxy-ca`)
now return an error if used without an activating proxy feature instead
of silently doing nothing.

Signed-off-by: Aleksy Siek <aleksy@alwaysfurther.ai>

* fix: review comments

Signed-off-by: Aleksy Siek <aleksy@alwaysfurther.ai>

* cargo fmt

Signed-off-by: Aleksy Siek <aleksy@alwaysfurther.ai>

---------

Signed-off-by: Aleksy Siek <aleksy@alwaysfurther.ai>
Signed-off-by: Aleksy Siek <aleksy@alwaysfurther.ai>
…ials (nolabs-ai#1215)

* make custom credentials require explicit activation

refactor(credentials): require explicit activation for custom credentials

Previously, merely defining custom credentials in a profile would cause them to be automatically activated, leading to the creation of routes and the proxy becoming active even if no services explicitly requested credentials.

This change modifies the behavior of `resolve_credentials` and `prepare_proxy_launch_options` to treat custom credentials as definitions or templates. They must now be explicitly listed in the `credentials` section of a policy to be enabled. This aligns their behavior with other credential types, ensuring that the proxy and routes are only activated when genuinely needed.

- Custom credential definitions no longer implicitly activate routes.
- The proxy will not activate solely due to the presence of custom credential definitions.

Fixes: nolabs-ai#1214

Signed-off-by: Luke Hinds <lukehinds@gmail.com>

* fix(proxy): correct proxy active state for custom credentials

When defining custom credential sources for a proxy, the `is_active` method would previously evaluate to true if a `CredentialProxyIntent` was present, even if that intent contained an empty list of actual login credentials. This incorrectly suggested the proxy was "active" for traffic authentication.

This change updates the `is_active` logic to only return true when explicit login credentials are provided. It also ensures that `CredentialProxyIntent` is always constructed and carried forward if custom credential definitions are specified, enabling network profile overrides even when no actual authentication credentials are required.

- update `is_active` to check for non-empty credential list
- ensure `CredentialProxyIntent` carries custom definitions regardless of login credentials
- add test to confirm custom credentials are carried but do not activate proxy

Signed-off-by: Luke Hinds <lukehinds@gmail.com>

---------

Signed-off-by: Luke Hinds <lukehinds@gmail.com>
- Deny/Approve buttons with Once/Session/Always duration dropdown
- Blacklist (reject_domain) hosts auto-denied without prompting
- Once approval bypasses runtime filter re-check
- Deny(Session/Always) adds to runtime deny filter and persists
- Tests for filter blacklist, deny scope, approval scope
The ConfigWriter was using network_profile (a network policy field)
to determine which profile file to write persisted hosts to. When
network_profile was None (the default), it fell back to writing to
'default' profile — but 'default' is never loaded on restart unless
the user explicitly runs --profile default.

Now ProxyLaunchOptions carries profile_name (from --profile CLI
arg). ConfigWriter uses this to write to the correct user profile
file (e.g., ~/.config/nono/profiles/claude-code.json) that will be
loaded on the next restart.

Signed-off-by: klassm <klassm@users.noreply.github.com>
…r rebase

The merge conflicts reverted two security fixes:

1. connect.rs: Both primary and runtime filter checks now short-circuit
   on DenyLinkLocal in addition to DenyHost, preventing cloud metadata
   SSRF via DNS rebinding from reaching the approval dialog.

2. types.rs: NetworkApprovalDecision::is_denied() now includes the
   Timeout variant, so timeout is correctly treated as a denial.

Signed-off-by: klassm <klassm@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.