diff --git a/CVE-2025-46701-1.patch b/CVE-2025-46701-1.patch
new file mode 100644
index 0000000000000000000000000000000000000000..e2c047ff7d43266d9ec6c43486377ff083e7f8b8
--- /dev/null
+++ b/CVE-2025-46701-1.patch
@@ -0,0 +1,384 @@
+From 8df00018a252baa9497615d6420fb6c10466fa74 Mon Sep 17 00:00:00 2001
+From: Mark Thomas
+Date: Mon, 28 Apr 2025 12:58:21 +0100
+Subject: [PATCH] Refactor CGI servlet to access resources via WebResources
+
+Origin: https://github.com/apache/tomcat/commit/8df00018a252baa9497615d6420fb6c10466fa74
+---
+ .../apache/catalina/servlets/CGIServlet.java | 228 +++++++-----------
+ .../catalina/servlets/LocalStrings.properties | 1 -
+ .../servlets/LocalStrings_fr.properties | 1 -
+ .../servlets/LocalStrings_ja.properties | 1 -
+ .../servlets/LocalStrings_ko.properties | 1 -
+ .../servlets/LocalStrings_zh_CN.properties | 1 -
+ 6 files changed, 90 insertions(+), 143 deletions(-)
+
+diff --git a/java/org/apache/catalina/servlets/CGIServlet.java b/java/org/apache/catalina/servlets/CGIServlet.java
+index b825920..e8e9f62 100644
+--- a/java/org/apache/catalina/servlets/CGIServlet.java
++++ b/java/org/apache/catalina/servlets/CGIServlet.java
+@@ -24,6 +24,8 @@ import java.io.InputStream;
+ import java.io.InputStreamReader;
+ import java.io.OutputStream;
+ import java.io.UnsupportedEncodingException;
++import java.net.MalformedURLException;
++import java.net.URL;
+ import java.net.URLDecoder;
+ import java.nio.file.Files;
+ import java.util.ArrayList;
+@@ -622,9 +624,6 @@ public final class CGIServlet extends HttpServlet {
+ /** pathInfo for the current request */
+ private String pathInfo = null;
+
+- /** real file system directory of the enclosing servlet's web app */
+- private String webAppRootDir = null;
+-
+ /** tempdir for context - used to expand scripts in unexpanded wars */
+ private File tmpDir = null;
+
+@@ -678,7 +677,6 @@ public final class CGIServlet extends HttpServlet {
+ */
+ protected void setupFromContext(ServletContext context) {
+ this.context = context;
+- this.webAppRootDir = context.getRealPath("/");
+ this.tmpDir = (File) context.getAttribute(ServletContext.TEMPDIR);
+ }
+
+@@ -785,10 +783,9 @@ public final class CGIServlet extends HttpServlet {
+ * cgiPathPrefix is defined by setting this servlet's cgiPathPrefix init parameter
+ *
+ *
+- * @param pathInfo String from HttpServletRequest.getPathInfo()
+- * @param webAppRootDir String from context.getRealPath("/")
+ * @param contextPath String as from HttpServletRequest.getContextPath()
+ * @param servletPath String as from HttpServletRequest.getServletPath()
++ * @param pathInfo String from HttpServletRequest.getPathInfo()
+ * @param cgiPathPrefix subdirectory of webAppRootDir below which the web app's CGIs may be stored; can be null.
+ * The CGI search path will start at webAppRootDir + File.separator + cgiPathPrefix (or
+ * webAppRootDir alone if cgiPathPrefix is null). cgiPathPrefix is defined by setting
+@@ -805,57 +802,105 @@ public final class CGIServlet extends HttpServlet {
+ * found
+ *
+ */
+- protected String[] findCGI(String pathInfo, String webAppRootDir, String contextPath, String servletPath,
+- String cgiPathPrefix) {
+- String path = null;
+- String name = null;
+- String scriptname = null;
++ protected String[] findCGI(String contextPath, String servletPath, String pathInfo, String cgiPathPrefix) {
+
+- if (webAppRootDir.lastIndexOf(File.separator) == (webAppRootDir.length() - 1)) {
+- // strip the trailing "/" from the webAppRootDir
+- webAppRootDir = webAppRootDir.substring(0, (webAppRootDir.length() - 1));
+- }
++ StringBuilder cgiPath = new StringBuilder();
++ StringBuilder urlPath = new StringBuilder();
+
+- if (cgiPathPrefix != null) {
+- webAppRootDir = webAppRootDir + File.separator + cgiPathPrefix;
+- }
++ URL cgiScriptURL = null;
+
+- if (log.isTraceEnabled()) {
+- log.trace(sm.getString("cgiServlet.find.path", pathInfo, webAppRootDir));
++ if (cgiPathPrefix == null || cgiPathPrefix.isEmpty()) {
++ cgiPath.append(servletPath);
++ } else {
++ cgiPath.append('/');
++ cgiPath.append(cgiPathPrefix);
+ }
++ urlPath.append(servletPath);
+
+- File currentLocation = new File(webAppRootDir);
+- StringTokenizer dirWalker = new StringTokenizer(pathInfo, "/");
+- if (log.isTraceEnabled()) {
+- log.trace(sm.getString("cgiServlet.find.location", currentLocation.getAbsolutePath()));
+- }
+- StringBuilder cginameBuilder = new StringBuilder();
+- while (!currentLocation.isFile() && dirWalker.hasMoreElements()) {
+- String nextElement = (String) dirWalker.nextElement();
+- currentLocation = new File(currentLocation, nextElement);
+- cginameBuilder.append('/').append(nextElement);
++ StringTokenizer pathWalker = new StringTokenizer(pathInfo, "/");
++
++ while (pathWalker.hasMoreElements() && cgiScriptURL == null) {
++ String urlSegment = pathWalker.nextToken();
++ cgiPath.append('/');
++ cgiPath.append(urlSegment);
++ urlPath.append('/');
++ urlPath.append(urlSegment);
+ if (log.isTraceEnabled()) {
+- log.trace(sm.getString("cgiServlet.find.location", currentLocation.getAbsolutePath()));
++ log.trace(sm.getString("cgiServlet.find.location", cgiPath.toString()));
++ }
++ try {
++ cgiScriptURL = context.getResource(cgiPath.toString());
++ } catch (MalformedURLException e) {
++ // Ignore - should never happen
+ }
+ }
+- String cginame = cginameBuilder.toString();
+- if (!currentLocation.isFile()) {
++
++ // No script was found
++ if (cgiScriptURL == null) {
+ return new String[] { null, null, null, null };
+ }
+
+- path = currentLocation.getAbsolutePath();
+- name = currentLocation.getName();
++ // Set-up return values
++ String path = null;
++ String scriptName = null;
++ String cgiName = null;
++ String name = null;
+
+- if (servletPath.startsWith(cginame)) {
+- scriptname = contextPath + cginame;
+- } else {
+- scriptname = contextPath + servletPath + cginame;
++ path = context.getRealPath(cgiPath.toString());
++ if (path == null) {
++ /*
++ * The script doesn't exist directly on the file system. It might be located in an archive or similar.
++ * Such scripts are extracted to the web application's temporary file location.
++ */
++ File tmpCgiFile = new File(tmpDir + cgiPath.toString());
++ if (!tmpCgiFile.exists()) {
++
++ // Create directories
++ File parent = tmpCgiFile.getParentFile();
++ if (!parent.mkdirs() && !parent.isDirectory()) {
++ log.warn(sm.getString("cgiServlet.expandCreateDirFail", parent.getAbsolutePath()));
++ return new String[] { null, null, null, null };
++ }
++
++ try (InputStream is = context.getResourceAsStream(cgiPath.toString())) {
++ synchronized (expandFileLock) {
++ // Check if file was created by concurrent request
++ if (!tmpCgiFile.exists()) {
++ try {
++ Files.copy(is, tmpCgiFile.toPath());
++ } catch (IOException ioe) {
++ log.warn(sm.getString("cgiServlet.expandFail", cgiScriptURL,
++ tmpCgiFile.getAbsolutePath()), ioe);
++ if (tmpCgiFile.exists()) {
++ if (!tmpCgiFile.delete()) {
++ log.warn(sm.getString("cgiServlet.expandDeleteFail",
++ tmpCgiFile.getAbsolutePath()));
++ }
++ }
++ return new String[] { null, null, null, null };
++ }
++ if (log.isDebugEnabled()) {
++ log.debug(sm.getString("cgiServlet.expandOk", cgiScriptURL,
++ tmpCgiFile.getAbsolutePath()));
++ }
++ }
++ }
++ } catch (IOException ioe) {
++ log.warn(sm.getString("cgiServlet.expandCloseFail", cgiScriptURL), ioe);
++ }
++ }
++ path = tmpCgiFile.getAbsolutePath();
+ }
+
++ scriptName = urlPath.toString();
++ cgiName = scriptName.substring(servletPath.length());
++ name = scriptName.substring(scriptName.lastIndexOf('/') + 1);
++
+ if (log.isTraceEnabled()) {
+- log.trace(sm.getString("cgiServlet.find.found", name, path, scriptname, cginame));
++ log.trace(sm.getString("cgiServlet.find.found", name, path, scriptName, cgiName));
+ }
+- return new String[] { path, scriptname, cginame, name };
++
++ return new String[] { path, scriptName, cgiName, name };
+ }
+
+ /**
+@@ -892,13 +937,7 @@ public final class CGIServlet extends HttpServlet {
+ sPathInfoOrig = this.pathInfo;
+ sPathInfoOrig = sPathInfoOrig == null ? "" : sPathInfoOrig;
+
+- if (webAppRootDir == null) {
+- // The app has not been deployed in exploded form
+- webAppRootDir = tmpDir.toString();
+- expandCGIScript();
+- }
+-
+- sCGINames = findCGI(sPathInfoOrig, webAppRootDir, contextPath, servletPath, cgiPathPrefix);
++ sCGINames = findCGI(contextPath, servletPath, sPathInfoOrig, cgiPathPrefix);
+
+ sCGIFullPath = sCGINames[0];
+ sCGIScriptName = sCGINames[1];
+@@ -1025,93 +1064,6 @@ public final class CGIServlet extends HttpServlet {
+ return true;
+ }
+
+- /**
+- * Extracts requested resource from web app archive to context work directory to enable CGI script to be
+- * executed.
+- */
+- protected void expandCGIScript() {
+- StringBuilder srcPath = new StringBuilder();
+- StringBuilder destPath = new StringBuilder();
+- InputStream is = null;
+-
+- // paths depend on mapping
+- if (cgiPathPrefix == null) {
+- srcPath.append(pathInfo);
+- is = context.getResourceAsStream(srcPath.toString());
+- destPath.append(tmpDir);
+- destPath.append(pathInfo);
+- } else {
+- // essentially same search algorithm as findCGI()
+- srcPath.append(cgiPathPrefix);
+- StringTokenizer pathWalker = new StringTokenizer(pathInfo, "/");
+- // start with first element
+- while (pathWalker.hasMoreElements() && (is == null)) {
+- srcPath.append('/');
+- srcPath.append(pathWalker.nextElement());
+- is = context.getResourceAsStream(srcPath.toString());
+- }
+- destPath.append(tmpDir);
+- destPath.append('/');
+- destPath.append(srcPath);
+- }
+-
+- if (is == null) {
+- // didn't find anything, give up now
+- log.warn(sm.getString("cgiServlet.expandNotFound", srcPath));
+- return;
+- }
+-
+- try {
+- File f = new File(destPath.toString());
+- if (f.exists()) {
+- // Don't need to expand if it already exists
+- return;
+- }
+-
+- // create directories
+- File dir = f.getParentFile();
+- if (!dir.mkdirs() && !dir.isDirectory()) {
+- log.warn(sm.getString("cgiServlet.expandCreateDirFail", dir.getAbsolutePath()));
+- return;
+- }
+-
+- try {
+- synchronized (expandFileLock) {
+- // make sure file doesn't exist
+- if (f.exists()) {
+- return;
+- }
+-
+- // create file
+- if (!f.createNewFile()) {
+- return;
+- }
+-
+- Files.copy(is, f.toPath());
+-
+- if (log.isDebugEnabled()) {
+- log.debug(sm.getString("cgiServlet.expandOk", srcPath, destPath));
+- }
+- }
+- } catch (IOException ioe) {
+- log.warn(sm.getString("cgiServlet.expandFail", srcPath, destPath), ioe);
+- // delete in case file is corrupted
+- if (f.exists()) {
+- if (!f.delete()) {
+- log.warn(sm.getString("cgiServlet.expandDeleteFail", f.getAbsolutePath()));
+- }
+- }
+- }
+- } finally {
+- try {
+- is.close();
+- } catch (IOException e) {
+- log.warn(sm.getString("cgiServlet.expandCloseFail", srcPath), e);
+- }
+- }
+- }
+-
+-
+ /**
+ * Returns important CGI environment information in a multi-line text format.
+ *
+@@ -1413,9 +1365,9 @@ public final class CGIServlet extends HttpServlet {
+ * Allowed characters in path segments: This implementation does not allow non-terminal NULL segments
+ * in the the path -- IOExceptions may be thrown;
+ * "." and ".." path segments: This implementation does not allow
+- * "." and ".." in the the path, and such characters will result in an IOException
+- * being thrown (this should never happen since Tomcat normalises the requestURI before determining the
+- * contextPath, servletPath and pathInfo);
++ * "." and ".." in the path, and such characters will result in an IOException being
++ * thrown (this should never happen since Tomcat normalises the requestURI before determining the contextPath,
++ * servletPath and pathInfo);
+ * Implementation limitations: This implementation does not impose any limitations except as
+ * documented above. This implementation may be limited by the servlet container used to house this
+ * implementation. In particular, all the primary CGI variable values are derived either directly or indirectly
+diff --git a/java/org/apache/catalina/servlets/LocalStrings.properties b/java/org/apache/catalina/servlets/LocalStrings.properties
+index b869d08..cf72066 100644
+--- a/java/org/apache/catalina/servlets/LocalStrings.properties
++++ b/java/org/apache/catalina/servlets/LocalStrings.properties
+@@ -21,7 +21,6 @@ cgiServlet.expandCloseFail=Failed to close input stream for script at path [{0}]
+ cgiServlet.expandCreateDirFail=Failed to create destination directory [{0}] for script expansion
+ cgiServlet.expandDeleteFail=Failed to delete file at [{0}] after IOException during expansion
+ cgiServlet.expandFail=Failed to expand script at path [{0}] to [{1}]
+-cgiServlet.expandNotFound=Unable to expand [{0}] as it could not be found
+ cgiServlet.expandOk=Expanded script at path [{0}] to [{1}]
+ cgiServlet.find.found=Found CGI: name [{0}], path [{1}], script name [{2}] and CGI name [{3}]
+ cgiServlet.find.location=Looking for a file at [{0}]
+diff --git a/java/org/apache/catalina/servlets/LocalStrings_fr.properties b/java/org/apache/catalina/servlets/LocalStrings_fr.properties
+index abf744b..137b3f6 100644
+--- a/java/org/apache/catalina/servlets/LocalStrings_fr.properties
++++ b/java/org/apache/catalina/servlets/LocalStrings_fr.properties
+@@ -21,7 +21,6 @@ cgiServlet.expandCloseFail=Impossible de fermer le flux d''entrée du script ave
+ cgiServlet.expandCreateDirFail=Echec de la création du répertoire de destination [{0}] pour la décompression du script
+ cgiServlet.expandDeleteFail=Impossible d''effacer le fichier [{0}] suite à une IOException pendant la décompression
+ cgiServlet.expandFail=Impossible de faire l''expansion du script au chemin [{0}] vers [{1}]
+-cgiServlet.expandNotFound=Impossible de décompresser [{0}] car il n''a pas été trouvé
+ cgiServlet.expandOk=Extrait le script du chemin [{0}] vers [{1}]
+ cgiServlet.find.found=Trouvé le CGI : nom [{0}], chemin [{1}], nom de script [{2}] et nom du CGI [{3}]
+ cgiServlet.find.location=Recherche d''un fichier en [{0}]
+diff --git a/java/org/apache/catalina/servlets/LocalStrings_ja.properties b/java/org/apache/catalina/servlets/LocalStrings_ja.properties
+index c56a57b..4ae874e 100644
+--- a/java/org/apache/catalina/servlets/LocalStrings_ja.properties
++++ b/java/org/apache/catalina/servlets/LocalStrings_ja.properties
+@@ -21,7 +21,6 @@ cgiServlet.expandCloseFail=パス [{0}] のスクリプトの入力ストリー
+ cgiServlet.expandCreateDirFail=スクリプトの展開先ディレクトリ[{0}]の作成に失敗しました。
+ cgiServlet.expandDeleteFail=拡張中にIOExceptionの後に [{0}] でファイルを削除できませんでした
+ cgiServlet.expandFail=パス [{0}] のスクリプトを [{1}] に展開できませんでした
+-cgiServlet.expandNotFound=見つけることができなかったため [{0}] を展開できません
+ cgiServlet.expandOk=パス [{0}] の [{1}] に展開されたスクリプト
+ cgiServlet.find.found=見つかったCGI: 名前 [{0}]、パス [{1}]、スクリプト名 [{2}]、CGI名 [{3}]
+ cgiServlet.find.location=ファイル [{0}] を探しています。
+diff --git a/java/org/apache/catalina/servlets/LocalStrings_ko.properties b/java/org/apache/catalina/servlets/LocalStrings_ko.properties
+index aeb3d72..547c842 100644
+--- a/java/org/apache/catalina/servlets/LocalStrings_ko.properties
++++ b/java/org/apache/catalina/servlets/LocalStrings_ko.properties
+@@ -21,7 +21,6 @@ cgiServlet.expandCloseFail=경로 [{0}]에 위치한 스크립트를 위한, 입
+ cgiServlet.expandCreateDirFail=스크립트를 압축해제 하기 위한 대상 디렉토리 [{0}]을(를) 생성하지 못했습니다.
+ cgiServlet.expandDeleteFail=압축해제 중 IOException이 발생한 후, [{0}]에 위치한 해당 파일을 삭제하지 못했습니다.
+ cgiServlet.expandFail=경로 [{0}]의 스크립트를 [{1}](으)로 압축해제 하지 못했습니다.
+-cgiServlet.expandNotFound=[{0}]을(를) 찾을 수 없어서 압축해제 할 수 없습니다.
+ cgiServlet.expandOk=[{0}] 경로에 있는 스트립트가 [{1}](으)로 압축 해제되었습니다.
+ cgiServlet.find.found=CGI 발견: 이름 [{0}], 경로 [{1}], 스크립트 이름 [{2}], CGI 이름 [{3}]
+ cgiServlet.find.location=[{0}]에 위치한 파일을 찾는 중
+diff --git a/java/org/apache/catalina/servlets/LocalStrings_zh_CN.properties b/java/org/apache/catalina/servlets/LocalStrings_zh_CN.properties
+index 72ee5c9..700617c 100644
+--- a/java/org/apache/catalina/servlets/LocalStrings_zh_CN.properties
++++ b/java/org/apache/catalina/servlets/LocalStrings_zh_CN.properties
+@@ -21,7 +21,6 @@ cgiServlet.expandCloseFail=无法关闭路径[{0}]处脚本的输入流
+ cgiServlet.expandCreateDirFail=无法为脚本扩展创建目标目录[{0}]
+ cgiServlet.expandDeleteFail=扩展期间,发生IOException异常后删除文件[{0}]失败
+ cgiServlet.expandFail=在路径[{0}] 到[{1}] 展开脚本失败.
+-cgiServlet.expandNotFound=无法展开[{0}],因为找不到它。
+ cgiServlet.expandOk=从路径[{0}]到[{1}]扩展脚本
+ cgiServlet.find.found=找到CGI:name[{0}]、path[{1}]、script name[{2}]和CGI name[{3}]
+ cgiServlet.find.location=在 [{0}] 查找文件
+--
+2.49.0
+
diff --git a/CVE-2025-46701-2.patch b/CVE-2025-46701-2.patch
new file mode 100644
index 0000000000000000000000000000000000000000..b4332980fb50413782007e1d2fc2fcca68e26b7f
--- /dev/null
+++ b/CVE-2025-46701-2.patch
@@ -0,0 +1,160 @@
+From 8cb95ff03221067c511b3fa66d4f745bc4b0a605 Mon Sep 17 00:00:00 2001
+From: Mark Thomas
+Date: Fri, 2 May 2025 16:42:30 +0100
+Subject: [PATCH] Use WebResource API to differentiate files and directories
+
+It is much easier/more efficient to do this directly than via the
+ServletContext API.
+
+Origin: https://github.com/apache/tomcat/commit/8cb95ff03221067c511b3fa66d4f745bc4b0a605
+---
+ .../apache/catalina/servlets/CGIServlet.java | 37 +++++++++++--------
+ .../catalina/servlets/LocalStrings.properties | 1 +
+ 2 files changed, 23 insertions(+), 15 deletions(-)
+
+diff --git a/java/org/apache/catalina/servlets/CGIServlet.java b/java/org/apache/catalina/servlets/CGIServlet.java
+index e8e9f62..f7b2563 100644
+--- a/java/org/apache/catalina/servlets/CGIServlet.java
++++ b/java/org/apache/catalina/servlets/CGIServlet.java
+@@ -24,8 +24,6 @@ import java.io.InputStream;
+ import java.io.InputStreamReader;
+ import java.io.OutputStream;
+ import java.io.UnsupportedEncodingException;
+-import java.net.MalformedURLException;
+-import java.net.URL;
+ import java.net.URLDecoder;
+ import java.nio.file.Files;
+ import java.util.ArrayList;
+@@ -44,12 +42,16 @@ import javax.servlet.RequestDispatcher;
+ import javax.servlet.ServletConfig;
+ import javax.servlet.ServletContext;
+ import javax.servlet.ServletException;
++import javax.servlet.UnavailableException;
+ import javax.servlet.http.Cookie;
+ import javax.servlet.http.HttpServlet;
+ import javax.servlet.http.HttpServletRequest;
+ import javax.servlet.http.HttpServletResponse;
+ import javax.servlet.http.HttpSession;
+
++import org.apache.catalina.Globals;
++import org.apache.catalina.WebResource;
++import org.apache.catalina.WebResourceRoot;
+ import org.apache.catalina.util.IOTools;
+ import org.apache.juli.logging.Log;
+ import org.apache.juli.logging.LogFactory;
+@@ -244,6 +246,8 @@ public final class CGIServlet extends HttpServlet {
+ private Set cgiMethods = new HashSet<>();
+ private boolean cgiMethodsAll = false;
+
++ private transient WebResourceRoot resources = null;
++
+
+ /**
+ * The time (in milliseconds) to wait for the reading of stderr to complete before terminating the CGI process.
+@@ -379,6 +383,13 @@ public final class CGIServlet extends HttpServlet {
+ } else if (value != null) {
+ cmdLineArgumentsDecodedPattern = Pattern.compile(value);
+ }
++
++ // Load the web resources
++ resources = (WebResourceRoot) getServletContext().getAttribute(Globals.RESOURCES_ATTR);
++
++ if (resources == null) {
++ throw new UnavailableException(sm.getString("cgiServlet.noResources"));
++ }
+ }
+
+
+@@ -807,7 +818,7 @@ public final class CGIServlet extends HttpServlet {
+ StringBuilder cgiPath = new StringBuilder();
+ StringBuilder urlPath = new StringBuilder();
+
+- URL cgiScriptURL = null;
++ WebResource cgiScript = null;
+
+ if (cgiPathPrefix == null || cgiPathPrefix.isEmpty()) {
+ cgiPath.append(servletPath);
+@@ -819,7 +830,7 @@ public final class CGIServlet extends HttpServlet {
+
+ StringTokenizer pathWalker = new StringTokenizer(pathInfo, "/");
+
+- while (pathWalker.hasMoreElements() && cgiScriptURL == null) {
++ while (pathWalker.hasMoreElements() && (cgiScript == null || !cgiScript.isFile())) {
+ String urlSegment = pathWalker.nextToken();
+ cgiPath.append('/');
+ cgiPath.append(urlSegment);
+@@ -828,15 +839,11 @@ public final class CGIServlet extends HttpServlet {
+ if (log.isTraceEnabled()) {
+ log.trace(sm.getString("cgiServlet.find.location", cgiPath.toString()));
+ }
+- try {
+- cgiScriptURL = context.getResource(cgiPath.toString());
+- } catch (MalformedURLException e) {
+- // Ignore - should never happen
+- }
++ cgiScript = resources.getResource(cgiPath.toString());
+ }
+
+ // No script was found
+- if (cgiScriptURL == null) {
++ if (cgiScript == null || !cgiScript.isFile()) {
+ return new String[] { null, null, null, null };
+ }
+
+@@ -846,7 +853,7 @@ public final class CGIServlet extends HttpServlet {
+ String cgiName = null;
+ String name = null;
+
+- path = context.getRealPath(cgiPath.toString());
++ path = cgiScript.getCanonicalPath();
+ if (path == null) {
+ /*
+ * The script doesn't exist directly on the file system. It might be located in an archive or similar.
+@@ -862,14 +869,14 @@ public final class CGIServlet extends HttpServlet {
+ return new String[] { null, null, null, null };
+ }
+
+- try (InputStream is = context.getResourceAsStream(cgiPath.toString())) {
++ try (InputStream is = cgiScript.getInputStream()) {
+ synchronized (expandFileLock) {
+ // Check if file was created by concurrent request
+ if (!tmpCgiFile.exists()) {
+ try {
+ Files.copy(is, tmpCgiFile.toPath());
+ } catch (IOException ioe) {
+- log.warn(sm.getString("cgiServlet.expandFail", cgiScriptURL,
++ log.warn(sm.getString("cgiServlet.expandFail", cgiScript.getURL(),
+ tmpCgiFile.getAbsolutePath()), ioe);
+ if (tmpCgiFile.exists()) {
+ if (!tmpCgiFile.delete()) {
+@@ -880,13 +887,13 @@ public final class CGIServlet extends HttpServlet {
+ return new String[] { null, null, null, null };
+ }
+ if (log.isDebugEnabled()) {
+- log.debug(sm.getString("cgiServlet.expandOk", cgiScriptURL,
++ log.debug(sm.getString("cgiServlet.expandOk", cgiScript.getURL(),
+ tmpCgiFile.getAbsolutePath()));
+ }
+ }
+ }
+ } catch (IOException ioe) {
+- log.warn(sm.getString("cgiServlet.expandCloseFail", cgiScriptURL), ioe);
++ log.warn(sm.getString("cgiServlet.expandCloseFail", cgiScript.getURL()), ioe);
+ }
+ }
+ path = tmpCgiFile.getAbsolutePath();
+diff --git a/java/org/apache/catalina/servlets/LocalStrings.properties b/java/org/apache/catalina/servlets/LocalStrings.properties
+index cf72066..da597f2 100644
+--- a/java/org/apache/catalina/servlets/LocalStrings.properties
++++ b/java/org/apache/catalina/servlets/LocalStrings.properties
+@@ -29,6 +29,7 @@ cgiServlet.invalidArgumentDecoded=The decoded command line argument [{0}] did no
+ cgiServlet.invalidArgumentEncoded=The encoded command line argument [{0}] did not match the configured cmdLineArgumentsEncoded pattern [{1}]
+ cgiServlet.invalidCommand=Illegal Character in CGI command path ('.' or '..') detected, not running CGI [{0}]
+ cgiServlet.notReady=CGI Servlet is not ready to run
++cgiServlet.noResources=No static resources were found
+ cgiServlet.runBadHeader=Bad header line [{0}]
+ cgiServlet.runFail=I/O problems processing CGI
+ cgiServlet.runHeaderReaderFail=I/O problems closing header reader
+--
+2.49.0
+
diff --git a/tomcat.spec b/tomcat.spec
index fe2cf5523d5e6584b2d4ca461954df184fd2a5b9..2d9dce67f48e83eada386c3d6442cadd2c298d4f 100644
--- a/tomcat.spec
+++ b/tomcat.spec
@@ -23,7 +23,7 @@
Name: tomcat
Epoch: 1
Version: %{major_version}.%{minor_version}.%{micro_version}
-Release: 2
+Release: 3
Summary: Apache Servlet/JSP Engine, RI for Servlet %{servletspec}/JSP %{jspspec} API
License: Apache-2.0
@@ -56,6 +56,8 @@ Patch9: CVE-2025-31650-2.patch
Patch10: CVE-2025-31650-3.patch
Patch11: CVE-2025-31651-1.patch
Patch12: CVE-2025-31651-2.patch
+Patch13: CVE-2025-46701-1.patch
+Patch14: CVE-2025-46701-2.patch
BuildArch: noarch
@@ -422,6 +424,9 @@ fi
%{appdir}/docs
%changelog
+* Wed Jun 04 2025 yaoxin <1024769339@qq.com> 1:9.0.100-3
+- Fix CVE-2025-46701
+
* Tue Apr 29 2025 wangkai <13474090681@163.com> - 1:9.0.100-2
- Fix CVE-2025-31650, CVE-2025-31651