Skip to content

autonomy(check-security-binding): static credential-root + egress-target validation cannot converge without a configured allowlist #549

Description

@kyle-sexton

Root cause (surfaced by PR #377 review loop)

plugins/autonomy/skills/setup/scripts/check-security-binding.mjs validates two open-ended input classes with static structural recognition and no configured allowlist:

  1. Credential probe paths (isCredentialTarget, ~L100-186) — must recognize whether a probed path is a real host credential location.
  2. Egress targets (isNonExternalEgressHost, ~L631-678) — must recognize whether a probed host is a provably external address (vs. a non-globally-routable / special-use address whose failed connection proves nothing).

Neither can be decided statically. A static checker with no config source can only pattern-match structure, so for each class the reviewer (chatgpt-codex-connector) can always construct a fresh input that is structurally plausible but semantically meaningless:

  • Credential side: an invented home-base path such as /home/definitely-not-a-host-user/.ssh passes (home is a home-base segment) while the real host credentials remain elsewhere and readable.
  • Egress side: each IANA/RFC special-use range must be denied one at a time. The bot has walked the registry across ~29 review cycles (loopback encodings, ::/96, IPv4-compat, 192.88.99.0/24 6to4, fec0::/10 site-local, 192.0.0.0/24 protocol-assignment, and now 100::/64 discard-only per RFC 6666), and unenumerated blocks remain (e.g. 64:ff9b::/96 NAT64, 3fff::/20 documentation).

This is not point-fixable. Each landed denial predictably spawns the next variant in the same class — an adversarial enumeration of an open-ended space, not a converging bug list. 42 findings across 28+ Codex review cycles on PR #377 are all instances of these two root causes.

Convergent fix (needs a human architecture decision)

Replace open-ended structural recognition with deny-by-default + configured allowlists, which the code comments and prior review replies already name as the deferred seam ("org-specific names belong to the future configured allow-list"):

  • Credential roots: accept a probe path as evidence only if it resolves under an operator-configured trusted credential root (e.g. a --credential-roots / config list). No configured root then no static acceptance.
  • Egress targets: accept a target as external-egress evidence only if it is on an operator-configured --egress-hosts allowlist (deny-by-default), rather than trying to enumerate every non-global range to reject.

Under a configured allowlist, both point-denial enumerations become superseded/throwaway, and the validator converges by construction.

Why this is filed rather than fixed inline

PR #377's babysit worker hit the non-convergence fix-round cap (~29 cycles, no realistic path to convergence via point-fixes). The two current-head P1 threads (commit 931771d, check-security-binding.mjs L184 credential path and L659 IPv6 discard-only) are left open and unresolved — they are valid but resolve to this single architectural decision, which a human must make. This issue captures that decision so the threads/PR are not point-fixed into a 30th cycle.

References


Reference: Boris Cherny, "Steps of AI Adoption" (Google Doc)

Metadata

Metadata

Assignees

Labels

priority: mediumReal value, no hard deadline; normal backlog flow.status: readyTriaged, unblocked, and fully specified; eligible to pick up.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions