Skip to content

Umbrella: connector, credential and egress hardening (external-implementation comparison) #13623

Description

@mrveiss

Review of an external connector-gateway implementation covering the same problem domain (credential custody, provider egress, agent-facing action catalog), compared line-by-line against ours. Full audit in docs/research/connector-credential-egress-audit.md.

Comparing our connector/credential/egress layer against an implementation built for the same job at roughly 100x the provider count surfaced two live bugs, two fail-open guards, and five structural gaps. Every item below cites a file read, not a filename guess.

Two were found by reading the reference implementation's own code comments — that codebase had already hit the bug and recorded why the obvious fix is also wrong. We have the same bug.

Task tree

Sequencing

Security first (children 1-5), then capability (6-8). Child 9 is a decision for the owner and blocks nothing.

#13643 is the platform rule, not a one-off fix: anywhere credentials or connectors are used, they go through the canonical secrets manager — one framework for passing credentials to modules, agents and users under grant, audit and revocation. It belongs to #10088 Task 5 and is cross-filed here because it lands in the same files as #13629/#13630.

Folded into existing work, not filed separately

Deliberately NOT proposed — do not re-file

  • Progressive tool discovery / search-then-execute. The reference fronts a ~10,000-action catalog with a handful of search/read/execute tools, and it is the most elegant idea in it. We have ~40 tools (autobot-backend/tools/tool_registry.py:849-894); the whole manifest fits in context. Adopting it would buy nothing and cost an extra LLM round trip per tool use plus a new failure mode (search misses a tool and the agent cannot know what it did not see). Revisit trigger: if services/mcp_bridge_workers starts federating third-party MCP servers and the aggregate tool count crosses a few hundred.
  • A provider-catalog generator / mass provider onboarding. That very large provider set ships with no provider-level regression tests in its open repository, by explicit policy. Twelve tested connectors with checkpointing, change detection, and config migration are worth more to a KB-ingesting system than 1,270 untested ones.
  • Adopting an external gateway as a runtime dependency. A second gateway process, credential store, and policy model is a net loss for a system that needs roughly a dozen integrations.

Where we are already ahead (context for reviewers)

  • DNS-rebind defence is real, not advisory. safe_aiohttp_resolver pins the socket to a pre-verified IP with use_dns_cache=False, and pinned_request_with_redirects builds a fresh pinned connector per hop. The reference cannot do this at all — connection pinning is not expressible over the fetch API it is built on.
  • Fail-closed DNS. is_public_url returns False on any resolution failure; the reference deliberately falls through to the transport.
  • Auth is a different class of system. The reference is admin token + runtime tokens, single operator, no multi-user RBAC. We have full user management, SSO/SCIM, per-user RBAC, run-JWT scopes, pre-auth throttling, constant-time comparison.

Activity

  1. changed the title [-]Umbrella: connector, credential and egress hardening (research: open-connector comparison)[/-] [+]Umbrella: connector, credential and egress hardening (external-implementation comparison)[/+] on Aug 5, 2026
  2. added
    area: secrets-egressWave 2 · cluster D — Secrets, credentials & egress
    umbrellaEpic/umbrella tracking issue grouping member issues
    on Sep 1, 2026
  3. modified the milestones: Backlog, v0.11.0 on Sep 12, 2026
  4. mrveiss commented on Sep 21, 2026

    @mrveiss
    OwnerAuthor

    Measured egress-guard coverage while reviewing the platform's regulated-readiness posture. Counts for this umbrella, non-test, excluding venv/, node_modules/, __pycache__/:

    Measure Count
    guard_egress= passed explicitly 28 call sites (only 2 with True, the private-network opt-in)
    Shared pooled client call sites ~103 (per autobot_shared/http_client_manager.py:229-243, which documents the guard as "deliberately opt-in rather than default-on")
    requests.<verb>( outside the shared client 16 occurrences / 8 files
    httpx.<verb>( / AsyncClient( / Client( 40 occurrences / 20 files
    aiohttp.ClientSession( direct 30 occurrences / 24 files (2 are the guard's own internals)
    Union bypassing the guarded client 51 distinct files, 86 call sites

    One example worth its own look: autobot-backend/services/autoresearch/osint_engine.py:384 constructs httpx.AsyncClient(follow_redirects=True) and sweeps arbitrary discovered URLs with no SSRF check.

    Policy shape, for the record: the guard is an address deny-list, not a destination allow-list. Loopback / link-local / metadata ranges are hard-blocked (autobot_shared/url_safety.py:108-124) and RFC-1918 is blocked unless opted in, but any public host is reachable by default. The one true allow-list is OAuth-specific — _DEFAULT_OAUTH_ALLOWED_HOSTS at url_safety.py:49-62.

    The SSRF engineering itself is good — DNS-rebind-safe pinning, redirect re-validation, credential-header stripping across cross-origin redirects (ssrf_guard.py:139-216). The gap is coverage, not quality.

    Filed adjacent under umbrella #17217 (declared controls that do not execute); recording the counts here rather than opening a duplicate, since this umbrella already owns the scope.

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