diff --git a/Gemfile b/Gemfile
index 89b42534ce..bdad189046 100644
--- a/Gemfile
+++ b/Gemfile
@@ -52,7 +52,7 @@ gem 'will_paginate', '~> 3.1'
gem 'yaml_db'
gem 'rails_autolink'
gem 'rfc-822'
-gem 'nokogiri', '~> 1.16.2'
+gem 'nokogiri', '~> 1.16.5'
#necessary for newer hashie dependency, original api_smith is no longer active
gem 'api_smith', git: 'https://github.com/youroute/api_smith.git', ref: '1fb428cebc17b9afab25ac9f809bde87b0ec315b'
gem 'rdf-virtuoso', '>= 0.2.0'
@@ -134,7 +134,7 @@ gem 'request_store'
gem 'bundler', '>= 1.8.4'
-gem 'ro-crate', '~> 0.5.1'
+gem 'ro-crate', '~> 0.5.2'
gem 'rugged'
gem 'i18n-js'
diff --git a/Gemfile.lock b/Gemfile.lock
index d3e795ca4e..946308413a 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -460,7 +460,7 @@ GEM
nokogiri (~> 1)
rake
mini_mime (1.1.5)
- mini_portile2 (2.8.5)
+ mini_portile2 (2.8.6)
minitest (5.20.0)
minitest-reporters (1.5.0)
ansi
@@ -492,7 +492,7 @@ GEM
net-protocol
netrc (0.11.0)
nio4r (2.7.0)
- nokogiri (1.16.2)
+ nokogiri (1.16.5)
mini_portile2 (~> 2.8.2)
racc (~> 1.4)
nori (1.1.5)
@@ -737,7 +737,7 @@ GEM
json (~> 2.3.0)
ucf (~> 2.0.2)
uuid (~> 2.3)
- ro-crate (0.5.1)
+ ro-crate (0.5.2)
addressable (>= 2.7, < 2.9)
rubyzip (~> 2.0.0)
rsolr (2.5.0)
@@ -1028,7 +1028,7 @@ DEPENDENCIES
my_responds_to_parent!
mysql2
net-ftp
- nokogiri (~> 1.16.2)
+ nokogiri (~> 1.16.5)
omniauth (~> 2.1.0)
omniauth-github
omniauth-rails_csrf_protection
@@ -1069,7 +1069,7 @@ DEPENDENCIES
rfc-822
rmagick (= 5.3.0)
ro-bundle (~> 0.3.0)
- ro-crate (~> 0.5.1)
+ ro-crate (~> 0.5.2)
rspec-rails (~> 5.1)
rubocop
ruby-prof
diff --git a/app/assets/javascripts/objects_input.js b/app/assets/javascripts/objects_input.js
index 3bcb08fd06..ad421c1ae1 100644
--- a/app/assets/javascripts/objects_input.js
+++ b/app/assets/javascripts/objects_input.js
@@ -32,9 +32,8 @@ var ObjectsInput = {
const template = $j(this).data('typeahead-template') || 'typeahead/hint';
opts.templateResult = HandlebarsTemplates[template];
- opts.escapeMarkup = function (m) {
- return m;
- }
+ opts.escapeMarkup = ObjectsInput.doNothing;
+ opts.templateSelection = ObjectsInput.escapeSelectionMarkup;
if ($j(this).data('typeahead-query-url')) {
opts.ajax={
@@ -47,6 +46,12 @@ var ObjectsInput = {
opts
);
});
+ },
+ doNothing: function (m) {
+ return m;
+ },
+ escapeSelectionMarkup: function (m) {
+ return jQuery.fn.select2.defaults.defaults.escapeMarkup(m.text);
}
}
$j(document).ready(function () {
diff --git a/app/assets/javascripts/single_page/dynamic_table.js.erb b/app/assets/javascripts/single_page/dynamic_table.js.erb
index 0827ff286a..ae1a9cc598 100644
--- a/app/assets/javascripts/single_page/dynamic_table.js.erb
+++ b/app/assets/javascripts/single_page/dynamic_table.js.erb
@@ -19,6 +19,33 @@ const defaultCols = [{
}
}];
+// Sanitizes input data to prevent XSS attacks
+// https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html
+function sanitizeHTML(str) {
+ return str.replace(/[&<>"']/g, function(match) {
+ return {
+ '&': '&',
+ '<': '<',
+ '>': '>',
+ '"': '"',
+ "'": '''
+ }[match];
+ });
+}
+
+function sanitizeData(data) {
+ if (typeof data === 'string' && data !== "") {
+ return sanitizeHTML(data);
+ } else if(typeof data === 'array'){
+ return data.forEach((e) => {
+ sanitizeData(e);
+ });
+ } else {
+ // Handle other data types or nested objects/arrays if necessary
+ return data;
+ }
+}
+
const objectInputTemp = '' +
'