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

tballison pushed a commit to branch TIKA-4809-stage-3
in repository https://gitbox.apache.org/repos/asf/tika.git

commit 559dd58f291b169c3d5b707c52495daf4f533944
Author: tallison <[email protected]>
AuthorDate: Sun Aug 9 16:18:22 2026 -0400

    TIKA-4809: Correct security claims in serialization, design-notes and 
filesystem docs
---
 .../modules/ROOT/pages/developers/serialization.adoc | 20 ++++++++++++++++++++
 .../ROOT/pages/migration-to-4x/design-notes-4x.adoc  |  8 ++++++++
 .../modules/ROOT/pages/pipes/plugins/filesystem.adoc | 11 ++++++-----
 3 files changed, 34 insertions(+), 5 deletions(-)

diff --git a/docs/modules/ROOT/pages/developers/serialization.adoc 
b/docs/modules/ROOT/pages/developers/serialization.adoc
index 122589731d..d8477966b3 100644
--- a/docs/modules/ROOT/pages/developers/serialization.adoc
+++ b/docs/modules/ROOT/pages/developers/serialization.adoc
@@ -241,6 +241,26 @@ The serialization system implements a security allowlist:
 This prevents attacks where malicious JSON specifies dangerous classes
 for instantiation.
 
+[IMPORTANT]
+====
+The allowlist governs *which components may be instantiated* from JSON. It does
+not restrict *how an already-loaded component may be configured*.
+
+Self-configuring components — which includes every `Parser`, since `Parser`
+extends `SelfConfiguring` — are skipped by the wire-block scan
+(`ParseContextDeserializer.assertNoBlockedComponents`): their config subtree is
+passed through to the component unexamined. So while a request cannot bind a 
new
+`Parser` from the wire, a request carrying
+`{"parse-context": {"pdf-parser": {"ocr": {"strategy": 
"OCR_AND_TEXT_EXTRACTION"}}}}`
+will reach `PDFParser` and take effect.
+
+That is why per-request configuration is gated separately by
+`allowPerRequestConfig`, which is off by default. Treat "the caller may supply
+per-request config" as equivalent to "the caller may set any parser option,
+including options that spawn external processes such as OCR" — not as something
+the allowlist constrains.
+====
+
 [source,java]
 ----
 // This will FAIL - class not registered
diff --git a/docs/modules/ROOT/pages/migration-to-4x/design-notes-4x.adoc 
b/docs/modules/ROOT/pages/migration-to-4x/design-notes-4x.adoc
index 7913fafefb..f6053f808d 100644
--- a/docs/modules/ROOT/pages/migration-to-4x/design-notes-4x.adoc
+++ b/docs/modules/ROOT/pages/migration-to-4x/design-notes-4x.adoc
@@ -74,6 +74,14 @@ may be bound from the wire; `Parser`, `Detector`, 
`Renderer`, and similar are
 blocked before anything is constructed. See
 xref:developers/serialization.adoc[Serialization and Configuration].
 
+Note the boundary: the allowlist blocks *binding a component* from the wire, 
not
+*configuring one that is already loaded*. Self-configuring components — every
+`Parser` among them — have their config subtree passed through unscanned, so a
+per-request config can still set parser options (including ones that spawn
+external processes, such as OCR). This is why `allowPerRequestConfig` is a
+separate gate and is off by default; the allowlist alone does not make
+per-request configuration safe to expose.
+
 === Implementation Challenges
 
 * Converted code to true Java beans with matching getters/setters
diff --git a/docs/modules/ROOT/pages/pipes/plugins/filesystem.adoc 
b/docs/modules/ROOT/pages/pipes/plugins/filesystem.adoc
index 034a5d7b93..2a13b5d068 100644
--- a/docs/modules/ROOT/pages/pipes/plugins/filesystem.adoc
+++ b/docs/modules/ROOT/pages/pipes/plugins/filesystem.adoc
@@ -81,8 +81,8 @@ The outer key (`fsf`) is the fetcher ID — referenced by 
`pipesIterator.fetcher
 |Field |Default |Description
 
 |`basePath`
-|_required_
-|Base directory for fetch operations. Fetch keys are resolved relative to this 
path.
+|_none_
+|Base directory for fetch operations. Fetch keys are resolved relative to this 
path and must stay inside it. Not technically required, but omitting it 
disables containment entirely — see `allowAbsolutePaths` below and 
<<security-notes>>.
 
 |`extractFileSystemMetadata`
 |`false`
@@ -90,7 +90,7 @@ The outer key (`fsf`) is the fetcher ID — referenced by 
`pipesIterator.fetcher
 
 |`allowAbsolutePaths`
 |`false`
-|When `true`, fetch keys may be absolute paths and `basePath` may be omitted. 
Use sparingly — see <<security-notes>>.
+|Permission to run *without* a `basePath`. It is not a relaxation of 
`basePath` — see <<security-notes>>.
 |===
 
 [#file-system-emitter]
@@ -253,6 +253,7 @@ Tradeoffs:
 [#security-notes]
 == Security Notes
 
-* **`basePath` is a sandbox boundary.** The fetcher and emitter reject 
fetch/emit keys that resolve outside `basePath`. Do not set 
`allowAbsolutePaths=true` unless the source of fetch keys is fully trusted — an 
attacker-controlled fetch key could otherwise read arbitrary files.
-* **Symlinks are followed.** A symlink under `basePath` pointing outside 
`basePath` may still be readable. If you need strict containment, do not allow 
symlinks in your input tree.
+* **`basePath` is the sandbox boundary, and it is the only one.** With 
`basePath` set, the fetcher and emitter reject any key that resolves outside 
it, including absolute paths and `../` traversal. `allowAbsolutePaths` has no 
effect in this state.
+* **Without `basePath` there is no containment at all.** The key is used as a 
raw absolute path, and the containment checks are skipped entirely. 
`allowAbsolutePaths=true` is how you assert that you intend this; it is a 
switch between two states, not a dial that loosens `basePath`. For the fetcher 
this means any file the process can read; for the emitter, any file it can 
write. Use it only when fetch/emit keys come from a fully trusted source and 
access to the service is restricted by ot [...]
+* **Symlink containment differs between fetcher and emitter.** The fetcher 
re-checks with `toRealPath()`, so a symlink under `basePath` pointing outside 
it is rejected. The emitter does not: it checks only the normalized path, so a 
symlink already present under its `basePath` can be written through. Do not 
rely on symlinks being contained on the emit side.
 * **Output directories are created automatically.** The emitter creates 
intermediate directories as needed. Make sure the process's umask is 
appropriate for the data being written.

Reply via email to