I did this
This is a follow-up to 3e9817cd1b (2026-05-07, "url: remove ssh_config_matches"). Not a security report — I understand the documented rationale: host verification happens at connect time, the verified connection persists, use FORBID_REUSE if you need per-transfer checks. The design is coherent and the commit message explains it clearly.
The concern is narrower: CURLOPT_SSH_HOSTKEYFUNCTION. The SHA256/MD5/KNOWNHOSTS options are static values checked once against a host key — skipping them on reuse is fine, the host was already accepted. But CURLOPT_SSH_HOSTKEYFUNCTION is a callback. Callers set it to run active logic on each transfer: audit logging, TOFU state updates, revocation checks. On a reused connection the callback simply doesn't fire, and there is no signal in the return code that this happened — the transfer returns CURLE_OK and the caller has no way to know their callback was skipped.
Quick reproducer: two easies on one multi, same URL/user/password, only the SHA256 pin differs:
eA: CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256 = "gWi8KeA9...GMA" (correct)
eB: CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256 = "AAAABBBBCCCC...KKK" (wrong)
Run A to completion, remove from multi (keep conn in pool), add B, run B:
========== A: sftp://.../file1 fp=CORRECT ==========
* SHA256 checksum match
* Authentication complete
========== B: sftp://.../file2 fp=WRONG ==========
* Reusing existing sftp: connection with host 127.0.0.1
A: CURLE=0
B: CURLE=0 /file2 body: 'file2 contents'
No SHA256 fingerprint: line for B; the wrong pin sits unread in B.data->set.str[...]. Server log shows one TCP accept, one auth, two file opens. Same shape with _MD5, _KNOWNHOSTS, _AUTH_TYPES, and _HOSTKEYFUNCTION.
The doc update in c31fcf2dec reads like the single-handle "I changed my mind" scenario — the wording could be a bit sharper about multi-handle pools so callers who set CURLOPT_SSH_HOSTKEYFUNCTION for per-transfer side-effects know they need FORBID_REUSE. For the callback specifically, refusing reuse outright when either side has ssh_hostkeyfunc set would be the most conservative option and avoids needing any doc clarification.
I expected the following
docs are readable to coincide with the actual behavior
curl/libcurl version
master
operating system
all
I did this
This is a follow-up to
3e9817cd1b(2026-05-07, "url: remove ssh_config_matches"). Not a security report — I understand the documented rationale: host verification happens at connect time, the verified connection persists, useFORBID_REUSEif you need per-transfer checks. The design is coherent and the commit message explains it clearly.The concern is narrower:
CURLOPT_SSH_HOSTKEYFUNCTION. The SHA256/MD5/KNOWNHOSTS options are static values checked once against a host key — skipping them on reuse is fine, the host was already accepted. ButCURLOPT_SSH_HOSTKEYFUNCTIONis a callback. Callers set it to run active logic on each transfer: audit logging, TOFU state updates, revocation checks. On a reused connection the callback simply doesn't fire, and there is no signal in the return code that this happened — the transfer returnsCURLE_OKand the caller has no way to know their callback was skipped.Quick reproducer: two easies on one multi, same URL/user/password, only the SHA256 pin differs:
Run A to completion, remove from multi (keep conn in pool), add B, run B:
No
SHA256 fingerprint:line for B; the wrong pin sits unread inB.data->set.str[...]. Server log shows one TCP accept, one auth, two file opens. Same shape with_MD5,_KNOWNHOSTS,_AUTH_TYPES, and_HOSTKEYFUNCTION.The doc update in
c31fcf2decreads like the single-handle "I changed my mind" scenario — the wording could be a bit sharper about multi-handle pools so callers who setCURLOPT_SSH_HOSTKEYFUNCTIONfor per-transfer side-effects know they needFORBID_REUSE. For the callback specifically, refusing reuse outright when either side hasssh_hostkeyfuncset would be the most conservative option and avoids needing any doc clarification.I expected the following
docs are readable to coincide with the actual behavior
curl/libcurl version
master
operating system
all