PR #25258 opened by michaelni
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25258
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25258.patch

Fixes: cookie disclosure to other hosts
Fixes: WmqLccCSqIFr
Found during the review of https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25035
Cookie disclosure Replicated through UnModified FFmpeg



>From 5b3cbbaded2f10825dbde5e11df5bfadeed27f55 Mon Sep 17 00:00:00 2001
From: Michael Niedermayer <[email protected]>
Date: Tue, 20 Oct 2026 01:01:18 +0200
Subject: [PATCH] avformat/libcurl: restrict cookies given without a Domain to
 the host of the URL

Fixes: cookie disclosure to other hosts
Fixes: WmqLccCSqIFr
Found during the review of https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25035
Cookie disclosure Replicated through UnModified FFmpeg
---
 doc/protocols.texi    |  3 ++-
 libavformat/libcurl.c | 43 +++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 43 insertions(+), 3 deletions(-)

diff --git a/doc/protocols.texi b/doc/protocols.texi
index 287d972f688..75730e3687a 100644
--- a/doc/protocols.texi
+++ b/doc/protocols.texi
@@ -1151,7 +1151,8 @@ Set the HTTP proxy to tunnel through.
 
 @item cookies
 Cookies to be sent in future requests, given as newline-delimited
-@code{Set-Cookie}-style values.
+@code{Set-Cookie}-style values. A cookie without a domain is sent to the host 
of
+the URL and its subdomains.
 
 @item location
 The actual location of the data after following redirects. This is an output
diff --git a/libavformat/libcurl.c b/libavformat/libcurl.c
index fc487602db9..0e6d609f7a6 100644
--- a/libavformat/libcurl.c
+++ b/libavformat/libcurl.c
@@ -1242,6 +1242,25 @@ static int setup_protocols(CurlContext *c)
     return ret;
 }
 
+/* Whether a Set-Cookie style line carries a non-empty Domain attribute. */
+static int cookie_has_domain(const char *cookie)
+{
+    const char *p = cookie;
+
+    while ((p = strchr(p, ';'))) {
+        p += 1 + strspn(p + 1, " \t");
+        if (!av_strncasecmp(p, "domain", 6)) {
+            const char *v = p + 6 + strspn(p + 6, " \t");
+            if (*v == '=') {
+                v += 1 + strspn(v + 1, " \t.");
+                if (*v && *v != ';')
+                    return 1;
+            }
+        }
+    }
+    return 0;
+}
+
 #define CURL_SETOPT(opt, val)                                               \
     do {                                                                    \
         int ret_ = curl_setopt_checked(c, #opt,                            \
@@ -1318,25 +1337,45 @@ static int setup_curl(CurlContext *c)
     }
     if (c->cookies && c->cookies[0]) {
         char *copy = av_strdup(c->cookies);
-        char *line, *saveptr = NULL;
+        char *line, *saveptr = NULL, *bound;
+        char host[1024];
+        AVBPrint bp;
         if (!copy)
             return AVERROR(ENOMEM);
+        av_url_split(NULL, 0, NULL, 0, host, sizeof(host), NULL, NULL, 0, url);
+        av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED);
         for (line = av_strtok(copy, "\r\n", &saveptr); line;
              line = av_strtok(NULL, "\r\n", &saveptr)) {
-            char *sc = av_asprintf("Set-Cookie: %s", line);
+            int len = strlen(line), has_domain = cookie_has_domain(line);
+            char *sc;
 
+            while (len && (line[len - 1] == ' ' || line[len - 1] == '\t'))
+                len--;
+            sc = av_asprintf("Set-Cookie: %.*s%s%s", len, line,
+                             has_domain ? "" : "; domain=", has_domain ? "" : 
host);
             if (!sc) {
                 av_free(copy);
+                av_bprint_finalize(&bp, NULL);
                 return AVERROR(ENOMEM);
             }
             cc = curl_easy_setopt(e, CURLOPT_COOKIELIST, sc);
+            av_bprintf(&bp, "%s\n", sc + sizeof("Set-Cookie: ") - 1);
             av_free(sc);
             if ((ret = curl_setopt_checked(c, "CURLOPT_COOKIELIST", cc)) < 0) {
                 av_free(copy);
+                av_bprint_finalize(&bp, NULL);
                 return ret;
             }
         }
         av_free(copy);
+        if (!av_bprint_is_complete(&bp)) {
+            av_bprint_finalize(&bp, NULL);
+            return AVERROR(ENOMEM);
+        }
+        if ((ret = av_bprint_finalize(&bp, &bound)) < 0)
+            return ret;
+        av_free(c->cookies);
+        c->cookies = bound;
     }
 
     if ((ret = build_headers(c)) < 0)
-- 
2.54.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to