This patch addresses CSV formula injection vulnerabilities by ensuring
all Text::CSV instances use formula protection.
Changes made:
* Add formula => 'empty' to all Text::CSV constructors in:
- Koha::Patrons::Import
- Koha::BackgroundJob::ImportKBARTFile
- Koha::ERM::EUsage::CounterFile
The 'empty' formula mode causes potentially dangerous formulas (starting
with =, +, -, @) to be treated as empty strings rather than executed,
preventing CSV injection attacks while maintaining data integrity.
Security impact:
* Prevents execution of malicious formulas in CSV imports
* Protects against data exfiltration via CSV formula injection
* Maintains backward compatibility for legitimate CSV data
To test:
1. Apply the previous patch (author test)
2. Run:
$ ktd --shell
k$ prove xt/author/Text_CSV_Various.t
=> FAIL: Should show 3 files without formula protection
3. Apply this patch
4. Repeat 2
=> SUCCESS: All tests should now pass
5. Try importing CSV with formula content (=cmd|"/c calc",test,data)
=> SUCCESS: Formula content is rejected/emptied, not executed
6. Import normal CSV data
=> SUCCESS: Normal data imports correctly
7. Sign off :-D
Signed-off-by: David Cook <dcook@prosentient.com.au>
Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de>
Signed-off-by: Jesse Maseto <jesse@bywatersolutions.com>
This test ensures all Text::CSV usage in Koha includes proper formula
injection protection to prevent CSV formula injection attacks.
The test scans all Perl modules and verifies that Text::CSV constructors
include the 'formula' parameter set to a safe mode ('empty', 'die',
'croak', 'diag', or numeric 1-5).
To test:
1. Apply this patch
2. Run:
$ ktd --shell
k$ prove xt/author/Text_CSV_Various.t
=> FAIL: Test should fail showing files without formula protection:
- Koha/Patrons/Import.pm
- Koha/BackgroundJob/ImportKBARTFile.pm
- Koha/ERM/EUsage/CounterFile.pm
3. Apply the follow-up patch to fix the violations
4. Repeat 2
=> SUCCESS: All tests should pass
5. Sign off :-D
Signed-off-by: David Cook <dcook@prosentient.com.au>
Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de>
Signed-off-by: Jesse Maseto <jesse@bywatersolutions.com>
This patch fixes a XSS vulnerability in the
suspend hold modal in the staff interface.
By building our Javascript using Web APIs rather
than with strings and jQuery's html() method,
we're able to securely handle malicious payloads.
Test plan:
0. Apply the patch
1. Go to http://localhost:8081/cgi-bin/koha/reserve/request.pl?biblionumber=29
2. Add a hold for "koha" patron
3. Go to http://localhost:8081/cgi-bin/koha/circ/circulation.pl?borrowernumber=51
4. Click "Holds" tab and click "Suspend"
5. Note the modal loads properly
6. Go to http://localhost:8081/cgi-bin/koha/members/moremember.pl?borrowernumber=51
7. Click "Holds" tab and click "Suspend"
8. Note the modal loads properly
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
Signed-off-by: Marcel de Rooy <m.de.rooy@rijksmuseum.nl>
Bug 40538: Simplify code
Signed-off-by: Marcel de Rooy <m.de.rooy@rijksmuseum.nl>
Signed-off-by: Jesse Maseto <jesse@bywatersolutions.com>
See also comment33, point 4.
Test plan:
cp debian/templates/apache-shared-opac-antibot.conf /etc/koha/
Test enabling/disabling by toggling the comment of the SetEnvIf line,
restart apache and remove the KOHA_INIT and CGISESSID cookie.
Signed-off-by: Marcel de Rooy <m.de.rooy@rijksmuseum.nl>
Signed-off-by: Jesse Maseto <jesse@bywatersolutions.com>
This patch adds a fast simple bot challenge via Apache.
To test:
0. Apply the patch
1. sudo cp debian/templates/apache-shared-opac-antibot.conf /etc/koha/.
2. sudo cp debian/templates/apache-shared-opac-plack.conf /etc/koha/.
3. curl http://localhost:8080/cgi-bin/koha/opac-search.pl
4. Note an instant response with a very simple HTML response
5. Open an incognito browser and go to http://localhost:8080/cgi-bin/koha/opac-search.pl
6. Note a very brief loading animation before the OPAC search page appearing
7. Do a search
8. Note no more loading animation appears
9. Close the incognito browser
10. Open an incognito browser and go to http://localhost:8080/cgi-bin/koha/opac-main.pl
11. Do a search via the "Library catalog" search bar
12. Note no loading animation appears
Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>
Signed-off-by: Cornelius Hertfelder <cornelius.hertfelder@bsz-bw.de>
Signed-off-by: Magnus Enger <magnus@libriotech.no>
We have tested this in production on at least three live sites for
several weeks, and it has worked as expected. We have not noticed any
negative side effects.
Signed-off-by: Marcel de Rooy <m.de.rooy@rijksmuseum.nl>
Signed-off-by: Jesse Maseto <jesse@bywatersolutions.com>
This patch updates the teams.yaml to include the voted in 25.11
release team.
Test plan
1/ Check against https://wiki.koha-community.org/wiki/Release_Teams
Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Jesse Maseto <jesse@bywatersolutions.com>
To test:
1 - Remove age limits from a Child and Adult category in Administration->Patron categories. Ensure Child category can be guarantor and Adult cannot
2 - The above step is to avoid any age checks and form resubmission which removes the guarantor fields
3 - Find/create a child patron
4 - Add a guarantee from the Adult category to the child
5 - Check the DB:
SELECT * FROM borrower_relationships WHERE guarantee_id={borrowernumber of child};
6 - Note the id colum
7 - Edit the child patron to Adult category
8 - Repeat 5
9 - Note the relationship still exists and the id is incremented
10 - Oof!
11 - APPLY PATCH, restart_all
12 - Try again steps 3 - 8
13 - The relationship should not be re-added
14 - Try with more than 1 guarantor on the record, confirming all are deleted
15 - Try adding some guarantor to patron types that should be able to, they relationship should work.
16 - Try changing some patrons to categories that do allow guarantors, making sure the relationship does stay.
Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Baptiste Wojtkowski <baptiste.wojtkowski@biblibre.com>
Signed-off-by: Jesse Maseto <jesse@bywatersolutions.com>
This fixes checkout fields being made available to the public API.
Note: This depends on the fix at Bug 39313, so make sure you apply that
first.
To test:
1. Enabled OpacTrustedCheckout system preference
2. Search for an item and get the barcode
3. Go to the OPAC
4. Click the Self-checkout button at the top
5. Enter the barcode and submit
6. Notice that the due date does not show in the modal, even though the
due date was correctly set
7. Apply the patch and restart services
8. Go to the staff interface and check in your barcode
9. Repeat steps 3-5
10. Confirm the due date does show correctly in the modal
11. Confirm tests pass t/db_dependent/Koha/Checkout.t
Sponsored-by: Reserve Bank of New Zealand
Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Jesse Maseto <jesse@bywatersolutions.com>
This change checks that the string width is larger than 0 before
attempting to perform line wrapping on the line.
Test plan:
0. Apply the patch and koha-plack --restart kohadev
1. Follow instructions at end of this message[1]
2. Note that the infinite loop does not happen and that a blank
card is created
3. Export the batch using the test layout and template that come
with koha-testing-docker
4. Note that the patron card is correctly created
[1]
To reproduce:
0. Change Koha test user's firstnameto "Firstname" and surname to "Lastname"
1. Create a template:
Units: PostScript Points
Page height: 60pt
Page width: 60pt
Card height: 60pt
Card with: 60pt
Top page margin: 10pt
Left page margin: 10pt
Number of columns: 1
Number of rows: 1
Gap between columns: 10pt
Gap between rows: 10pt
2. Create a layout:
Units: US inches
Field 1:
Text: Library Name
Font: Times-Roman
Font size: 12 pt
Text alignment: Left
Lower left X coordinate: 100in
Lower left Y coordinate: 100in
Field 2:
Text: <firstname> <surname>
Font: Times-Roman
Font size: 10pt
Text alignment: Left
Lower left X coordinate: 5in
Lower left Y coordinate: 5in
3. Create a batch for borrowernumber 51 (if using "koha" test user in ktd)
4. Export using the above template and layout
Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Marcel de Rooy <m.de.rooy@rijksmuseum.nl>
Signed-off-by: Jesse Maseto <jesse@bywatersolutions.com>
CSRF protection is only working if Koha is running under Plack.
The about page is not showing any errors if plack is not running.
Test plan:
0. Do not apply this patch
1. Go to the about page
=> Notice the "PSGI" entry in the "Server information" tab
2. Disable plack
koha-plack --disable kohadev && restart_all
3. Go to the about page
=> Notice that the "PSGI" entry is not displayed, and nothing indicates
that plack is not running
4. Apply this patch
=> "PSGI" now shows "Koha is running in CGI mode. This is a security issue! Use koha-plack --help"
Better wording idea welcome.
Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Baptiste Wojtkowski <baptiste.wojtkowski@biblibre.com>
Signed-off-by: Jesse Maseto <jesse@bywatersolutions.com>
This slightly improves the current situation, where on background_jobs.pl
each plugin job would be displayed as "Unknown job type 'plugin_...'".
After this patch, we display the implementing package name
(sourced from plugins' background_tasks()), which is slightly more
human-friendly and significantly less error-looking.
Test plan:
1. In KTD, install a plugin implementing background jobs (e.g. the KitchenSink)
2. On http://localhost:8081/cgi-bin/koha/plugins/plugins-home.pl,
enable the plugin and run a tool/report from it
3. Observe ugly job types column on http://localhost:8081/cgi-bin/koha/admin/background_jobs.pl
4. Apply the patch
5. Observe the improved job types on http://localhost:8081/cgi-bin/koha/admin/background_jobs.pl
Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Jesse Maseto <jesse@bywatersolutions.com>
This patch modifies the template for adding to a basket from a new
(empty) record in order to make the "Add user" patron search results
correct. The patron search results table headers must be defined in the
template before they are used.
To test, apply the patch and go to Acquisitions.
- Search for a vendor.
- Add or create a basket for that vendor.
- Click "Add to basket" and select "From a new (empty) record."
- In the "New order" form, under the "Patrons" heading, click "Add user"
- Search for patrons to add.
- In the patron search results, each column should have a heading: Card,
Name, Category, Library.
Sponsored-by: Athens County Public Libraries
Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Julian Maurice <julian.maurice@biblibre.com>
Signed-off-by: Jesse Maseto <jesse@bywatersolutions.com>
modified: koha-tmpl/intranet-tmpl/prog/en/modules/acqui/neworderempty.tt
This patch adds th del=1 param to the batchMod link in the breadcrumbs to ensure we return to batch item
deletion and not modification
To test:
1 - Browse to Cataloging->Batch item deletion
2 - Click the 'Batch item deletion' link in the breadcrumbs
3 - You are now at 'Batch item modification'
4 - Apply patch
5 - Repeat, you stay on the correct page
6 - Complete a batch item deletion and confirm the breadcrum is correct at each stage.
Signed-off-by: Roman Dolny <roman.dolny@jezuici.pl>
Signed-off-by: Baptiste Wojtkowski <baptiste.wojtkowski@biblibre.com>
Signed-off-by: Jesse Maseto <jesse@bywatersolutions.com>
modified: koha-tmpl/intranet-tmpl/prog/en/modules/tools/batchMod-del.tt
This patch corrects a few spelling mistakes and missing grammer and adds
a little more detail to the '--date', '--email' and '--frombranch'
options.
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Julian Maurice <julian.maurice@biblibre.com>
Signed-off-by: Jesse Maseto <jesse@bywatersolutions.com>
modified: misc/cronjobs/overdue_notices.pl
This patch makes the `_process_mappings()` method split the index values
in the event of them being bigger than the allowed 32766 bytes size.
To test:
1. Have KTD running with ES:
$ ktd --proxy --es7 up -d
2. Perform a search
3. Pick the first result for edition
4. Find a cool Wiki page with lots of paragraphs
5. Copy all of the paragraphs and put them on a 500$a field for the record.
6. Repeat 2
=> FAIL: The record is not found
7. Reindex manually:
$ ktd --shell
k$ perl misc/search_tools/rebuild_elasticsearch.pl --biblios --where "biblionumber=3" -v -v
=> FAIL: You get something like:
```
[22229] Committing final records...
One or more ElasticSearch errors occurred when indexing documents at /kohadevbox/koha/Koha/SearchEngine/Elasticsearch/Indexer.pm line 148.
[22229] There were errors during indexing
Record #3 Document contains at least one immense term in field="note.raw" (whose UTF8 encoding is longer than the max length 32766), all of which were skipped. Please correct the analyzer to not produce such terms. The prefix of the first immense term is: '[10, 109, 117, 115, 116, 97, 102, 97, 32, 102, 117, 101, 32, 101, 108, 32, 115, 101, 103, 117, 110, 100, 111, 32, 104, 105, 106, 111, 32, 100]...', original message: bytes can be at most 32766 in length; got 32771 (illegal_argument_exception) : max_bytes_length_exceeded_exception (bytes can be at most 32766 in length; got 32771)
[22229] Total 1 records indexed
```
8. Apply this patch
9. Repeat 7
=> SUCCESS: No error!
10. Repeat 2
=> SUCCESS: The record is indexed and can be found!
11. Sign off :-D
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: David Cook <dcook@prosentient.com.au>
Signed-off-by: Jesse Maseto <jesse@bywatersolutions.com>
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>
Signed-off-by: Jesse Maseto <jesse@bywatersolutions.com>
It seems to me like a copy and paste error coming from the holds
endpoint.
To test:
1. Use a REST API tool like Postman to ask for some patron's checkouts
2. Add x-koha-emebed: cancellation_requested
=> FAIL: It explodes, cannot embed it
3. Apply this patch
4. Repeat 2
=> SUCCESS: cancellation_requested no longer a valid option
5. Sign off :-D
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>
This patch adds more embed options to checkouts endpoints.
To test you really need to try them on a REST tool.
* patron
* item
* library
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>
This patch adds a call to get_enabled_plugins before processing background jobs to ensure
that all plugin hooks are loaded and cached
To test:
1 - Install a plugin that adds new objects e.g. the Contracts plugin
https://github.com/bywatersolutions/fs-koha-plugin-contracts
or the Koha Advent plugin:
https://gitlab.com/koha-community/koha-advent/koha-plugin-fancyplugin
2 - Restart all
3 - Tail all your logs
4 - Stage and import a file containing items
5 - Note in the logs
DBI Exception: DBD::mysql::st execute failed: Lock wait timeout exceeded; try restarting transaction
6 - Apply this patch
7 - Restart all
8 - Stage and import again
9 - Success!
Signed-off-by: David Cook <dcook@prosentient.com.au>
Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Jesse Maseto <jesse@bywatersolutions.com>
If table aqbudgets is miissing foreign key
'aqbudgetperiods_ibfk_1' database update fails on
"Can't DROP FOREIGN KEY" error.
To test:
1. Remove changes made in bug 32132, drop foreign key
aqbudgetperiods_ibfk_1 and downgrade your database:
- ALTER TABLE aqbudgets MODIFY COLUMN `budget_period_id` INT(11) NULL;
- UPDATE aqbudgets SET budget_period_id = NULL
WHERE budget_period_id IN(SELECT budget_period_id FROM aqbudgetperiods
WHERE budget_period_description = "Budget for funds without budget");
- DELETE FROM aqbudgetperiods
WHERE budget_period_description = "Budget for funds without budget";
- ALTER TABLE aqbudgets DROP FOREIGN KEY aqbudgetperiods_ibfk_1;
- UPDATE systempreferences SET value="23.1200022" WHERE variable = "Version;
2. Upgrade your database (e.g. running installer/data/mysql/updatedatabase.pl)
=> Update fails on error "Can't DROP FOREIGN KEY `aqbudgetperiods_ibfk_1`;...".
4. Apply this patch.
5. Try to update your database again.
=> Database should now be upgraded succesfully.
=> Confirm table aqbudgets now contains 'aqbudgetperiods_ibfk_1'.
Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Signed-off-by: Marcel de Rooy <m.de.rooy@rijksmuseum.nl>
Signed-off-by: Jesse Maseto <jesse@bywatersolutions.com>
The update wasn't checking for index pre-existance and as such could
fail in certain cases.
Signed-off-by: Chris Cormack <chris@bigballofwax.co.nz>
Signed-off-by: Julian Maurice <julian.maurice@biblibre.com>
Signed-off-by: Jesse Maseto <jesse@bywatersolutions.com>
This change turns off ABSOLUTE and EVAL_PERL for user-entered templates,
as these options can allow for arbitrary code execution and information
disclosure.
Test plan:
0. Apply the patch
1. koha-plack --restart kohadev
2. Create a Notice for Reports with a report like:
[% IF ( x == 1 ) %]
One
[% ELSE %]
Two
[% END %]
3. Run a report using this template
4. The report should show "Two"
5. Turn on CHECKOUT emails for a test patron
6. Perform a checkout
7. Look at the CHECKOUT email and note that the email body
is correctly generated
Signed-off-by: Magnus Enger <magnus@libriotech.no>
Would be good to have this fixed as the default.
Signed-off-by: Marcel de Rooy <m.de.rooy@rijksmuseum.nl>
The test plan should include PERL blocks or absolute paths! Tested those
instead. Testing x==1 seems irrelevant.
I tried:[% PERL %]print 1;[% END %] and [% INCLUDE /app/Dockerfile_1 %]
Signed-off-by: wainuiwitikapark <wainuiwitikapark@catalyst.net.nz>
When ILS-DI is disabled we still expect to return the correct service name/section in the
xml, but just indicate that it is disabled.
We should skip the check for authorized IPs in this case, as the IP only matters when service is enabled
Signed-off-by: wainuiwitikapark <wainuiwitikapark@catalyst.net.nz>
This lists the new syntax for allowing all IPs in the preference
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: wainuiwitikapark <wainuiwitikapark@catalyst.net.nz>
This patch forces a check of authorized IPs against the Koha system preference, if nothing is present, no access is allowed
To test:
1 - Enable ILS-DI, leave ILS-DI:AuthorizedIPs blank
2 - In another window:
http://localhost:8080/cgi-bin/koha/ilsdi.pl?service=GetAvailability&id=1+2+99999&id_type=item
3 - You get a response
4 - Apply patch and restart all
5 - Reload ilsdi page, 'Not authorized'
6 - Copy the IP listed as refused and paste into ILS-DI:AuthorizedIPs
7 - Reload the page, you get a response again
8 - Change ILS-DI:AuthorizedIPs to:
0:0:0:0/0
9 - You still have access
10 - Paste your specific IP again, and add a second made up IP (comma separated)
11 - Reload and confirm you still have access
Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>
Signed-off-by: wainuiwitikapark <wainuiwitikapark@catalyst.net.nz>
Typo in system preference 'minPasswordPreference' -> 'minPasswordLength'
in opac/opac-password-recovery.pl
There is no 'minPasswordPreference' system preference in database.
Bug 23816 added the capability to override minPasswordLength.
Test plan:
==========
1. Check 'minPasswordPreference' appearances:
git grep -i 'minPasswordPreference' **/*
--> Note: only one in opac-password-recovery.pl; no one in sysprefs.sql
2. Apply the patch.
3. Repeat p. 1. Note there is not 'minPasswordPreference' at all.
Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>
(cherry picked from commit 4b8db36d2a)
Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de>
Signed-off-by: wainuiwitikapark <wainuiwitikapark@catalyst.net.nz>
Reorder logic slightly for each to only create the counter_file after the mock_userenv has taken place
prove t/db_dependent/api/v1/erm_custom_reports.t
Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>
(cherry picked from commit 1e7c49ab98)
Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de>
Signed-off-by: wainuiwitikapark <wainuiwitikapark@catalyst.net.nz>
The ud_provider->{report_type} is only defined on ->harvest_sushi, meaning it'll never be defined here.
We don't need this anyway. The filename should be the filename of the file being manually uploaded. We only need this concat logic for COUNTER files being generated by Koha following a SUSHI harvest, and that works.
This also gets rid of a warning when running the tests
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>
(cherry picked from commit 0231911c98)
Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de>
Signed-off-by: wainuiwitikapark <wainuiwitikapark@catalyst.net.nz>