Skip to content

guards(egress): guard_egress is opt-in at 28 of ~103 shared-client call sites — ruling needed on the default #17233

Description

@mrveiss

Owner ruling 2026-09-21: each default-off control gets its own ruling issue, with its blast
radius measured before the default is touched. This is the egress one.

Current state

guard_egress= is a per-call-site opt-in parameter, not a global default. It appears at 28
call sites
against ~103 shared-client callers, and a further ~51 files call
requests / httpx / aiohttp directly, bypassing the shared client entirely.

The guard itself is an address deny-list (loopback, link-local, cloud-metadata, reserved),
not a destination allow-list — so with the guard on, internal addresses are refused but
any public host is reachable.

Evidence: autobot_shared/http_client_manager.py:209-272.

Not every guard_egress=False is wrong. autobot-backend/llm_shared/pricing/live_sources.py:48
documents its own as deliberate — public addresses only, redirects refused — and that call site
is a reasonable exception. The defect is that the safe setting is the one you have to ask for.

Why the default matters here

A control that must be requested protects only the call sites whose author knew to request it.
The 28/103 ratio is the measurement of that gap, and the ~51 direct-library callers are outside
the mechanism altogether — flipping the default does nothing for them.

Acceptance criteria

  • Blast radius measured before any default changes: for each of the ~103 shared-client
    callers, whether it would still function with the guard on, and which of the 28 existing
    False sites are deliberate exceptions like the pricing one.
  • A ruling is recorded: default-on, or documented as deliberately advisory. Not left implicit.
  • If default-on: every deliberate exception passes guard_egress=False explicitly with a
    comment saying why, so the exception is visible at the call site.
  • The ~51 direct requests/httpx/aiohttp callers are counted and tracked — flipping the
    shared-client default does not reach them, and a ruling that ignores them overstates its own
    coverage. File separately if out of scope here.
  • Guard distinguishes no unguarded callers from could not enumerate callers.

Related

Activity

  1. added this to the v0.10.0 milestone on Sep 21, 2026
  2. mrveiss commented on Sep 22, 2026

    @mrveiss
    OwnerAuthor

    Adjacent finding while auditing the LLM provider layer, filed separately as #17249 rather than folded in here, because it sits outside this issue's measured population.

    This issue counts guard_egress across the ~103 shared-client callers and the ~51 direct requests/httpx/aiohttp callers. There is a third bucket: subsystems that reach the network through a vendor SDK, which never touch the shared client at all, so whatever ruling lands here does not reach them.

    grep -rn 'guard_egress' autobot-backend/llm_shared/providers/ → 0 hits. OpenAICompatibleProvider._create_client (autobot-backend/llm_shared/providers/openai_compatible.py:96-98) hands base_url to the SDK, which owns the socket. CustomOpenAIProvider._resolve_base_url (custom_openai.py:54-60) resolves that host from CUSTOM_OPENAI_BASE_URL — operator-supplied stored config, i.e. exactly the Rule 8 trigger — and the request never reaches _assert_egress_allowed.

    Noting it here only so the blast-radius measurement in this issue's first acceptance criterion is not read as covering the LLM path. It does not.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions