Skip to content

fix: harden PHP request parsing (post_max_size, max_input_nesting_level) - #586

Open
oc-tmueller wants to merge 3 commits into
masterfrom
fix/php-input-hardening
Open

oc-tmueller wants to merge 3 commits into
masterfrom
fix/php-input-hardening

Conversation

@oc-tmueller

@oc-tmueller oc-tmueller commented Oct 22, 2026 •

Copy link
Copy Markdown
Member

Post-patch hardening for CVE-2026-109618 / CVE-2026-109619, following Freexian's advice. The fixed PHP introduces a hard memory limit that kills the worker when it is reached, and post_max_size should stay below a quarter of memory_limit. Until now post_max_size followed OWNCLOUD_MAX_UPLOAD (20G); on ownCloud 10, .htaccess set it to 513M. Both are above the 512M memory_limit.

Changes, for both v22.04 and v24.04:

  • New OWNCLOUD_POST_MAX_SIZE, default 100M. It sets post_max_size in the ini and is also enforced in the vhost with php_admin_value, so ownCloud's .htaccess php_value post_max_size 513M can't raise it. upload_max_filesize stays on OWNCLOUD_MAX_UPLOAD.
  • max_input_nesting_level 64 → 6.
  • session.upload_progress.enabled = Off. GHSA-6wmf-4rv5-p3rp names it as the mod_php attack path for CVE-2026-109619 and recommends keeping it off after patching. Nothing in core or its bundled apps uses it (searched on 10.16.6 and 11.0.1). It is verified off at runtime under mod_php on both lines.
  • expose_php = Off is now set explicitly. Ubuntu's php.ini already had it off, so this changes no behaviour.
  • ENVIRONMENT.md and CHANGELOG.

Verified on local builds of both bases with the 10.16.6 and 11.0.1 server images on top:

  • Runtime post_max_size is 100M on both. On 10.16, .htaccess no longer wins: the published image reports 513M, and the published 11.0.1 reports 20G.
  • OWNCLOUD_POST_MAX_SIZE=200M gives 200M. max_input_nesting_level is 6 (published: 64). No X-Powered-By header.
  • A 200 MB WebDAV PUT returns 201 with the full size. A form POST to the OCS share API succeeds.
  • A 150 MB multipart POST is no longer parsed: one startup warning, no memory exhaustion. A 50 MB one still parses.
  • A raw POST body above the limit is still delivered whole through php://input (tested on PHP 7.4 and 8.3), so WOPI-style saves keep working.

Known side effects:

  • The Files web UI tooltip now reads "Upload (max. 100 MB)", because core shows min(upload_max_filesize, post_max_size). Uploads themselves are chunked WebDAV PUT and not limited by it.
  • Form or multipart POSTs above 100M are no longer parsed.
  • v20.04, which CI does not build, is left unchanged.

🤖 Generated with Claude Code

oc-tmueller and others added 2 commits October 22, 2026 16:39
post_max_size no longer follows OWNCLOUD_MAX_UPLOAD (20G). It defaults
to 100M, below a quarter of the 512M memory_limit as Freexian recommends
after CVE-2026-109618/-109619, is configurable with the new
OWNCLOUD_POST_MAX_SIZE, and is enforced with php_admin_value so that
ownCloud's .htaccess cannot raise it. max_input_nesting_level drops to
6, and expose_php = Off is made explicit. File uploads use WebDAV PUT
and are unaffected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Thomas Müller <323649642+oc-tmueller@users.noreply.github.com>
A value with a space no longer breaks Apache's config parsing. On
ownCloud 10, .htaccess pins memory_limit to 512M and upload_max_filesize
to 513M, so the environment variables do not set those there.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Thomas Müller <323649642+oc-tmueller@users.noreply.github.com>
@oc-tmueller
oc-tmueller marked this pull request as draft October 22, 2026 14:53
GHSA-6wmf-4rv5-p3rp names session upload progress as the confirmed
mod_php attack path for CVE-2026-109619 and recommends keeping it off
after patching. Nothing in ownCloud core or its bundled apps uses it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Thomas Müller <323649642+oc-tmueller@users.noreply.github.com>
@oc-tmueller

Copy link
Copy Markdown
Member Author

Compatibility with ownCloud 10.16.6 and 11.0.1

All checks below ran on images built from 2eef8ca, the head of this PR.

Acceptance tests

The full API and CLI acceptance suites passed on both lines with no regressions. Every scenario that came out differently from the published images is @local_storage locking, and it flips in both directions. owncloud-docker/server#738 runs the same suites in CI, and they are green for both lines.

Uploads and form parsing

Settings applied on both lines: post_max_size=100M (on 10.16 .htaccess can no longer raise it), max_input_nesting_level=6, session.upload_progress off.

10.16.6 11.0.1
WebDAV PUT of 150 MB 201, full size 201, full size
Chunked upload (v2), 3 × 50 MB assembled into 150 MB 201, full size 201, full size
application/octet-stream POST of 150 MB whole body in php://input whole body in php://input
Multipart POST of 50 MB parsed parsed
Multipart POST of 150 MB not parsed (intended); raw body still in php://input same
Form fields nested 5–6 levels deep kept kept
Form fields nested 7 levels deep dropped, other fields unaffected same

The 10.16 web UI uploads with WebDAV PUT (apps/files/js/file-upload.js), not multipart, so post_max_size doesn't limit it. Core's uploadLimit() now returns 100 MB on both lines. It only feeds the "Upload (max. 100 MB)" tooltip; nothing enforces it.

WOPI (Collabora / richdocuments)

Tested end to end with Collabora CODE 26.04.5.2: richdocuments 4.3.1 on 11.0.1, and 4.2.4 on 10.16.6.

  • A real editing session (open, edit, save) works on both lines. CODE saves with POST …/wopi/files/<id>/contents, Content-Type: application/octet-stream, X-WOPI-Override: PUT. richdocuments reads that body from php://input, which post_max_size doesn't limit.
  • PutFile with 150 MB and a real access token returns 200 on both lines, and the SHA-256 of the stored file matches what was sent.
  • PutRelativeFile (Save As) with 150 MB returns 200 on both lines, and the new file's SHA-256 matches.

WOPI (Microsoft Office Online)

Checked in the source of the wopi app (current release line and the ownCloud 10 line); not run end to end, because that needs Microsoft's service. PutFile and PutRelativeFile both read the raw body from php://input, and the access token comes from the query string. Neither depends on $_POST or $_FILES. As the table shows, a body over the limit stays in php://input whatever its Content-Type, so these saves keep working above 100 MB.

Side effects

  • Each WOPI save over 100 MB logs one Apache error-log warning: PHP Warning: POST Content-Length of … bytes exceeds the limit of 104857600 bytes. Nothing appears in owncloud.log.
  • Unrelated to this change: the wopi app's Save As reads the whole body into memory, so a Save As close to memory_limit (512M) can run out of memory. That limit was there before this PR.

🤖 Generated with Claude Code

@oc-tmueller
oc-tmueller marked this pull request as ready for review October 27, 2026 09:51
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