Skip to content

fix: split large Content-Security-Policy headers over multiple HTTP headers - #60337

Open
n-iv wants to merge 1 commit into
nextcloud:masterfrom
n-iv:fix/csp-header-split-for-large-policies
Open

fix: split large Content-Security-Policy headers over multiple HTTP headers#60337
n-iv wants to merge 1 commit into
nextcloud:masterfrom
n-iv:fix/csp-header-split-for-large-policies

Conversation

@n-iv

@n-iv n-iv commented May 12, 2026

Copy link
Copy Markdown
Contributor

Summary

When the Content-Security-Policy header exceeds 7800 bytes, split it into multiple header() calls. Apache mod_proxy_fcgi otherwise fails with AH01070 Error parsing script headers and returns HTTP 500 because
HUGE_STRING_LEN is hardcoded at 8192 bytes in httpd.h and is used to parse FCGI response headers. Raising this limit by recompiling Apache does not fix the issue (other related FCGI buffer limits sit at the same value).

The split is performed only between directives, never inside one. Per CSP Level 3 §3.1, multiple CSP headers are enforced as the intersection of the conveyed policies, so behavior is unchanged for compliant clients.

Checklist

AI (if applicable)

  • The content of this PR was partly or fully generated using AI

Copilot AI review requested due to automatic review settings May 12, 2026 21:18
@n-iv
n-iv requested a review from a team as a code owner May 12, 2026 21:18
@n-iv
n-iv requested review from ArtificialOwl, icewind1991, leftybournes and provokateurin and removed request for a team May 12, 2026 21:18

Copilot AI 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.

Pull request overview

This PR addresses Apache mod_proxy_fcgi failures caused by oversized Content-Security-Policy response headers by splitting long CSP/Feature-Policy values into multiple header() calls (splitting only between directives) to stay under a safe per-header length threshold.

Changes:

  • Add logic in the HTTP output layer to split large Content-Security-Policy and Feature-Policy headers into multiple header lines.
  • Keep splitting boundaries at directive separators (;) to avoid splitting inside directives.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread lib/private/AppFramework/Http/Output.php Outdated
Comment thread lib/private/AppFramework/Http/Output.php Outdated
Comment thread lib/private/AppFramework/Http/Output.php Outdated
Comment thread lib/private/AppFramework/Http/Output.php Outdated
@kesselb

kesselb commented May 12, 2026

Copy link
Copy Markdown
Contributor

cc @skjnldsv could be related to nextcloud/documentation#13803

@skjnldsv

Copy link
Copy Markdown
Member

cc @skjnldsv could be related to nextcloud/documentation#13803

Was thinking the same!!

Comment thread lib/private/AppFramework/Http/Output.php Outdated
Comment thread lib/private/AppFramework/Http/Output.php Outdated
Comment thread lib/private/AppFramework/Http/Output.php
Comment thread lib/private/AppFramework/Http/Output.php
@susnux susnux added the bug label May 19, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Hello there,
Thank you so much for taking the time and effort to create a pull request to our Nextcloud project.

We hope that the review process is going smooth and is helpful for you. We want to ensure your pull request is reviewed to your satisfaction. If you have a moment, our community management team would very much appreciate your feedback on your experience with this PR review process.

Your feedback is valuable to us as we continuously strive to improve our community developer experience. Please take a moment to complete our short survey by clicking on the following link: https://cloud.nextcloud.com/apps/forms/s/i9Ago4EQRZ7TWxjfmeEpPkf6

Thank you for contributing to Nextcloud and we hope to hear from you soon!

(If you believe you should not receive this message, you can add yourself to the blocklist.)

@skjnldsv
skjnldsv force-pushed the fix/csp-header-split-for-large-policies branch from bd7e780 to ef604a0 Compare June 5, 2026 12:39
@skjnldsv skjnldsv added the 3. to review Waiting for reviews label Jun 5, 2026
@skjnldsv
skjnldsv requested review from come-nc, kesselb, pringelmann and provokateurin and removed request for ArtificialOwl June 5, 2026 12:39
@skjnldsv

skjnldsv commented Jun 5, 2026

Copy link
Copy Markdown
Member

@n-iv could you squash your commits into one again please? :)
I added some more coworkers to see if they can review. Please note that your PR is a good idea I think, but we're right in the middle of RC/final releases, so our availability is a bit scarce a the moment 😉

@n-iv
n-iv force-pushed the fix/csp-header-split-for-large-policies branch from 7b084c6 to e445372 Compare June 8, 2026 11:23
…eaders

Signed-off-by: niv <nicolas.varlot@ac-versailles.fr>
@n-iv

n-iv commented Jun 8, 2026

Copy link
Copy Markdown
Contributor Author

Hi @skjnldsv

I squashed my commits. Np for your availability, mine is quite low too :)

@susnux susnux added the community pull requests from community label Jun 9, 2026
@susnux susnux added this to the Nextcloud 35 milestone Jun 9, 2026
@skjnldsv

skjnldsv commented Jul 21, 2026

Copy link
Copy Markdown
Member

Soooo, I had another look:

The split logic only breaks between directives, never inside one. Makes sense, if you split one directive's list of allowed sources across two headers, the browser treats each header as a seperate policy and only allows what both agree on, so splitting mid directive would probably end up blocking stuff that shoud be allowed. But that also means if a single directive (script-src, connect-src, img-src etc, these get built up from every app's allowed domains) is itself over ~7800 bytes on its own, this fix doesnt help. It'll just emit that one oversized directive as is and were back to the same AH01070 error. Given how many apps push domains onto those directives (federation, external storage, collabora, s3 previews...) I think thats a pretty plausible real world case, not just a rare edge case. Could you test with a policy where one single directive alone is already past the limit, rather then lots of small ones adding up togehter?

Also, are the domain lists deduped anywhere before buildPolicy() runs? If two apps add the same domain it'll show up twice and waste bytes for free, might buy some headroom cheap.

Last thing, tests are unchecked in the PR checklist and OutputTest.php currently has zero coverage of setHeader() at all. This will need tests before merge imho, normal header passthrough, the multi header split case, and ideally the one giant directive case too, however that ends up handled.

@nextcloud-bot nextcloud-bot mentioned this pull request Aug 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

3. to review Waiting for reviews bug community pull requests from community feedback-requested

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants