This is an automated email from the ASF dual-hosted git repository.

lukaszlenart pushed a commit to branch chore/harden-showcase-apps
in repository https://gitbox.apache.org/repos/asf/struts.git

commit 1f02829705d8322d1d05c6c4459d319344a9ebbf
Author: Lukasz Lenart <[email protected]>
AuthorDate: Mon Mar 16 07:52:40 2026 +0100

    chore: harden showcase apps and convert READMEs to Markdown
    
    - Add production deployment warnings to showcase and rest-showcase READMEs
    - Convert README.txt to README.md with proper Markdown formatting
    - Restrict ViewSourceAction config parameter to XML files within webapp path
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
---
 apps/rest-showcase/README.md                       | 18 ++++++++++++++++
 apps/rest-showcase/README.txt                      | 15 -------------
 apps/showcase/README.md                            | 19 ++++++++++++++++
 apps/showcase/README.txt                           | 16 --------------
 .../struts2/showcase/source/ViewSourceAction.java  | 25 +++++++++++++++++++++-
 5 files changed, 61 insertions(+), 32 deletions(-)

diff --git a/apps/rest-showcase/README.md b/apps/rest-showcase/README.md
new file mode 100644
index 000000000..1437ea14f
--- /dev/null
+++ b/apps/rest-showcase/README.md
@@ -0,0 +1,18 @@
+# Rest Showcase
+
+> **WARNING:** This application is a demonstration/development tool only. It 
is **NOT** intended for production
+> deployment. Deploying this application on a publicly accessible server may 
pose security risks.
+
+Rest Showcase is a simple example of a REST app built with the REST plugin.
+
+For more on getting started with Struts, see:
+
+- https://struts.apache.org/getting-started/
+
+## I18N
+
+Please note that this project was created with the assumption that it will be 
run in an environment where the default
+locale is set to English. This means that the default messages defined in 
`package.properties` are in English.
+
+If the default locale for your server is different, then rename 
`package.properties` to `package_en.properties` and
+create a new `package.properties` with proper values for your default locale.
diff --git a/apps/rest-showcase/README.txt b/apps/rest-showcase/README.txt
deleted file mode 100644
index 13f133be8..000000000
--- a/apps/rest-showcase/README.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-README.txt - Rest Showcase Webapp
-
-Rest Showcase is a simple example of REST app build with the REST plugin.
-
-For more on getting started with Struts, see 
-
-* http://cwiki.apache.org/WW/home.html
-
-I18N:
-=====
-Please note that this project was created with the assumption that it will be 
run
-in an environment where the default locale is set to English. This means that
-the default messages defined in package.properties are in English. If the 
default
-locale for your server is different, then rename package.properties to 
package_en.properties
-and create a new package.properties with proper values for your default locale.
diff --git a/apps/showcase/README.md b/apps/showcase/README.md
new file mode 100644
index 000000000..4d7bc6e84
--- /dev/null
+++ b/apps/showcase/README.md
@@ -0,0 +1,19 @@
+# Showcase
+
+> **WARNING:** This application is a demonstration/development tool only. It 
is **NOT** intended for production
+> deployment. It contains features such as source code viewing that 
intentionally expose internal application details.
+> Deploying this application on a publicly accessible server may pose security 
risks.
+
+Showcase is a collection of examples with code that you might adopt and adapt 
in your own applications.
+
+For more on getting started with Struts, see:
+
+- https://struts.apache.org/getting-started/
+
+## I18N
+
+Please note that this project was created with the assumption that it will be 
run in an environment where the default
+locale is set to English. This means that the default messages defined in 
`package.properties` are in English.
+
+If the default locale for your server is different, then rename 
`package.properties` to `package_en.properties` and
+create a new `package.properties` with proper values for your default locale.
diff --git a/apps/showcase/README.txt b/apps/showcase/README.txt
deleted file mode 100644
index 8e6cbb03c..000000000
--- a/apps/showcase/README.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-README.txt - showcase
-
-Showcase is a collection of examples with code that you might be adopt and 
-adapt in your own applications. 
-
-For more on getting started with Struts, see 
-
-* http://cwiki.apache.org/WW/home.html
-
-I18N:
-=====
-Please note that this project was created with the assumption that it will be 
run
-in an environment where the default locale is set to English. This means that
-the default messages defined in package.properties are in English. If the 
default
-locale for your server is different, then rename package.properties to 
package_en.properties
-and create a new package.properties with proper values for your default locale.
diff --git 
a/apps/showcase/src/main/java/org/apache/struts2/showcase/source/ViewSourceAction.java
 
b/apps/showcase/src/main/java/org/apache/struts2/showcase/source/ViewSourceAction.java
index 2cd4b5a1b..4f8c457cf 100644
--- 
a/apps/showcase/src/main/java/org/apache/struts2/showcase/source/ViewSourceAction.java
+++ 
b/apps/showcase/src/main/java/org/apache/struts2/showcase/source/ViewSourceAction.java
@@ -30,7 +30,9 @@ import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
+import java.net.URI;
 import java.net.URL;
+import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -90,7 +92,10 @@ public class ViewSourceAction extends ActionSupport 
implements ServletContextAwa
         if (config != null && config.startsWith("file:/")) {
             int pos = config.lastIndexOf(':');
             configLine = Integer.parseInt(config.substring(pos + 1));
-            configLines = read(new URL(config.substring(0, pos)).openStream(), 
configLine);
+            String fileUrl = config.substring(0, pos);
+            if (isAllowedConfigPath(fileUrl)) {
+                configLines = read(new URL(fileUrl).openStream(), configLine);
+            }
         }
         return SUCCESS;
     }
@@ -227,6 +232,24 @@ public class ViewSourceAction extends ActionSupport 
implements ServletContextAwa
         return snippet;
     }
 
+    /**
+     * Validates that the given file URL points to an XML file within the 
webapp's real path,
+     * preventing arbitrary file reads via crafted config parameters.
+     */
+    private boolean isAllowedConfigPath(String fileUrl) {
+        try {
+            Path filePath = Path.of(new URI(fileUrl)).toRealPath();
+            String realBasePath = servletContext.getRealPath("/");
+            if (realBasePath == null) {
+                return false;
+            }
+            Path basePath = Path.of(realBasePath).toRealPath();
+            return filePath.startsWith(basePath) && 
filePath.toString().endsWith(".xml");
+        } catch (Exception e) {
+            return false;
+        }
+    }
+
     @Override
     public void withServletContext(ServletContext arg0) {
         this.servletContext = arg0;

Reply via email to