From 63cfa99169cf925c8d18365fa1fd0b53e38c6785 Mon Sep 17 00:00:00 2001 From: Abdessamie Date: Wed, 22 Jul 2026 06:21:26 +0200 Subject: [PATCH] avformat/rtsp: clear authentication on cross-origin redirects RTSP redirects retain URL credentials and authentication state when a Location URI changes to another origin. This can forward reusable credentials to a server with a different scheme, host, or port. Clear the stored credentials and authentication state when the redirect crosses an origin boundary. Preserve them for same-origin redirects. Fixes: cross-origin credential disclosure Fixes: rtsp_redirect_auth_leak_poc.py Fixes: VaKaPOnfN02z (cherry picked from commit a441a2eb383960d76632eb5dc42639ec52d46bd8) Signed-off-by: Michael Niedermayer --- libavformat/rtsp.c | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/libavformat/rtsp.c b/libavformat/rtsp.c index 45b62c4188..f3c76e8e4d 100644 --- a/libavformat/rtsp.c +++ b/libavformat/rtsp.c @@ -1868,6 +1868,32 @@ void ff_rtsp_close_connections(AVFormatContext *s) ffurl_closep(&rt->rtsp_hd); } +static int rtsp_url_same_origin(const char *url1, const char *url2) +{ + char proto1[128], proto2[128]; + char host1[1024], host2[1024]; + int port1, port2; + + av_url_split(proto1, sizeof(proto1), NULL, 0, host1, sizeof(host1), + &port1, NULL, 0, url1); + av_url_split(proto2, sizeof(proto2), NULL, 0, host2, sizeof(host2), + &port2, NULL, 0, url2); + + if (!proto1[0] || !proto2[0] || !host1[0] || !host2[0]) + return 0; + + if (port1 < 0) + port1 = !av_strcasecmp(proto1, "rtsps") ? RTSPS_DEFAULT_PORT + : RTSP_DEFAULT_PORT; + if (port2 < 0) + port2 = !av_strcasecmp(proto2, "rtsps") ? RTSPS_DEFAULT_PORT + : RTSP_DEFAULT_PORT; + + return !av_strcasecmp(proto1, proto2) && + !av_strcasecmp(host1, host2) && + port1 == port2; +} + int ff_rtsp_connect(AVFormatContext *s) { RTSPState *rt = s->priv_data; @@ -2181,7 +2207,13 @@ redirect: ff_rtsp_close_streams(s); ff_rtsp_close_connections(s); if (reply->status_code >=300 && reply->status_code < 400 && s->iformat) { - int ret = ff_format_check_set_url(s, reply->location); + int ret; + + if (!rtsp_url_same_origin(s->url, reply->location)) { + memset(rt->auth, 0, sizeof(rt->auth)); + memset(&rt->auth_state, 0, sizeof(rt->auth_state)); + } + ret = ff_format_check_set_url(s, reply->location); if (ret < 0) { err = ret; goto fail2;