From 7c38c932d6a94bd33b858b8874598209f2e6eb6e Mon Sep 17 00:00:00 2001 From: Lari Taskula Date: Thu, 5 Feb 2026 16:31:11 +0200 Subject: [PATCH] Bug 38365: Set limitations on endpoint input This patch attempts to set some sane input limits to the CSP violation report. To test: 1. Rebuild API redocly bundle --ext json api/v1/swagger/swagger.yaml --output api/v1/swagger/swagger_bundle.json 2. t/db_dependent/api/v1/public/csp_reports.t --- api/v1/swagger/definitions/csp_report.yaml | 14 +++++++++++ t/db_dependent/api/v1/public/csp_reports.t | 27 +++++++++++++++++++++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/api/v1/swagger/definitions/csp_report.yaml b/api/v1/swagger/definitions/csp_report.yaml index e175c911f2f..69793c0d925 100644 --- a/api/v1/swagger/definitions/csp_report.yaml +++ b/api/v1/swagger/definitions/csp_report.yaml @@ -11,37 +11,51 @@ properties: document-uri: type: string description: The URI of the document where the violation occurred + maxLength: 200 referrer: type: string description: The referrer of the document where the violation occurred + maxLength: 200 violated-directive: type: string description: The directive that was violated (e.g., "script-src 'self'") + maxLength: 100 effective-directive: type: string description: The effective directive that was violated + maxLength: 100 original-policy: type: string description: The original CSP policy as specified in the header + maxLength: 400 disposition: type: string description: Either "enforce" or "report" depending on CSP mode + enum: + - enforce + - report blocked-uri: type: string description: The URI of the resource that was blocked + maxLength: 200 line-number: type: integer description: Line number in the document where the violation occurred + maximum: 999999 column-number: type: integer description: Column number where the violation occurred + maximum: 999999 source-file: type: string description: The URI of the script where the violation occurred + maxLength: 200 status-code: type: integer description: HTTP status code of the document + maximum: 999 script-sample: type: string description: First 40 characters of the inline script that caused the violation + maxLength: 41 additionalProperties: true diff --git a/t/db_dependent/api/v1/public/csp_reports.t b/t/db_dependent/api/v1/public/csp_reports.t index aaa4b21eb8f..4b6d995825f 100755 --- a/t/db_dependent/api/v1/public/csp_reports.t +++ b/t/db_dependent/api/v1/public/csp_reports.t @@ -40,7 +40,7 @@ my $csp = Koha::ContentSecurityPolicy->new; subtest 'add() tests' => sub { - plan tests => 16; + plan tests => 22; $schema->storage->txn_begin; @@ -88,6 +88,31 @@ subtest 'add() tests' => sub { ->status_is( 400, 'CSP report denied (400)' ) ->json_is( '/error', 'This token has expired.', '...because of an expired token' ); + $csp_report->{'csp-report'}->{'line-number'} = 99999999999999999; + + # Anonymous request should reject too long integers + $t->post_ok( '/api/v1/public/csp-reports?token=' + . $csp->api_token => { 'Content-Type' => 'application/csp-report' } => json => $csp_report ) + ->status_is( 400, 'CSP report rejected (400) because of line-number exceeding maximum value' ); + $csp_report->{'csp-report'}->{'line-number'} = 42; + + $csp_report->{'csp-report'}->{'disposition'} = 'this is not okay'; + + # Anonymous request should reject values not in enum + $t->post_ok( '/api/v1/public/csp-reports?token=' + . $csp->api_token => { 'Content-Type' => 'application/csp-report' } => json => $csp_report ) + ->status_is( 400, 'CSP report rejected (400) because of disposition is not either "enforce" nor "report"' ); + $csp_report->{'csp-report'}->{'disposition'} = 'enforce'; + + $csp_report->{'csp-report'}->{'script-sample'} = + 'this is way too long script sample. a maximum of only 40 characters is allowed'; + + # Anonymous request should reject too long strings + $t->post_ok( '/api/v1/public/csp-reports?token=' + . $csp->api_token => { 'Content-Type' => 'application/csp-report' } => json => $csp_report ) + ->status_is( 400, 'CSP report rejected (400) because of script-sample exceeding maximum length' ); + $csp_report->{'csp-report'}->{'script-sample'} = 'console.log("hi");'; + # Anonymous request should work (browsers send these without auth) $t->post_ok( '/api/v1/public/csp-reports?token=' . $csp->api_token => { 'Content-Type' => 'application/csp-report' } => json => $csp_report ) -- 2.34.1