Skip to content

require application/json on tika-server /pipes and /async - #3442

Open
mrdevel2002-ui wants to merge 1 commit into
apache:mainfrom
mrdevel2002-ui:pipes-async-consumes-json
Open

mrdevel2002-ui wants to merge 1 commit into
apache:mainfrom
mrdevel2002-ui:pipes-async-consumes-json

Conversation

@mrdevel2002-ui

Copy link
Copy Markdown
Contributor

PipesResource.postRmeta and AsyncResource.post have no @Consumes, so they parse the FetchEmitTuple JSON whatever the request's Content-Type is. That makes /pipes and /async reachable by a cross-site request. A page on any origin can call fetch("http://tika:9998/pipes", {method: "POST", mode: "no-cors", body: tupleJson}). The body goes out as text/plain (or untyped, for a Blob body), which is a CORS simple request, so the browser sends it with no preflight. The server then runs the fetch, parse and emit with the operator's fetchers and emitters. For example, it can make an http fetcher request an internal URL, or read a file through a file-system fetcher and write it out through the configured emitter. The attacker can't read the response, but the side effects happen. tika-server has no caller authentication, and the security model relies on keeping it on a trusted network. A browser inside that network gets round that restriction, and DNS rebinding reaches the same calls.

Both handlers now declare @Consumes("application/json"). A cross-origin application/json POST needs a preflight, which the server won't grant unless the operator configures cors. This is the content type the documented curl examples already send. The trade-off is that a client posting the tuple JSON as text/plain, or with no Content-Type, now gets 415. I chose this over refusing only the safelisted types, because an untyped body is still a simple request. This is the only JSON-body POST route in tika-server. The other POST routes are multipart and behind allowPerRequestConfig, so they are left alone here.

testCrossSiteSimpleRequestIsRefused in TikaPipesTest posts a valid tuple as text/plain, as form-urlencoded and with no Content-Type. It expects 415 each time and checks that nothing was emitted. On main it fails with expected: <415> but was: <200>. The existing pipes and async tests used WebClient.post without a type, so they now declare application/json. ./mvnw clean install is green for tika-server-core (238 tests) and tika-server-standard (145 tests), including checkstyle, spotless and forbidden-apis.

  • open issue on the Tika issue tracker: not filed yet, happy to open one or have it linked
  • issue ID in the PR title and commit message: pending the issue above
  • commits are squashed into a single one
  • Tika builds and unit tests pass with ./mvnw clean install (tika-server-core and tika-server-standard)
  • generative AI tool used: the commit carries Generated-by: per the ASF Generative Tooling Guidance
  • no conflicts with the recent main branch
  • no new module

Without @consumes both handlers read the tuple JSON under any
Content-Type, so a browser can submit one cross-site as a text/plain,
form-urlencoded or untyped POST with no CORS preflight.

Generated-by: Claude Code
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant