Repository navigation
Umbrella: connector, credential and egress hardening (external-implementation comparison) #13623
Description
Activity
- 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 - added a commit that references this issue
on Aug 5, 2026 - added sub-issues
on Sep 1, 2026 - addedarea: secrets-egressWave 2 · cluster D — Secrets, credentials & egressWave 2 · cluster D — Secrets, credentials & egressumbrellaEpic/umbrella tracking issue grouping member issuesEpic/umbrella tracking issue grouping member issues
on Sep 1, 2026 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 explicitly28 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 client16 occurrences / 8 files httpx.<verb>(/AsyncClient(/Client(40 occurrences / 20 files aiohttp.ClientSession(direct30 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:384constructshttpx.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_HOSTSaturl_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.
- added sub-issues
on Sep 30, 2026
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
expires_inpermanently disables refreshget_access_tokencan lose a rotating refresh tokencreated_by;rotate()decrypts without attributionOAuthProvidertoo thin for real providersintegrations/bypasses the secrets manager entirely (also Umbrella/PRD: unify AutoBot secrets — one RBAC-governed store, vaults + one key abstraction (replaces 11 stores, 5 keys, 2 UIs) #10088 Task 5)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
resolve_forbidden_toolsreturns a barefrozenset[str]) belongs in security(agents): resolve_forbidden_tools fails open on unknown agent id — two disjoint id namespaces silently unbound an agent #13588/feat(agent-loop): agent cannot ask the user a question mid-task — the only human channel is a yes/no approval #13592 — the agent seam already suffers from having two policy paths, and adding a third mechanism is the same mistake. Noted here so it is not re-filed.resolve_forbidden_toolsreaches the same empty set from an unknown agent id. Same value, opposite intent, and no audit trail distinguishes them at runtime.Deliberately NOT proposed — do not re-file
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: ifservices/mcp_bridge_workersstarts federating third-party MCP servers and the aggregate tool count crosses a few hundred.Where we are already ahead (context for reviewers)
safe_aiohttp_resolverpins the socket to a pre-verified IP withuse_dns_cache=False, andpinned_request_with_redirectsbuilds 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.is_public_urlreturnsFalseon any resolution failure; the reference deliberately falls through to the transport.