From 2ee992abf2ba987ae3d1f8c9a7eb6f75ba109a87 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 Signed-off-by: David Cook --- api/v1/swagger/definitions/csp_report.yaml | 17 ++++++++++++ t/db_dependent/api/v1/public/csp_reports.t | 32 ++++++++++++++++++++-- 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/api/v1/swagger/definitions/csp_report.yaml b/api/v1/swagger/definitions/csp_report.yaml index e175c911f2f..82bf9176ce8 100644 --- a/api/v1/swagger/definitions/csp_report.yaml +++ b/api/v1/swagger/definitions/csp_report.yaml @@ -11,37 +11,54 @@ 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 + minimum: 0 + maximum: 999999 column-number: type: integer description: Column number where the violation occurred + minimum: 0 + 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 + minimum: 0 + 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 40da813de6a..35862f107e8 100755 --- a/t/db_dependent/api/v1/public/csp_reports.t +++ b/t/db_dependent/api/v1/public/csp_reports.t @@ -36,7 +36,7 @@ t::lib::Mocks::mock_preference( 'RESTBasicAuth', 1 ); subtest 'add() tests' => sub { - plan tests => 7; + plan tests => 15; $schema->storage->txn_begin; @@ -52,11 +52,39 @@ subtest 'add() tests' => sub { 'blocked-uri' => 'inline', 'line-number' => 42, 'column-number' => 10, - 'source-file' => 'https://library.example.org/cgi-bin/koha/opac-main.pl', + 'source-file' => 'https://library.example.org/cgi-bin/koah/opac-main.pl', 'status-code' => 200, } }; + $csp_report->{'csp-report'}->{'line-number'} = 99999999999999999; + + # Too large integers should be rejected + $t->post_ok( '/api/v1/public/csp-reports' => { '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'} = -1; + + # Too small integers should be rejected + $t->post_ok( '/api/v1/public/csp-reports' => { 'Content-Type' => 'application/csp-report' } => json => $csp_report ) + ->status_is( 400, 'CSP report rejected (400) because of line-number not reaching minimum value' ); + $csp_report->{'csp-report'}->{'line-number'} = 42; + + $csp_report->{'csp-report'}->{'disposition'} = 'this is not okay'; + + # Enum values should be confirmed + $t->post_ok( '/api/v1/public/csp-reports' => { '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'; + + # Too long strings should be rejected + $t->post_ok( '/api/v1/public/csp-reports' => { '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' => { 'Content-Type' => 'application/csp-report' } => json => $csp_report ) ->status_is( 204, 'CSP report accepted' ); -- 2.39.5