Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
- Remove the no longer needed escape_once helper call in node.haml, relying on HAML's global escape_html instead (@robertcheramy)
- Update web libraries to the latest versions (@robertcheramy)
- Encode JSON output with the standard library instead of Sinatra's json helper (@robertcheramy)
- Set HAML's `attr_quote` explicitly to `"` for stable output across HAML versions (@robertcheramy)

### Fixed
- Fix XSS vulnerability (CWE-79) by enabling HAML's escape_html globally; user-controlled values in node names, group names, model names, and URL parameters are now HTML-escaped in all templates (@mattimustang)
Expand Down
5 changes: 4 additions & 1 deletion lib/oxidized/web/webapp.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ module API
class WebApp < Sinatra::Base
helpers Sinatra::UrlForHelper
set :public_folder, proc { File.join(root, 'public') }
set :haml, { escape_html: true }
# attr_quote: use double quotes for HTML attributes. Set explicitly so the
# output is stable across Haml versions. Haml 7.3.0 changed the default
# from "'" to '"' (haml/haml#1188); older versions still default to "'".
set :haml, { escape_html: true, attr_quote: '"' }

get '/' do
redirect url_for('/nodes')
Expand Down
2 changes: 1 addition & 1 deletion oxidized-web.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ Gem::Specification.new do |s|
s.add_dependency 'emk-sinatra-url-for', '~> 0.2'
# HAML 7.0.0 changed default attr_quote from ' to ".
# Updating needs the unit tests to be fixed.
s.add_dependency 'haml', '>= 6', '<7'
s.add_dependency 'haml', '>= 6', '< 8'
s.add_dependency 'htmlentities', '~> 4.3'
s.add_dependency 'json', '~> 2.3'
# Only depend on a minimal version of Oxidized so we don't need to
Expand Down
26 changes: 13 additions & 13 deletions spec/web/node/version_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,26 +27,26 @@ def app
get '/node/version?node_full=sw5'
_(last_response.ok?).must_equal true
_(last_response.body.include?(
"<tr>\n<td>3</td>\n<td class='time' epoch='1738781340'>" \
"<tr>\n<td>3</td>\n<td class=\"time\" epoch=\"1738781340\">" \
"2025-02-05 19:49:00 +0100</td>\n"
)).must_equal true

_(last_response.body.include?(
"href='/node/version/view?node=sw5&amp;group=&amp;oid=C006&amp;" \
"epoch=1738781340&amp;num=3' title='configuration'>"
"href=\"/node/version/view?node=sw5&amp;group=&amp;oid=C006&amp;" \
"epoch=1738781340&amp;num=3\" title=\"configuration\">"
)).must_equal true
_(last_response.body.include?(
"href='/node/version/diffs?node=sw5&amp;group=&amp;oid=C006&amp;" \
"epoch=1738781340&amp;num=3' title='Compare with previous version'>"
"href=\"/node/version/diffs?node=sw5&amp;group=&amp;oid=C006&amp;" \
"epoch=1738781340&amp;num=3\" title=\"Compare with previous version\">"
)).must_equal true
_(last_response.body.include?(
"href='/node/version/view?node=sw5&amp;group=&amp;oid=C001&amp;" \
"epoch=1738778460&amp;num=1' title='configuration'>"
"href=\"/node/version/view?node=sw5&amp;group=&amp;oid=C001&amp;" \
"epoch=1738778460&amp;num=1\" title=\"configuration\">"
)).must_equal true
# Compare to the version previous 1 is not possible, so don't display it
_(last_response.body.include?(
"href='/node/version/diffs?node=sw5&amp;group=&amp;oid=C001&amp;" \
"epoch=1738778460&amp;num=1' title='Compare with previous version'>"
"href=\"/node/version/diffs?node=sw5&amp;group=&amp;oid=C001&amp;" \
"epoch=1738778460&amp;num=1\" title=\"Compare with previous version\">"
)).must_equal false
end

Expand All @@ -56,7 +56,7 @@ def app
get '/node/version?node_full=group1/sw5'
_(last_response.ok?).must_equal true
_(last_response.body.include?(
"<tr>\n<td>3</td>\n<td class='time' epoch='1738781340'>" \
"<tr>\n<td>3</td>\n<td class=\"time\" epoch=\"1738781340\">" \
"2025-02-05 19:49:00 +0100</td>\n"
)).must_equal true
end
Expand All @@ -67,7 +67,7 @@ def app
get '/node/version?node_full=gr/oup1/sw5'
_(last_response.ok?).must_equal true
_(last_response.body.include?(
"<tr>\n<td>3</td>\n<td class='time' epoch='1738781340'>" \
"<tr>\n<td>3</td>\n<td class=\"time\" epoch=\"1738781340\">" \
"2025-02-05 19:49:00 +0100</td>\n"
)).must_equal true
end
Expand All @@ -84,7 +84,7 @@ def app
# right string
_(last_response.body.include?(
"Date of version:\n" \
"<span class='time' epoch='1738781340'>" \
"<span class=\"time\" epoch=\"1738781340\">" \
"#{Time.at(1738781340)}</span>"
)).must_equal true
end
Expand Down Expand Up @@ -153,7 +153,7 @@ def app
# right string
_(last_response.body.include?(
"Date of version:\n" \
"<span class='time' epoch='1738781340'>" \
"<span class=\"time\" epoch=\"1738781340\">" \
"#{Time.at(1738781340)}</span>"
)).must_equal true
end
Expand Down