Skip to content

fix: prevent appconfig path traversal to RCE via public_/remote_ keys (OC10-146) - #41803

Open
oc-tmueller wants to merge 1 commit into
10.16from
fix/oc10-146-appconfig-path-traversal
Open

fix: prevent appconfig path traversal to RCE via public_/remote_ keys (OC10-146)#41803
oc-tmueller wants to merge 1 commit into
10.16from
fix/oc10-146-appconfig-path-traversal

Conversation

@oc-tmueller

Copy link
Copy Markdown

Summary

An authenticated admin could set the core appconfig key public_webdav (or any public_/remote_ key) to a path-traversal value and have it require_once'd by public.php on the next GET /public.php/webdav, achieving remote code execution.

Two independent defects made this possible; both are fixed here (defense in depth).

1. Sink — public.php had no traversal check (essential fix)

public.php included the stored handler path relative to the app directory with no traversal guard, unlike remote.php which already rejects ../. Added the same guard so a traversal path can never be included — this is the DB- and endpoint-independent gate.

2. Guard bypass — strict $app === 'core' compare

AppConfigController blocked admins from setting public_/remote_ keys on core with a strict $app === 'core' compare. A mangled app id such as "core " (trailing space) is not equal to "core" in PHP, yet the database folds it back to the core row — defeating the guard. This is the same defeat mechanism as the earlier core%81 truncation bypass. The app id is now normalized (cleanAppId + trim + strtolower) before the check, in:

  • AppConfigController::getValue/setValue/deleteKey
  • the legacy core/ajax/appconfig.php endpoint
  • and deleteApp now refuses to wipe the whole core appconfig.

Tests

Adds regression tests covering the mangled core spellings ("core ", " core", "CORE", "core/", "core..") and allowed near-misses (encore, non-service keys on core).

Verified in the ownCloud CI toolchain (PHP 7.4, PHPUnit 9.6, sqlite): OK — 40 tests, 105 assertions. Reverting the guard to the strict compare makes 13 of the new cases fail, confirming they catch the bypass.


Resubmission of #41802, re-authored and SSH-signed under @oc-tmueller.

… (OC10-146)

An authenticated admin could set the core appconfig key `public_webdav`
(or any `public_`/`remote_` key) to a path-traversal value and have it
`require_once`'d by public.php on the next `GET /public.php/webdav`,
achieving remote code execution.

Two independent defects made this possible:

1. Sink: public.php included the stored handler path relative to the app
   directory with no traversal check, unlike remote.php which already
   rejects `../`. This is the essential, DB-independent gate: add the same
   guard so a traversal path can never be included.

2. Guard bypass: AppConfigController used a strict `$app === 'core'` compare
   to block admins from setting `public_`/`remote_` keys on core. A mangled
   app id such as `"core "` (trailing space) is not equal to `"core"` in PHP
   yet the database folds it back to the core row, defeating the guard. This
   is the same defeat mechanism as OC10-5 (`core%81` truncation). Normalize
   the app id (cleanAppId + trim + strtolower) before the check, in both the
   controller (getValue/setValue/deleteKey) and the legacy core/ajax/appconfig.php
   endpoint, and block deleting the whole core appconfig via deleteApp.

Adds regression tests covering the mangled `core` spellings and the
allowed near-misses.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@CLAassistant

CLAassistant commented Sep 2, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

app-id guard can no longer be bypassed by mangled spellings such as a trailing
space.

https://github.com/owncloud/core/pull/41802

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do we do about this?

The PR number is off-by-one. The master PR #41804 has the correct numbers.

@phil-davis phil-davis left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@oc-tmueller you can decide if you update the PR number in the changelog entry.

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.

3 participants