This is an automated email from the ASF dual-hosted git repository.
tballison pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tika.git
The following commit(s) were added to refs/heads/main by this push:
new f235aae182 require enableUnsecureFeatures in /pipes and /async
handlers (#2902)
f235aae182 is described below
commit f235aae1822f90c023937548d3d95b60b56d92a1
Author: Tim Allison <[email protected]>
AuthorDate: Wed Jun 24 20:38:46 2026 -0400
require enableUnsecureFeatures in /pipes and /async handlers (#2902)
---
.../integration-testing/run-uat-script.adoc | 3 +-
.../advanced/integration-testing/tika-server.adoc | 17 +++++++++
docs/modules/ROOT/pages/advanced/robustness.adoc | 2 +-
.../migration-to-4x/migrating-tika-server-4x.adoc | 16 +++++++++
.../ROOT/pages/using-tika/server/index.adoc | 21 +++++++++++-
.../apache/tika/server/core/TikaServerConfig.java | 25 ++++++++++++++
.../tika/server/core/TikaServerConfigTest.java | 40 ++++++++++++++++++++++
.../configs/tika-config-server-basic.json | 1 +
.../configs/tika-config-server-emitter.json | 2 +-
.../configs/tika-config-server-pipes-basic.json | 1 +
...n => tika-config-server-pipes-no-unsecure.json} | 15 ++------
11 files changed, 127 insertions(+), 16 deletions(-)
diff --git
a/docs/modules/ROOT/pages/advanced/integration-testing/run-uat-script.adoc
b/docs/modules/ROOT/pages/advanced/integration-testing/run-uat-script.adoc
index 594e9e91ff..900cfedbc2 100644
--- a/docs/modules/ROOT/pages/advanced/integration-testing/run-uat-script.adoc
+++ b/docs/modules/ROOT/pages/advanced/integration-testing/run-uat-script.adoc
@@ -52,7 +52,8 @@ Coverage includes:
* `/language/stream`
* `/meta/form`, `/rmeta/form` (multipart variants)
* `enableUnsecureFeatures=false` gating: `/meta/config`, `/rmeta/config`,
- `/tika/config` all return 403
+ `/tika/config` all return 403; and selecting the `/pipes`, `/async`, or
`/status`
+ endpoints without `enableUnsecureFeatures` makes the server refuse to start
* `X-Tika-OCRskipOcr` header, `Content-Disposition` filename
* 404 / 405 error handling
diff --git
a/docs/modules/ROOT/pages/advanced/integration-testing/tika-server.adoc
b/docs/modules/ROOT/pages/advanced/integration-testing/tika-server.adoc
index 2608a6b490..d42d0a0644 100644
--- a/docs/modules/ROOT/pages/advanced/integration-testing/tika-server.adoc
+++ b/docs/modules/ROOT/pages/advanced/integration-testing/tika-server.adoc
@@ -214,6 +214,23 @@ curl -s -w "\nHTTP Status: %{http_code}\n" -X POST -F
"[email protected]" http:/
*Expected:* All return HTTP 403 with message: "Config endpoints are disabled.
Set enableUnsecureFeatures=true in server config."
+=== Test 18b: `/pipes`, `/async`, `/status` Require enableUnsecureFeatures
+
+[source,bash]
+----
+cat > tika-config-pipes-no-unsecure.json << 'EOF'
+{
+ "server": {"port": 9998, "endpoints": ["tika", "pipes"]},
+ "pipes": {"numClients": 2},
+ "plugin-roots": "/tmp/tika-server-test/plugins"
+}
+EOF
+
+java -jar tika-server-standard-4.0.0-SNAPSHOT.jar -c
tika-config-pipes-no-unsecure.json
+----
+
+*Expected:* The server refuses to start, failing with a `TikaConfigException`
stating that the `pipes` endpoint requires `enableUnsecureFeatures` to be
`true`. The same applies to `async` and `status`.
+
== Part 2: Tests with enableUnsecureFeatures
Stop the default server and create a config file:
diff --git a/docs/modules/ROOT/pages/advanced/robustness.adoc
b/docs/modules/ROOT/pages/advanced/robustness.adoc
index 784ba02463..170db7cf27 100644
--- a/docs/modules/ROOT/pages/advanced/robustness.adoc
+++ b/docs/modules/ROOT/pages/advanced/robustness.adoc
@@ -97,7 +97,7 @@ tika-server restarts gracefully.
tika-pipes::
Available through programmatic use, tika-app `-a` option, or tika-server's
`/async`
-and `/pipes` endpoints.
+and `/pipes` endpoints (the server endpoints require
`enableUnsecureFeatures=true`).
== Security Testing and Prevention
diff --git
a/docs/modules/ROOT/pages/migration-to-4x/migrating-tika-server-4x.adoc
b/docs/modules/ROOT/pages/migration-to-4x/migrating-tika-server-4x.adoc
index 4a18868ec4..59e8691e76 100644
--- a/docs/modules/ROOT/pages/migration-to-4x/migrating-tika-server-4x.adoc
+++ b/docs/modules/ROOT/pages/migration-to-4x/migrating-tika-server-4x.adoc
@@ -132,6 +132,22 @@ The following `TikaServerConfig` options have been removed:
* **Fetcher-based streaming** - The `InputStreamFactory` pattern for fetching
documents via HTTP headers (`fetcherName`, `fetchKey`) has been removed. All
documents are now processed via temp files through the pipes infrastructure.
+=== `/pipes`, `/async`, and `/status` Require `enableUnsecureFeatures`
+
+Previously these endpoints were enabled simply by listing them under
`server.endpoints`. They now *also* require `enableUnsecureFeatures` to be
`true`; selecting any of `pipes`, `async`, or `status` without it causes the
server to refuse to start with a clear error. `/pipes` and `/async` drive
process-isolated batch parsing through your fetchers and emitters, and
`/status` exposes server information, so this makes enabling them an explicit,
deliberate opt-in.
+
+**Migration:** if your config selects `pipes`, `async`, or `status`, add
`"enableUnsecureFeatures": true` to the `server` section:
+
+[source,json]
+----
+{
+ "server": {
+ "enableUnsecureFeatures": true,
+ "endpoints": ["tika", "rmeta", "pipes", "async", "status"]
+ }
+}
+----
+
== Configuration Changes
=== Required: Pipes Configuration
diff --git a/docs/modules/ROOT/pages/using-tika/server/index.adoc
b/docs/modules/ROOT/pages/using-tika/server/index.adoc
index 0c92d3e60f..ecec41df26 100644
--- a/docs/modules/ROOT/pages/using-tika/server/index.adoc
+++ b/docs/modules/ROOT/pages/using-tika/server/index.adoc
@@ -156,6 +156,11 @@ curl -T document.pdf
http://localhost:9998/meta/Content-Type # single field
* `/translate/all/\{translator}/\{src}/\{dest}` — translation
* `/pipes`, `/async` — Pipes-based bulk processing
+NOTE: `/pipes`, `/async`, and `/status` expose unsecure features and are only
available
+when `enableUnsecureFeatures` is `true` (see <<_security_configuration,Security
+Configuration>>). Selecting any of them without that flag causes the server to
refuse
+to start.
+
== Error Responses
When parsing fails due to a process-level problem — the forked child process
timed out,
@@ -207,7 +212,7 @@ Server behavior beyond host/port is controlled by a JSON
config file passed via
|`enableUnsecureFeatures`
|`false`
-|Enable the `/config` family of endpoints (see
<<_security_configuration,Security Configuration>>).
+|Required opt-in for unsecure features: the `/config` family of endpoints and
the `/pipes`, `/async`, and `/status` endpoints. The server refuses to start if
any of those endpoints are selected without this flag (see
<<_security_configuration,Security Configuration>>).
|`cors`
|`""` (off)
@@ -279,6 +284,20 @@ xref:using-tika/server/tls.adoc[2-way TLS authentication].
Exposing config endpo
to untrusted networks can help attackers identify vulnerabilities and craft
targeted attacks.
+=== Pipes, Async, and Status Endpoints
+
+The `/pipes`, `/async`, and `/status` endpoints also require
`enableUnsecureFeatures`.
+`/pipes` and `/async` drive process-isolated batch parsing through your
configured
+fetchers and emitters — whoever can reach them gains the read access of your
fetchers
+and the write access of your emitters (see
+https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2015-3271[CVE-2015-3271]);
`/status`
+exposes server information.
+
+In earlier releases these endpoints were enabled simply by listing them under
+`server.endpoints`. You must now *also* set `enableUnsecureFeatures` to `true`;
+selecting any of them without it causes the server to refuse to start. This is
+deliberate — it makes enabling these powerful endpoints an explicit,
considered choice.
+
=== Security Best Practices
1. **Keep config endpoints disabled** in production (default behavior).
diff --git
a/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/TikaServerConfig.java
b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/TikaServerConfig.java
index fa7bb3f93d..6eb1771af7 100644
---
a/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/TikaServerConfig.java
+++
b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/TikaServerConfig.java
@@ -58,6 +58,13 @@ public class TikaServerConfig {
"Additionally, /config endpoints allow per-request parser
configuration\n" +
"which could enable dangerous operations.\n" +
"Please make sure you know what you are doing.";
+ /**
+ * Endpoints that expose unsecure features (process-isolated pipes
parsing, async
+ * batch processing, and server status). Selecting any of these now
requires
+ * {@code enableUnsecureFeatures=true} as an explicit, deliberate opt-in.
+ */
+ private static final Set<String> ENDPOINTS_REQUIRING_UNSECURE_FEATURES =
+ new HashSet<>(Arrays.asList("pipes", "async", "status"));
private static final List<String> ONLY_IN_FORK_MODE = Arrays.asList(
new String[]{"maxFiles", "javaPath", "maxRestarts", "numRestarts",
"forkedStatusFile", "maxForkedStartupMillis",
"tmpFilePrefix"});
@@ -168,6 +175,24 @@ private long forkedProcessShutdownMillis =
DEFAULT_FORKED_PROCESS_SHUTDOWN_MILLI
if (host == null) {
throw new TikaConfigException("Must specify 'host'");
}
+ if (!enableUnsecureFeatures) {
+ List<String> requireUnsecure = new ArrayList<>();
+ for (String endpoint : endpoints) {
+ if (ENDPOINTS_REQUIRING_UNSECURE_FEATURES.contains(endpoint)
+ && !requireUnsecure.contains(endpoint)) {
+ requireUnsecure.add(endpoint);
+ }
+ }
+ if (!requireUnsecure.isEmpty()) {
+ throw new TikaConfigException(
+ "The following selected endpoint(s) require unsecure
features to be " +
+ "enabled: " + requireUnsecure + ". Set
'enableUnsecureFeatures' to true " +
+ "in the 'server' section of your tika-config and
confirm you understand " +
+ "the security implications (see the tika-server
documentation). These " +
+ "endpoints were previously enabled simply by selecting
them; the explicit " +
+ "opt-in is now required.");
+ }
+ }
}
public String getHost() {
diff --git
a/tika-server/tika-server-core/src/test/java/org/apache/tika/server/core/TikaServerConfigTest.java
b/tika-server/tika-server-core/src/test/java/org/apache/tika/server/core/TikaServerConfigTest.java
index 411317d6ef..d4920f04fe 100644
---
a/tika-server/tika-server-core/src/test/java/org/apache/tika/server/core/TikaServerConfigTest.java
+++
b/tika-server/tika-server-core/src/test/java/org/apache/tika/server/core/TikaServerConfigTest.java
@@ -18,6 +18,7 @@ package org.apache.tika.server.core;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.nio.file.Path;
@@ -32,6 +33,7 @@ import org.apache.commons.cli.Options;
import org.junit.jupiter.api.Test;
import org.apache.tika.TikaTest;
+import org.apache.tika.exception.TikaConfigException;
import org.apache.tika.utils.ProcessUtils;
public class TikaServerConfigTest extends TikaTest {
@@ -76,6 +78,44 @@ public class TikaServerConfigTest extends TikaTest {
TikaServerConfig config = TikaServerConfig.load(commandLine);
}
+ @Test
+ public void testUnsecureEndpointRequiresEnableUnsecureFeatures() throws
Exception {
+ // Selecting /pipes (or /async, /status) without
enableUnsecureFeatures must fail
+ // at config load, forcing an explicit opt-in.
+ CommandLineParser parser = new DefaultParser();
+ Path path = getConfigPath(getClass(),
"tika-config-server-pipes-no-unsecure.json");
+ CommandLine commandLine = parser.parse(new Options()
+ .addOption(Option
+ .builder("c")
+ .longOpt("config")
+ .hasArg()
+ .get()), new String[]{"-c",
ProcessUtils.escapeCommandLine(path
+ .toAbsolutePath()
+ .toString())});
+ TikaConfigException ex = assertThrows(TikaConfigException.class,
+ () -> TikaServerConfig.load(commandLine));
+ assertContains("enableUnsecureFeatures", ex.getMessage());
+ assertContains("pipes", ex.getMessage());
+ }
+
+ @Test
+ public void testUnsecureEndpointAllowedWithEnableUnsecureFeatures() throws
Exception {
+ // tika-config-server-basic.json selects the 'status' endpoint
together with
+ // enableUnsecureFeatures=true, so it must load without error.
+ CommandLineParser parser = new DefaultParser();
+ Path path = getConfigPath(getClass(), "tika-config-server-basic.json");
+ CommandLine commandLine = parser.parse(new Options()
+ .addOption(Option
+ .builder("c")
+ .longOpt("config")
+ .hasArg()
+ .get()), new String[]{"-c",
ProcessUtils.escapeCommandLine(path
+ .toAbsolutePath()
+ .toString())});
+ TikaServerConfig config = TikaServerConfig.load(commandLine);
+ assertTrue(config.isEnableUnsecureFeatures());
+ }
+
@Test
public void testTlsConfig() throws Exception {
Set<String> settings = new HashSet<>();
diff --git
a/tika-server/tika-server-core/src/test/resources/configs/tika-config-server-basic.json
b/tika-server/tika-server-core/src/test/resources/configs/tika-config-server-basic.json
index a14eda47ae..41d8acb90b 100644
---
a/tika-server/tika-server-core/src/test/resources/configs/tika-config-server-basic.json
+++
b/tika-server/tika-server-core/src/test/resources/configs/tika-config-server-basic.json
@@ -8,6 +8,7 @@
},
"server": {
"port": 9999,
+ "enableUnsecureFeatures": true,
"endpoints": [
"rmeta",
"status",
diff --git
a/tika-server/tika-server-core/src/test/resources/configs/tika-config-server-emitter.json
b/tika-server/tika-server-core/src/test/resources/configs/tika-config-server-emitter.json
index ce5f4a6f51..60a672a866 100644
---
a/tika-server/tika-server-core/src/test/resources/configs/tika-config-server-emitter.json
+++
b/tika-server/tika-server-core/src/test/resources/configs/tika-config-server-emitter.json
@@ -8,7 +8,7 @@
},
"server": {
"port": 9999,
- "enableUnsecure": true,
+ "enableUnsecureFeatures": true,
"endpoints": [
"emit",
"async",
diff --git
a/tika-server/tika-server-core/src/test/resources/configs/tika-config-server-pipes-basic.json
b/tika-server/tika-server-core/src/test/resources/configs/tika-config-server-pipes-basic.json
index 86a24fa4c3..2b7ed5a22b 100644
---
a/tika-server/tika-server-core/src/test/resources/configs/tika-config-server-pipes-basic.json
+++
b/tika-server/tika-server-core/src/test/resources/configs/tika-config-server-pipes-basic.json
@@ -8,6 +8,7 @@
},
"server": {
"port": 9999,
+ "enableUnsecureFeatures": true,
"endpoints": [
"rmeta",
"status",
diff --git
a/tika-server/tika-server-core/src/test/resources/configs/tika-config-server-pipes-basic.json
b/tika-server/tika-server-core/src/test/resources/configs/tika-config-server-pipes-no-unsecure.json
similarity index 55%
copy from
tika-server/tika-server-core/src/test/resources/configs/tika-config-server-pipes-basic.json
copy to
tika-server/tika-server-core/src/test/resources/configs/tika-config-server-pipes-no-unsecure.json
index 86a24fa4c3..262f29d7a8 100644
---
a/tika-server/tika-server-core/src/test/resources/configs/tika-config-server-pipes-basic.json
+++
b/tika-server/tika-server-core/src/test/resources/configs/tika-config-server-pipes-no-unsecure.json
@@ -9,21 +9,12 @@
"server": {
"port": 9999,
"endpoints": [
- "rmeta",
- "status",
- "tika"
+ "tika",
+ "pipes"
]
},
- "parse-context": {
- "timeout-limits": {
- "progressTimeoutMillis": 5000
- }
- },
"pipes": {
- "numClients": 2,
- "forkedJvmArgs": [
- "-Xmx256m"
- ]
+ "numClients": 2
},
"plugin-roots": "target/plugins"
}