new file mode 100644
@@ -0,0 +1,258 @@
+From 1bdb3dbcc85bd754b8f5af73159decd926a0b7a4 Mon Sep 17 00:00:00 2001
+From: Daniel Stenberg <daniel@haxx.se>
+Date: Fri, 12 Jun 2026 09:01:22 +0200
+Subject: [PATCH] config2setopts: use default protocol properly
+
+Verified by test 1724, 1725 and 2036
+
+Closes #21983
+
+CVE: CVE-2026-12064
+Upstream-Status: Backport [https://github.com/curl/curl/commit/ab3bb8cd8be8f9d4acb97da0418abc279182041e]
+
+Backport Changes:
+- Adapt the config2setopts.c change to curl 8.7.1's equivalent url_proto()
+ implementation in tool_operate.c. Since CURLU_NO_GUESS_SCHEME is not
+ available, parse without scheme guessing when --proto-default is set and
+ use the configured default only when the URL has no explicit scheme.
+- Preserve upstream error handling by propagating CURLUE_OUT_OF_MEMORY from
+ both curl_url_set() and curl_url_get() as CURLE_OUT_OF_MEMORY.
+- Register the regression tests in the target Makefile.inc. Renumber upstream
+ test2036 to test1726 because test2036 already exists in curl 8.7.1. Use
+ the target's %SSH_PWD substitution in test1725. Declare the no-server
+ test1726 explicitly because the older test harness requires it.
+
+(cherry picked from commit ab3bb8cd8be8f9d4acb97da0418abc279182041e)
+Signed-off-by: Devansh Patel <devanshp@cisco.com>
+---
+ docs/cmdline-opts/proto-default.md | 6 +++-
+ src/tool_operate.c | 45 +++++++++++++++----------
+ tests/data/Makefile.inc | 1 +
+ tests/data/test1724 | 53 ++++++++++++++++++++++++++++++
+ tests/data/test1725 | 29 ++++++++++++++++
+ tests/data/test1726 | 29 ++++++++++++++++
+ 6 files changed, 144 insertions(+), 19 deletions(-)
+ create mode 100644 tests/data/test1724
+ create mode 100644 tests/data/test1725
+ create mode 100644 tests/data/test1726
+
+diff --git a/docs/cmdline-opts/proto-default.md b/docs/cmdline-opts/proto-default.md
+index 209e5cdc83..903fac73a5 100644
+--- a/docs/cmdline-opts/proto-default.md
++++ b/docs/cmdline-opts/proto-default.md
+@@ -16,7 +16,8 @@ Example:
+
+ # `--proto-default`
+
+-Use *protocol* for any provided URL missing a scheme.
++Use *protocol* for any provided URL missing a scheme. The case-insensitive
++name should be given without any `://` suffix.
+
+ An unknown or unsupported protocol causes error *CURLE_UNSUPPORTED_PROTOCOL*.
+
+@@ -24,3 +25,6 @@ This option does not change the default proxy protocol (http).
+
+ Without this option set, curl guesses protocol based on the hostname, see
+ --url for details.
++
++The default protocol cannot be set to `ipfs` or `ipns`. Those schemes need to
++be used explicitly in the URL.
+diff --git a/src/tool_operate.c b/src/tool_operate.c
+index 7e2c1eefe0..c8059a40d9 100644
+--- a/src/tool_operate.c
++++ b/src/tool_operate.c
+@@ -704,26 +704,35 @@ static CURLcode url_proto(char **url,
+ if(*url) {
+ char *schemep = NULL;
+
+- if(!curl_url_set(uh, CURLUPART_URL, *url,
+- CURLU_GUESS_SCHEME | CURLU_NON_SUPPORT_SCHEME) &&
+- !curl_url_get(uh, CURLUPART_SCHEME, &schemep,
+- CURLU_DEFAULT_SCHEME)) {
+- if(curl_strequal(schemep, proto_ipfs) ||
+- curl_strequal(schemep, proto_ipns)) {
+- result = ipfs_url_rewrite(uh, schemep, url, config);
+- /* short-circuit proto_token, we know it's ipfs or ipns */
+- if(curl_strequal(schemep, proto_ipfs))
+- proto = proto_ipfs;
+- else if(curl_strequal(schemep, proto_ipns))
+- proto = proto_ipns;
+- if(result)
+- config->synthetic_error = TRUE;
++ CURLUcode uc =
++ curl_url_set(uh, CURLUPART_URL, *url,
++ CURLU_NON_SUPPORT_SCHEME |
++ (config->proto_default ? 0 : CURLU_GUESS_SCHEME));
++
++ if((uc == CURLUE_BAD_SCHEME) && config->proto_default)
++ proto = proto_token(config->proto_default);
++ else if(!uc) {
++ uc = curl_url_get(uh, CURLUPART_SCHEME, &schemep,
++ CURLU_DEFAULT_SCHEME);
++ if(!uc) {
++ if(curl_strequal(schemep, proto_ipfs) ||
++ curl_strequal(schemep, proto_ipns)) {
++ result = ipfs_url_rewrite(uh, schemep, url, config);
++ /* short-circuit proto_token, we know it's ipfs or ipns */
++ if(curl_strequal(schemep, proto_ipfs))
++ proto = proto_ipfs;
++ else if(curl_strequal(schemep, proto_ipns))
++ proto = proto_ipns;
++ if(result)
++ config->synthetic_error = TRUE;
++ }
++ else
++ proto = proto_token(schemep);
+ }
+- else
+- proto = proto_token(schemep);
+-
+- curl_free(schemep);
+ }
++ if(uc == CURLUE_OUT_OF_MEMORY)
++ result = CURLE_OUT_OF_MEMORY;
++ curl_free(schemep);
+ }
+ curl_url_cleanup(uh);
+ }
+diff --git a/tests/data/Makefile.inc b/tests/data/Makefile.inc
+index 9708e37b1f..da87400564 100644
+--- a/tests/data/Makefile.inc
++++ b/tests/data/Makefile.inc
+@@ -220,6 +220,7 @@ test1670 test1671 \
+ test1680 test1681 test1682 test1683 \
+ \
+ test1700 test1701 test1702 test1703 test1704 \
++test1724 test1725 test1726 \
+ \
+ test1800 test1801 \
+ \
+diff --git a/tests/data/test1724 b/tests/data/test1724
+new file mode 100644
+index 0000000000..3cd328e39c
+--- /dev/null
++++ b/tests/data/test1724
+@@ -0,0 +1,53 @@
++<?xml version="1.0" encoding="US-ASCII"?>
++<testcase>
++<info>
++<keywords>
++IPFS
++</keywords>
++</info>
++
++# Server-side
++<reply>
++<data nocheck="yes">
++HTTP/1.1 200 OK
++Date: Tue, 09 Nov 2010 14:49:00 GMT
++Server: test-server/fake
++Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
++ETag: "21025-dc7-39462498"
++Accept-Ranges: bytes
++Content-Length: 21
++Connection: close
++Content-Type: text/plain
++Funny-head: yesyes
++
++Hello curl from IPFS
++</data>
++</reply>
++
++# Client-side
++<client>
++<features>
++ipfs
++</features>
++<server>
++http
++</server>
++<name>
++IPFS with --proto-default HTTP
++</name>
++<command>
++--ipfs-gateway http://%HOSTIP:%HTTPPORT ipfs://bafybeidecnvkrygux6uoukouzps5ofkeevoqland7kopseiod6pzqvjg7u --proto-default http
++</command>
++</client>
++
++# Verify data after the test has been "shot"
++<verify>
++<protocol crlf="headers">
++GET /ipfs/bafybeidecnvkrygux6uoukouzps5ofkeevoqland7kopseiod6pzqvjg7u HTTP/1.1
++Host: %HOSTIP:%HTTPPORT
++User-Agent: curl/%VERSION
++Accept: */*
++
++</protocol>
++</verify>
++</testcase>
+diff --git a/tests/data/test1725 b/tests/data/test1725
+new file mode 100644
+index 0000000000..e3b2c5abd2
+--- /dev/null
++++ b/tests/data/test1725
+@@ -0,0 +1,29 @@
++<?xml version="1.0" encoding="US-ASCII"?>
++<testcase>
++<info>
++<keywords>
++SCP
++server key check
++</keywords>
++</info>
++
++# Client-side
++<client>
++<server>
++scp
++</server>
++<name>
++SCP incorrect host key with --proto-default SCP
++</name>
++<command>
++--hostpubmd5 00000000000000000000000000000000 --key %LOGDIR/server/curl_client_key --pubkey %LOGDIR/server/curl_client_key.pub -u %USER: %HOSTIP:%SSHPORT%SSH_PWD/%LOGDIR/irrelevant-file --insecure --proto-default SCP
++</command>
++</client>
++
++# Verify data after the test has been "shot"
++<verify>
++<errorcode>
++60
++</errorcode>
++</verify>
++</testcase>
+diff --git a/tests/data/test1726 b/tests/data/test1726
+new file mode 100644
+index 0000000000..61f5b5dbd5
+--- /dev/null
++++ b/tests/data/test1726
+@@ -0,0 +1,29 @@
++<?xml version="1.0" encoding="US-ASCII"?>
++<testcase>
++<info>
++<keywords>
++--proto-default
++</keywords>
++</info>
++
++# Client-side
++<client>
++<server>
++none
++</server>
++<name>
++Attempt to set a default protocol with :// suffix
++</name>
++<command>
++--proto-default https://
++</command>
++</client>
++
++# Verify data after the test has been "shot"
++<verify>
++# CURLE_UNSUPPORTED_PROTOCOL is error code 1
++<errorcode>
++1
++</errorcode>
++</verify>
++</testcase>
@@ -47,6 +47,7 @@ SRC_URI = " \
file://CVE-2026-8927.patch \
file://CVE-2026-8932.patch \
file://CVE-2026-9547.patch \
+ file://CVE-2026-12064.patch \
"
SRC_URI:append:class-nativesdk = " \