public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
* [rpms/curl] f44: Resolves: CVE-2026-11856 - cross-origin Digest auth state leak
@ 2026-07-31 10:22 Jan Macku
0 siblings, 0 replies; only message in thread
From: Jan Macku @ 2026-07-31 10:22 UTC (permalink / raw)
To: git-commits
A new commit has been pushed.
Repo : rpms/curl
Branch : f44
Commit : dbd1914113b04b5f0a9270656b575a47c76c88d9
Author : Jan Macku <jamacku@redhat.com>
Date : 2026-07-30T12:37:20+02:00
Stats : +341/-0 in 2 file(s)
URL : https://src.fedoraproject.org/rpms/curl/c/dbd1914113b04b5f0a9270656b575a47c76c88d9?branch=f44
Log:
Resolves: CVE-2026-11856 - cross-origin Digest auth state leak
---
diff --git a/0010-curl-8.18.0-CVE-2026-11856.patch b/0010-curl-8.18.0-CVE-2026-11856.patch
new file mode 100644
index 0000000..c0e7985
--- /dev/null
+++ b/0010-curl-8.18.0-CVE-2026-11856.patch
@@ -0,0 +1,337 @@
+From 90e9bbda751edc052b04a53b7044ad7f037ffc5d Mon Sep 17 00:00:00 2001
+From: Daniel Stenberg <daniel@haxx.se>
+Date: Wed, 10 Jun 2026 10:27:50 +0200
+Subject: [PATCH] digest: flush state on origin or credential change
+
+Verified by test 1686
+
+Closes #21944
+
+(cherry picked from commit 5c6b4880357ab3e72967c1c45cae0f96ffabc535)
+---
+ lib/http_digest.c | 31 ++++++++++++
+ lib/urldata.h | 8 ++--
+ lib/vauth/digest.c | 4 ++
+ lib/vauth/digest_sspi.c | 2 +
+ tests/data/Makefile.am | 2 +-
+ tests/data/test1686 | 84 +++++++++++++++++++++++++++++++++
+ tests/libtest/Makefile.inc | 1 +
+ tests/libtest/lib1686.c | 96 ++++++++++++++++++++++++++++++++++++++
+ 8 files changed, 223 insertions(+), 5 deletions(-)
+ create mode 100644 tests/data/test1686
+ create mode 100644 tests/libtest/lib1686.c
+
+diff --git a/lib/http_digest.c b/lib/http_digest.c
+index ccc67f5efc..129c0d33f7 100644
+--- a/lib/http_digest.c
++++ b/lib/http_digest.c
+@@ -98,7 +98,38 @@ CURLcode Curl_output_digest(struct Curl_easy *data,
+ #endif
+ }
+ else {
++ bool flush = FALSE;
+ digest = &data->state.digest;
++
++ if(digest->origin_host &&
++ (!curl_strequal(data->conn->host.name, digest->origin_host) ||
++ data->conn->remote_port != digest->origin_port))
++ flush = TRUE;
++ else if(digest->user &&
++ Curl_timestrcmp(data->state.aptr.user ?
++ data->state.aptr.user : "",
++ digest->user))
++ flush = TRUE;
++ else if(digest->passwd &&
++ Curl_timestrcmp(data->state.aptr.passwd ?
++ data->state.aptr.passwd : "",
++ digest->passwd))
++ flush = TRUE;
++
++ if(flush)
++ /* flush host Digest state */
++ Curl_auth_digest_cleanup(digest);
++
++ Curl_safefree(digest->origin_host);
++ digest->origin_host = curlx_strdup(data->conn->host.name);
++ digest->origin_port = data->conn->remote_port;
++ Curl_safefree(digest->user);
++ digest->user = curlx_strdup(data->state.aptr.user ?
++ data->state.aptr.user : "");
++ Curl_safefree(digest->passwd);
++ digest->passwd = curlx_strdup(data->state.aptr.passwd ?
++ data->state.aptr.passwd : "");
++
+ allocuserpwd = &data->state.aptr.userpwd;
+ userp = data->state.aptr.user;
+ passwdp = data->state.aptr.passwd;
+diff --git a/lib/urldata.h b/lib/urldata.h
+index aba1693ca7..221317e47e 100644
+--- a/lib/urldata.h
++++ b/lib/urldata.h
+@@ -291,14 +291,14 @@ struct ssl_general_config {
+ #ifndef CURL_DISABLE_DIGEST_AUTH
+ /* Struct used for Digest challenge-response authentication */
+ struct digestdata {
++ char *origin_host;
++ int origin_port;
++ char *user;
++ char *passwd;
+ #ifdef USE_WINDOWS_SSPI
+ BYTE *input_token;
+ size_t input_token_len;
+ CtxtHandle *http_context;
+- /* copy of user/passwd used to make the identity for http_context.
+- either may be NULL. */
+- char *user;
+- char *passwd;
+ #else
+ char *nonce;
+ char *cnonce;
+diff --git a/lib/vauth/digest.c b/lib/vauth/digest.c
+index a1fd248617..1cd867cead 100644
+--- a/lib/vauth/digest.c
++++ b/lib/vauth/digest.c
+@@ -1013,6 +1013,10 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
+ */
+ void Curl_auth_digest_cleanup(struct digestdata *digest)
+ {
++ Curl_safefree(digest->origin_host);
++ digest->origin_port = 0;
++ Curl_safefree(digest->user);
++ Curl_safefree(digest->passwd);
+ Curl_safefree(digest->nonce);
+ Curl_safefree(digest->cnonce);
+ Curl_safefree(digest->realm);
+diff --git a/lib/vauth/digest_sspi.c b/lib/vauth/digest_sspi.c
+index 615b4bc827..3fc75371b2 100644
+--- a/lib/vauth/digest_sspi.c
++++ b/lib/vauth/digest_sspi.c
+@@ -661,6 +661,8 @@ void Curl_auth_digest_cleanup(struct digestdata *digest)
+ /* Free the copy of user/passwd used to make the identity for http_context */
+ Curl_safefree(digest->user);
+ Curl_safefree(digest->passwd);
++ Curl_safefree(digest->origin_host);
++ digest->origin_port = 0;
+ }
+
+ #endif /* USE_WINDOWS_SSPI && !CURL_DISABLE_DIGEST_AUTH */
+diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am
+index bff118240c..9535861b18 100644
+--- a/tests/data/Makefile.am
++++ b/tests/data/Makefile.am
+@@ -225,7 +225,7 @@ test1660 test1661 test1662 test1663 test1664 test1665 \
+ \
+ test1670 test1671 \
+ \
+-test1680 test1681 test1682 test1683 \
++test1680 test1681 test1682 test1683 test1686 \
+ \
+ test1700 test1701 test1702 test1703 test1704 test1705 test1706 test1707 \
+ test1708 test1709 test1710 test1711 \
+diff --git a/tests/data/test1686 b/tests/data/test1686
+new file mode 100644
+index 0000000000..2d419ad608
+--- /dev/null
++++ b/tests/data/test1686
+@@ -0,0 +1,84 @@
++<?xml version="1.0" encoding="US-ASCII"?>
++<testcase>
++<info>
++<keywords>
++HTTP
++Digest
++</keywords>
++</info>
++
++<reply>
++<data crlf="headers" nocheck="yes">
++HTTP/1.1 401 Authorization Required
++Server: Apache/1.3.27 (Darwin) PHP/4.1.2
++WWW-Authenticate: Digest realm="my-backyard", nonce="314156295"
++Content-Length: 26
++
++This is not the real page
++</data>
++
++# This is supposed to be returned when the server gets a
++# Authorization: Digest line passed-in from the client
++<data1000 crlf="headers">
++HTTP/1.1 200 OK
++Server: Apache/1.3.27 (Darwin) PHP/4.1.2
++Content-Type: text/html; charset=iso-8859-1
++Content-Length: 23
++
++This IS the real page!
++</data1000>
++
++</reply>
++
++<client>
++<features>
++!SSPI
++crypto
++digest
++</features>
++<server>
++http
++</server>
++<name>
++HTTP Digest to different origins and switching credentials
++</name>
++<tool>
++lib%TESTNUMBER
++</tool>
++<command>
++%HOSTIP %HTTPPORT
++</command>
++</client>
++
++<verify>
++<protocol crlf="headers">
++GET /api HTTP/1.1
++Host: first.test:%HTTPPORT
++Accept: */*
++
++GET /api HTTP/1.1
++Host: first.test:%HTTPPORT
++Authorization: Digest username="alice", realm="my-backyard", nonce="314156295", uri="/api", response="4ecc00e567c37a9d537727890c2e5b32"
++Accept: */*
++
++GET /hook HTTP/1.1
++Host: second.test:%HTTPPORT
++Accept: */*
++
++GET /hook HTTP/1.1
++Host: second.test:%HTTPPORT
++Authorization: Digest username="alice", realm="my-backyard", nonce="314156295", uri="/hook", response="d3a7738fb6a23f5543fb8dacc0f0f253"
++Accept: */*
++
++GET /hook HTTP/1.1
++Host: second.test:%HTTPPORT
++Accept: */*
++
++GET /hook HTTP/1.1
++Host: second.test:%HTTPPORT
++Authorization: Digest username="bob", realm="my-backyard", nonce="314156295", uri="/hook", response="777e68eddb77294d9cbd6134973cbbab"
++Accept: */*
++
++</protocol>
++</verify>
++</testcase>
+diff --git a/tests/libtest/Makefile.inc b/tests/libtest/Makefile.inc
+index e3202804a9..5c5660ffd8 100644
+--- a/tests/libtest/Makefile.inc
++++ b/tests/libtest/Makefile.inc
+@@ -101,6 +101,7 @@ TESTS_C = \
+ lib1591.c lib1592.c lib1593.c lib1594.c lib1597.c \
+ lib1598.c lib1599.c \
+ lib1662.c \
++ lib1686.c \
+ lib1900.c lib1901.c lib1902.c lib1903.c lib1905.c lib1906.c lib1907.c \
+ lib1908.c lib1910.c lib1911.c lib1912.c lib1913.c \
+ lib1915.c lib1916.c lib1918.c lib1919.c lib1920.c \
+diff --git a/tests/libtest/lib1686.c b/tests/libtest/lib1686.c
+new file mode 100644
+index 0000000000..e457012bb9
+--- /dev/null
++++ b/tests/libtest/lib1686.c
+@@ -0,0 +1,96 @@
++/***************************************************************************
++ * _ _ ____ _
++ * Project ___| | | | _ \| |
++ * / __| | | | |_) | |
++ * | (__| |_| | _ <| |___
++ * \___|\___/|_| \_\_____|
++ *
++ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
++ *
++ * This software is licensed as described in the file COPYING, which
++ * you should have received as part of this distribution. The terms
++ * are also available at https://curl.se/docs/copyright.html.
++ *
++ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
++ * copies of the Software, and permit persons to whom the Software is
++ * furnished to do so, under the terms of the COPYING file.
++ *
++ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
++ * KIND, either express or implied.
++ *
++ * SPDX-License-Identifier: curl
++ *
++ ***************************************************************************/
++#include "first.h"
++
++static size_t devnull_1686(char *p, size_t s, size_t n, void *u)
++{
++ (void)p;
++ (void)u;
++ return s * n;
++}
++
++#define FIRSTHOST "first.test"
++#define SECONDHOST "second.test"
++
++static CURLcode test_lib1686(const char *hostip)
++{
++ CURL *curl = NULL;
++ CURLcode result = CURLE_OK;
++ const char *httpport = libtest_arg2;
++ char firsturl[100];
++ char secondurl[100];
++ char firstres[100];
++ char secondres[100];
++ struct curl_slist *host = NULL;
++ struct curl_slist *host2 = NULL;
++
++ if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
++ curl_mfprintf(stderr, "curl_global_init() failed\n");
++ return TEST_ERR_MAJOR_BAD;
++ }
++
++ /* create strings for CURLOPT_RESOLVE */
++ curl_msnprintf(firstres, sizeof(firstres), "%s:%s:%s",
++ FIRSTHOST, httpport, hostip);
++ curl_msnprintf(secondres, sizeof(secondres), "%s:%s:%s",
++ SECONDHOST, httpport, hostip);
++
++ /* create URLs */
++ curl_msnprintf(firsturl, sizeof(firsturl), "http://%s:%s/api",
++ FIRSTHOST, httpport);
++ curl_msnprintf(secondurl, sizeof(secondurl), "http://%s:%s/hook",
++ SECONDHOST, httpport);
++
++ host = curl_slist_append(NULL, firstres);
++ if(!host)
++ goto test_cleanup;
++ host2 = curl_slist_append(host, secondres);
++ if(!host2)
++ goto test_cleanup;
++ host = host2;
++
++ curl = curl_easy_init();
++ if(curl) {
++ easy_setopt(curl, CURLOPT_RESOLVE, host);
++ easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
++ easy_setopt(curl, CURLOPT_USERPWD, "alice:bond");
++ easy_setopt(curl, CURLOPT_WRITEFUNCTION, devnull_1686);
++
++ easy_setopt(curl, CURLOPT_URL, firsturl);
++ result = curl_easy_perform(curl);
++
++ easy_setopt(curl, CURLOPT_URL, secondurl);
++ result = curl_easy_perform(curl);
++
++ easy_setopt(curl, CURLOPT_USERPWD, "bob:secret");
++ easy_setopt(curl, CURLOPT_URL, secondurl);
++ result = curl_easy_perform(curl);
++ }
++
++test_cleanup:
++ curl_easy_cleanup(curl);
++ curl_global_cleanup();
++ curl_slist_free_all(host);
++ return result;
++}
+--
+2.55.0
+
diff --git a/curl.spec b/curl.spec
index a9fa385..073c102 100644
--- a/curl.spec
+++ b/curl.spec
@@ -51,6 +51,9 @@ Patch008: 0008-curl-8.18.0-CVE-2026-9547.patch
# Fix password leak with netrc and user in URL (CVE-2026-8926)
Patch009: 0009-curl-8.18.0-CVE-2026-8926.patch
+# Fix cross-origin Digest auth state leak (CVE-2026-11856)
+Patch010: 0010-curl-8.18.0-CVE-2026-11856.patch
+
# patch making libcurl multilib ready
Patch101: 0101-curl-7.32.0-multilib.patch
@@ -478,6 +481,7 @@ rm -f ${RPM_BUILD_ROOT}%{_mandir}/man1/wcurl.1*
- Fix trailing dot domain super cookie (CVE-2026-8924)
- Fix SSH improper host validation (CVE-2026-9547)
- Fix password leak with netrc and user in URL (CVE-2026-8926)
+- Fix cross-origin Digest auth state leak (CVE-2026-11856)
* Mon Jul 20 2026 Jan Macku <jamacku@redhat.com> - 8.18.0-7
- explicitly disable HTTP/3 support in the minimal build
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2026-07-31 10:22 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-07-31 10:22 [rpms/curl] f44: Resolves: CVE-2026-11856 - cross-origin Digest auth state leak Jan Macku
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox