checkAgentEndpoint decides whether this deployment is willing to dial an address. Both places that dial one then hand the URL to a fetch that follows redirects, so the address that was checked and the address that is reached are the same address only while nobody redirects.
A registrable agent at a public URL answering 307 Location: http://169.254.169.254/latest/meta-data/ puts the server on its own cloud metadata endpoint, which checkAgentEndpoint refuses under every configuration when asked directly.
Verified at main 06a1a84. A local server returning a 307 to a second server got the second server hit, and testAgentConnection returned ok: true for the redirected run. Pointing the same redirect at 169.254.169.254 came back 405, which is what this host's own metadata service answers a POST with (curl -X POST http://169.254.169.254/latest/meta-data/ returns 405 and GET / returns 404 here), so the request reached it.
Two call sites, and the second is the more serious:
server/src/agents/connection-test.ts:100 runs once, when somebody registers an endpoint.
server/src/copilot.ts:239 builds the HttpAgent every run dials. It gets the stored URL and either the runtime's own fetch or the stall-guard wrapper, neither of which constrains redirects, and it carries whatever auth header the registration supplied. An endpoint that passed review can start redirecting afterwards, and nothing looks again.
A PR follows. It applies the check to each hop rather than only the first, capped at three. Redirects are followed rather than refused, since a deployment putting its agent behind one has done nothing wrong and http to https is ordinary; each destination has to pass the same check, so following one can only reach somewhere registering it directly would have reached.
Worth stating plainly, since the fix does not close it: the check is by hostname, so a name that passes and then resolves to a private address between the check and the connection still gets through. Refusing redirects would not close that either.
checkAgentEndpointdecides whether this deployment is willing to dial an address. Both places that dial one then hand the URL to a fetch that follows redirects, so the address that was checked and the address that is reached are the same address only while nobody redirects.A registrable agent at a public URL answering
307 Location: http://169.254.169.254/latest/meta-data/puts the server on its own cloud metadata endpoint, whichcheckAgentEndpointrefuses under every configuration when asked directly.Verified at
main06a1a84. A local server returning a 307 to a second server got the second server hit, andtestAgentConnectionreturnedok: truefor the redirected run. Pointing the same redirect at169.254.169.254came back 405, which is what this host's own metadata service answers a POST with (curl -X POST http://169.254.169.254/latest/meta-data/returns 405 andGET /returns 404 here), so the request reached it.Two call sites, and the second is the more serious:
server/src/agents/connection-test.ts:100runs once, when somebody registers an endpoint.server/src/copilot.ts:239builds theHttpAgentevery run dials. It gets the stored URL and either the runtime's own fetch or the stall-guard wrapper, neither of which constrains redirects, and it carries whatever auth header the registration supplied. An endpoint that passed review can start redirecting afterwards, and nothing looks again.A PR follows. It applies the check to each hop rather than only the first, capped at three. Redirects are followed rather than refused, since a deployment putting its agent behind one has done nothing wrong and
httptohttpsis ordinary; each destination has to pass the same check, so following one can only reach somewhere registering it directly would have reached.Worth stating plainly, since the fix does not close it: the check is by hostname, so a name that passes and then resolves to a private address between the check and the connection still gets through. Refusing redirects would not close that either.