Maintenance: Add Brakeman for static security analysis.
This commit is contained in:
parent
fa7c4210bb
commit
9f7bec8942
30 changed files with 805 additions and 24 deletions
|
@ -34,6 +34,17 @@ zeitwerk_check:
|
||||||
- bundle exec rake zammad:db:init
|
- bundle exec rake zammad:db:init
|
||||||
- bundle exec rails zeitwerk:check
|
- bundle exec rails zeitwerk:check
|
||||||
|
|
||||||
|
brakeman:
|
||||||
|
<<: *template_pre
|
||||||
|
artifacts:
|
||||||
|
expire_in: 1 week
|
||||||
|
paths:
|
||||||
|
- tmp/brakeman-report.html
|
||||||
|
when: on_failure
|
||||||
|
script:
|
||||||
|
- bundle install -j $(nproc) --path vendor
|
||||||
|
- bundle exec brakeman -o /dev/stdout -o tmp/brakeman-report.html
|
||||||
|
|
||||||
coffeelint:
|
coffeelint:
|
||||||
<<: *template_pre
|
<<: *template_pre
|
||||||
script:
|
script:
|
||||||
|
|
1
Gemfile
1
Gemfile
|
@ -189,6 +189,7 @@ group :development, :test do
|
||||||
gem 'guard-symlink', require: false
|
gem 'guard-symlink', require: false
|
||||||
|
|
||||||
# code QA
|
# code QA
|
||||||
|
gem 'brakeman', require: false
|
||||||
gem 'coffeelint'
|
gem 'coffeelint'
|
||||||
gem 'overcommit'
|
gem 'overcommit'
|
||||||
gem 'rubocop'
|
gem 'rubocop'
|
||||||
|
|
|
@ -127,6 +127,7 @@ GEM
|
||||||
tzinfo
|
tzinfo
|
||||||
bootsnap (1.7.5)
|
bootsnap (1.7.5)
|
||||||
msgpack (~> 1.0)
|
msgpack (~> 1.0)
|
||||||
|
brakeman (5.0.4)
|
||||||
browser (5.3.1)
|
browser (5.3.1)
|
||||||
buftok (0.2.0)
|
buftok (0.2.0)
|
||||||
builder (3.2.4)
|
builder (3.2.4)
|
||||||
|
@ -657,6 +658,7 @@ DEPENDENCIES
|
||||||
autoprefixer-rails
|
autoprefixer-rails
|
||||||
biz
|
biz
|
||||||
bootsnap
|
bootsnap
|
||||||
|
brakeman
|
||||||
browser
|
browser
|
||||||
byebug
|
byebug
|
||||||
capybara
|
capybara
|
||||||
|
|
|
@ -26,8 +26,7 @@ module ApplicationController::PreventsCsrf
|
||||||
|
|
||||||
def verify_csrf_token
|
def verify_csrf_token
|
||||||
return true if !protect_against_forgery?
|
return true if !protect_against_forgery?
|
||||||
return true if request.get?
|
return true if request.get? || request.head?
|
||||||
return true if request.head?
|
|
||||||
return true if %w[token_auth basic_auth].include?(@_auth_type)
|
return true if %w[token_auth basic_auth].include?(@_auth_type)
|
||||||
|
|
||||||
# call Rails method to verify CRSF token
|
# call Rails method to verify CRSF token
|
||||||
|
|
|
@ -17,7 +17,7 @@ class ImportFreshdeskController < ApplicationController
|
||||||
endpoint = "#{params[:url]}/api/v2"
|
endpoint = "#{params[:url]}/api/v2"
|
||||||
endpoint.gsub!(%r{([^:])//+}, '\\1/')
|
endpoint.gsub!(%r{([^:])//+}, '\\1/')
|
||||||
|
|
||||||
response = UserAgent.request("#{endpoint}/contacts")
|
response = UserAgent.request("#{endpoint}/contacts", verify_ssl: true)
|
||||||
|
|
||||||
if response.header.nil? || !response.header['x-freshdesk-api-version']
|
if response.header.nil? || !response.header['x-freshdesk-api-version']
|
||||||
render json: {
|
render json: {
|
||||||
|
|
|
@ -23,7 +23,7 @@ class ImportZendeskController < ApplicationController
|
||||||
'Connection refused' => 'Connection refused!',
|
'Connection refused' => 'Connection refused!',
|
||||||
}
|
}
|
||||||
|
|
||||||
response = UserAgent.request(params[:url])
|
response = UserAgent.request(params[:url], verify_ssl: true)
|
||||||
|
|
||||||
if !response.success?
|
if !response.success?
|
||||||
message_human = ''
|
message_human = ''
|
||||||
|
@ -41,7 +41,7 @@ class ImportZendeskController < ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
# since 2016-10-15 a redirect to a marketing page has been implemented
|
# since 2016-10-15 a redirect to a marketing page has been implemented
|
||||||
if !response.body.match?(%r{#{params[:url]}})
|
if response.body.exclude?(params[:url])
|
||||||
render json: {
|
render json: {
|
||||||
result: 'invalid',
|
result: 'invalid',
|
||||||
message_human: 'Hostname not found!',
|
message_human: 'Hostname not found!',
|
||||||
|
|
|
@ -4,20 +4,20 @@ class KnowledgeBase::CategoriesController < KnowledgeBase::BaseController
|
||||||
before_action :load_knowledge_base, only: %i[reorder_root_categories reorder_categories reorder_answers]
|
before_action :load_knowledge_base, only: %i[reorder_root_categories reorder_categories reorder_answers]
|
||||||
|
|
||||||
def reorder_root_categories
|
def reorder_root_categories
|
||||||
reorder @knowledge_base.categories.root, params[:ordered_ids], KnowledgeBase::Category
|
reorder_records @knowledge_base.categories.root, params[:ordered_ids], KnowledgeBase::Category
|
||||||
end
|
end
|
||||||
|
|
||||||
def reorder_categories
|
def reorder_categories
|
||||||
reorder @category.children, params[:ordered_ids], KnowledgeBase::Category
|
reorder_records @category.children, params[:ordered_ids], KnowledgeBase::Category
|
||||||
end
|
end
|
||||||
|
|
||||||
def reorder_answers
|
def reorder_answers
|
||||||
reorder @category.answers, params[:ordered_ids], KnowledgeBase::Answer
|
reorder_records @category.answers, params[:ordered_ids], KnowledgeBase::Answer
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def reorder(collection, ids, klass)
|
def reorder_records(collection, ids, klass)
|
||||||
# Check if ids for models in collection are present
|
# Check if ids for models in collection are present
|
||||||
all_ids_present = collection.map(&:id).sort == ids.sort
|
all_ids_present = collection.map(&:id).sort == ids.sort
|
||||||
raise Exceptions::UnprocessableEntity, 'Provide position of all items in scope' if !all_ids_present
|
raise Exceptions::UnprocessableEntity, 'Provide position of all items in scope' if !all_ids_present
|
||||||
|
|
|
@ -53,22 +53,22 @@ class MentionsController < ApplicationController
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def ensure_mentionable_type!
|
def mentionable_type!
|
||||||
return if ['Ticket'].include?(params[:mentionable_type])
|
@mentionable_type ||= begin
|
||||||
|
raise 'Invalid mentionable_type!' if 'Ticket'.freeze != params[:mentionable_type]
|
||||||
|
|
||||||
raise 'Invalid mentionable_type!'
|
params[:mentionable_type]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def mentionable!
|
def mentionable!
|
||||||
ensure_mentionable_type!
|
object = mentionable_type!.constantize.find(params[:mentionable_id])
|
||||||
|
|
||||||
object = params[:mentionable_type].constantize.find(params[:mentionable_id])
|
|
||||||
authorize!(object, :agent_read_access?)
|
authorize!(object, :agent_read_access?)
|
||||||
object
|
object
|
||||||
end
|
end
|
||||||
|
|
||||||
def fill_condition_mentionable(condition)
|
def fill_condition_mentionable(condition)
|
||||||
condition[:mentionable_type] = params[:mentionable_type]
|
condition[:mentionable_type] = mentionable_type!
|
||||||
return if params[:mentionable_id].blank?
|
return if params[:mentionable_id].blank?
|
||||||
|
|
||||||
condition[:mentionable_id] = params[:mentionable_id]
|
condition[:mentionable_id] = params[:mentionable_id]
|
||||||
|
|
|
@ -101,6 +101,7 @@ class Cti::Driver::Placetel < Cti::Driver::Base
|
||||||
open_timeout: 4,
|
open_timeout: 4,
|
||||||
read_timeout: 6,
|
read_timeout: 6,
|
||||||
total_timeout: 6,
|
total_timeout: 6,
|
||||||
|
verify_ssl: true,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,7 @@ class Cti::Driver::SipgateIo < Cti::Driver::Base
|
||||||
open_timeout: 4,
|
open_timeout: 4,
|
||||||
read_timeout: 6,
|
read_timeout: 6,
|
||||||
total_timeout: 6,
|
total_timeout: 6,
|
||||||
|
verify_ssl: true,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -106,6 +106,7 @@ all:
|
||||||
json: true,
|
json: true,
|
||||||
open_timeout: 8,
|
open_timeout: 8,
|
||||||
read_timeout: 24,
|
read_timeout: 24,
|
||||||
|
verify_ssl: true,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,8 @@ load text modules from online
|
||||||
url,
|
url,
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
json: true,
|
json: true,
|
||||||
|
verify_ssl: true,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -98,6 +99,7 @@ push text_modules to online
|
||||||
json: true,
|
json: true,
|
||||||
open_timeout: 6,
|
open_timeout: 6,
|
||||||
read_timeout: 16,
|
read_timeout: 16,
|
||||||
|
verify_ssl: true,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
raise "Can't push text_modules to #{url}: #{result.error}" if !result.success?
|
raise "Can't push text_modules to #{url}: #{result.error}" if !result.success?
|
||||||
|
|
|
@ -300,7 +300,8 @@ class Transaction::Slack
|
||||||
total_timeout: 20,
|
total_timeout: 20,
|
||||||
log: {
|
log: {
|
||||||
facility: 'slack_webhook',
|
facility: 'slack_webhook',
|
||||||
}
|
},
|
||||||
|
verify_ssl: true,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
|
@ -85,6 +85,7 @@ push translations to online
|
||||||
json: true,
|
json: true,
|
||||||
open_timeout: 8,
|
open_timeout: 8,
|
||||||
read_timeout: 24,
|
read_timeout: 24,
|
||||||
|
verify_ssl: true,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
raise "Can't push translations to #{url}: #{result.error}" if !result.success?
|
raise "Can't push translations to #{url}: #{result.error}" if !result.success?
|
||||||
|
@ -355,6 +356,7 @@ all:
|
||||||
json: true,
|
json: true,
|
||||||
open_timeout: 8,
|
open_timeout: 8,
|
||||||
read_timeout: 24,
|
read_timeout: 24,
|
||||||
|
verify_ssl: true,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
raise "Can't load translations from #{url}: #{result.error}" if !result.success?
|
raise "Can't load translations from #{url}: #{result.error}" if !result.success?
|
||||||
|
|
742
config/brakeman.ignore
Normal file
742
config/brakeman.ignore
Normal file
|
@ -0,0 +1,742 @@
|
||||||
|
{
|
||||||
|
"ignored_warnings": [
|
||||||
|
{
|
||||||
|
"warning_type": "Redirect",
|
||||||
|
"warning_code": 18,
|
||||||
|
"fingerprint": "069e68c2898ea30f966463fa4616887fb203d48d8c2184693d56569d41f2d3b7",
|
||||||
|
"check_name": "Redirect",
|
||||||
|
"message": "Possible unprotected redirect",
|
||||||
|
"file": "app/controllers/external_credentials_controller.rb",
|
||||||
|
"line": 38,
|
||||||
|
"link": "https://brakemanscanner.org/docs/warning_types/redirect/",
|
||||||
|
"code": "redirect_to(ExternalCredential.request_account_to_link(params[:provider].downcase)[:authorize_url])",
|
||||||
|
"render_path": null,
|
||||||
|
"location": {
|
||||||
|
"type": "method",
|
||||||
|
"class": "ExternalCredentialsController",
|
||||||
|
"method": "link_account"
|
||||||
|
},
|
||||||
|
"user_input": "ExternalCredential.request_account_to_link(params[:provider].downcase)[:authorize_url]",
|
||||||
|
"confidence": "High",
|
||||||
|
"note": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"warning_type": "Remote Code Execution",
|
||||||
|
"warning_code": 24,
|
||||||
|
"fingerprint": "0fcd117fd53301f531142fc075ee8d30219c1239affce9322f9939ac0572ba3b",
|
||||||
|
"check_name": "UnsafeReflection",
|
||||||
|
"message": "Unsafe reflection method `constantize` called with model attribute",
|
||||||
|
"file": "app/models/ticket/number.rb",
|
||||||
|
"line": 45,
|
||||||
|
"link": "https://brakemanscanner.org/docs/warning_types/remote_code_execution/",
|
||||||
|
"code": "Setting.get(\"ticket_number\").constantize",
|
||||||
|
"render_path": null,
|
||||||
|
"location": {
|
||||||
|
"type": "method",
|
||||||
|
"class": "Ticket::Number",
|
||||||
|
"method": "Ticket::Number.adapter"
|
||||||
|
},
|
||||||
|
"user_input": "Setting.get(\"ticket_number\")",
|
||||||
|
"confidence": "Medium",
|
||||||
|
"note": "Setting.get(\"ticket_number\") returns defined ticket number backend class names"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"warning_type": "Denial of Service",
|
||||||
|
"warning_code": 76,
|
||||||
|
"fingerprint": "15d4ddbc3ac2ae0a0fe27218a42a1920fe2c1868ae5f504422c4af8ffe893beb",
|
||||||
|
"check_name": "RegexDoS",
|
||||||
|
"message": "Model attribute used in regular expression",
|
||||||
|
"file": "app/models/channel/filter/monitoring_base.rb",
|
||||||
|
"line": 92,
|
||||||
|
"link": "https://brakemanscanner.org/docs/warning_types/denial_of_service/",
|
||||||
|
"code": "/#{(Setting.get(\"#{integration_name}_recovery_match\") or \"(OK|UP)\")}/i",
|
||||||
|
"render_path": null,
|
||||||
|
"location": {
|
||||||
|
"type": "method",
|
||||||
|
"class": "Channel::Filter::MonitoringBase",
|
||||||
|
"method": "Channel::Filter::MonitoringBase.run"
|
||||||
|
},
|
||||||
|
"user_input": "Setting.get(\"#{integration_name}_recovery_match\")",
|
||||||
|
"confidence": "Medium",
|
||||||
|
"note": "Admin configured RegExp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"warning_type": "Denial of Service",
|
||||||
|
"warning_code": 76,
|
||||||
|
"fingerprint": "15d4ddbc3ac2ae0a0fe27218a42a1920fe2c1868ae5f504422c4af8ffe893beb",
|
||||||
|
"check_name": "RegexDoS",
|
||||||
|
"message": "Model attribute used in regular expression",
|
||||||
|
"file": "app/models/channel/filter/monitoring_base.rb",
|
||||||
|
"line": 121,
|
||||||
|
"link": "https://brakemanscanner.org/docs/warning_types/denial_of_service/",
|
||||||
|
"code": "/#{(Setting.get(\"#{integration_name}_recovery_match\") or \"(OK|UP)\")}/i",
|
||||||
|
"render_path": null,
|
||||||
|
"location": {
|
||||||
|
"type": "method",
|
||||||
|
"class": "Channel::Filter::MonitoringBase",
|
||||||
|
"method": "Channel::Filter::MonitoringBase.run"
|
||||||
|
},
|
||||||
|
"user_input": "Setting.get(\"#{integration_name}_recovery_match\")",
|
||||||
|
"confidence": "Medium",
|
||||||
|
"note": "Admin configured RegExp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"warning_type": "Remote Code Execution",
|
||||||
|
"warning_code": 24,
|
||||||
|
"fingerprint": "176994cedb6a57bc52f7a98b0fd93caad211f8f3b48fd010a5db164b37992e1f",
|
||||||
|
"check_name": "UnsafeReflection",
|
||||||
|
"message": "Unsafe reflection method `constantize` called with model attribute",
|
||||||
|
"file": "app/models/avatar.rb",
|
||||||
|
"line": 405,
|
||||||
|
"link": "https://brakemanscanner.org/docs/warning_types/remote_code_execution/",
|
||||||
|
"code": "ObjectLookup.by_id(object_id).constantize",
|
||||||
|
"render_path": null,
|
||||||
|
"location": {
|
||||||
|
"type": "method",
|
||||||
|
"class": "Avatar",
|
||||||
|
"method": "Avatar._add_init_avatar"
|
||||||
|
},
|
||||||
|
"user_input": "ObjectLookup.by_id(object_id)",
|
||||||
|
"confidence": "Medium",
|
||||||
|
"note": "ObjectLookup.by_id works as designed"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"warning_type": "Denial of Service",
|
||||||
|
"warning_code": 76,
|
||||||
|
"fingerprint": "230f45f9fba03dd6308704600d0c2cd639ab138a3a485c0dc54f750356d22ebc",
|
||||||
|
"check_name": "RegexDoS",
|
||||||
|
"message": "Model attribute used in regular expression",
|
||||||
|
"file": "app/models/ticket/subject.rb",
|
||||||
|
"line": 67,
|
||||||
|
"link": "https://brakemanscanner.org/docs/warning_types/denial_of_service/",
|
||||||
|
"code": "/#{Setting.get(\"ticket_hook\")}:#{number}(\\s+?|)/",
|
||||||
|
"render_path": null,
|
||||||
|
"location": {
|
||||||
|
"type": "method",
|
||||||
|
"class": "Ticket::Subject",
|
||||||
|
"method": "subject_clean"
|
||||||
|
},
|
||||||
|
"user_input": "Setting.get(\"ticket_hook\")",
|
||||||
|
"confidence": "Medium",
|
||||||
|
"note": "Admin configured RegExp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"warning_type": "Denial of Service",
|
||||||
|
"warning_code": 76,
|
||||||
|
"fingerprint": "2eaeb513e1e099ce8bf973d91a9bfce398910cdcede6fce7469d6bd576fe938f",
|
||||||
|
"check_name": "RegexDoS",
|
||||||
|
"message": "Model attribute used in regular expression",
|
||||||
|
"file": "app/models/ticket/subject.rb",
|
||||||
|
"line": 63,
|
||||||
|
"link": "https://brakemanscanner.org/docs/warning_types/denial_of_service/",
|
||||||
|
"code": "/\\[#{Setting.get(\"ticket_hook\")}#{Setting.get(\"ticket_hook_divider\")}#{number}\\](\\s+?|)/",
|
||||||
|
"render_path": null,
|
||||||
|
"location": {
|
||||||
|
"type": "method",
|
||||||
|
"class": "Ticket::Subject",
|
||||||
|
"method": "subject_clean"
|
||||||
|
},
|
||||||
|
"user_input": "Setting.get(\"ticket_hook\")",
|
||||||
|
"confidence": "Medium",
|
||||||
|
"note": "Admin configured RegExp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"warning_type": "SQL Injection",
|
||||||
|
"warning_code": 0,
|
||||||
|
"fingerprint": "34d5d0f52def9a9fbcb045f4f16b0117cb22d59d8ab6184f3bddd057d81d7cd1",
|
||||||
|
"check_name": "SQL",
|
||||||
|
"message": "Possible SQL injection",
|
||||||
|
"file": "app/models/channel/filter/internal_article_check.rb",
|
||||||
|
"line": 31,
|
||||||
|
"link": "https://brakemanscanner.org/docs/warning_types/sql_injection/",
|
||||||
|
"code": "ticket.articles.where(\"ticket_articles.to #{Rails.application.config.db_like} ?\", \"%#{parse_email(mail[:from_email])}%\")",
|
||||||
|
"render_path": null,
|
||||||
|
"location": {
|
||||||
|
"type": "method",
|
||||||
|
"class": "Channel::Filter::InternalArticleCheck",
|
||||||
|
"method": "Channel::Filter::InternalArticleCheck.last_outgoing_mail_is_internal?"
|
||||||
|
},
|
||||||
|
"user_input": "Rails.application.config.db_like",
|
||||||
|
"confidence": "Weak",
|
||||||
|
"note": "The db_like config setting is safe to use in an SQL string."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"warning_type": "Denial of Service",
|
||||||
|
"warning_code": 76,
|
||||||
|
"fingerprint": "381781925211cac1f2592a6537f4abc050f98b081e5554b7d3d70a9454157e35",
|
||||||
|
"check_name": "RegexDoS",
|
||||||
|
"message": "Model attribute used in regular expression",
|
||||||
|
"file": "app/models/ticket/number/increment.rb",
|
||||||
|
"line": 47,
|
||||||
|
"link": "https://brakemanscanner.org/docs/warning_types/denial_of_service/",
|
||||||
|
"code": "/(?<=\\W|^)#{Regexp.quote(Setting.get(\"ticket_hook\"))}\\s{0,2}(#{(\"\" or Setting.get(\"system_id\").to_s)}\\d{2,48})\\b/i",
|
||||||
|
"render_path": null,
|
||||||
|
"location": {
|
||||||
|
"type": "method",
|
||||||
|
"class": "Ticket::Number::Increment",
|
||||||
|
"method": "Ticket::Number::Increment.check"
|
||||||
|
},
|
||||||
|
"user_input": "Setting.get(\"system_id\").to_s",
|
||||||
|
"confidence": "Medium",
|
||||||
|
"note": "Admin configured RegExp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"warning_type": "Denial of Service",
|
||||||
|
"warning_code": 76,
|
||||||
|
"fingerprint": "4ea1b96c11cdde309b0f31defd8af9dc39dd7605a7bb18b13b122469a74a5a70",
|
||||||
|
"check_name": "RegexDoS",
|
||||||
|
"message": "Model attribute used in regular expression",
|
||||||
|
"file": "app/models/channel/filter/monitoring_base.rb",
|
||||||
|
"line": 115,
|
||||||
|
"link": "https://brakemanscanner.org/docs/warning_types/denial_of_service/",
|
||||||
|
"code": "/#{(Setting.get(\"#{integration_name}_ignore_match\") or \"\")}/i",
|
||||||
|
"render_path": null,
|
||||||
|
"location": {
|
||||||
|
"type": "method",
|
||||||
|
"class": "Channel::Filter::MonitoringBase",
|
||||||
|
"method": "Channel::Filter::MonitoringBase.run"
|
||||||
|
},
|
||||||
|
"user_input": "Setting.get(\"#{integration_name}_ignore_match\")",
|
||||||
|
"confidence": "Medium",
|
||||||
|
"note": "Admin configured RegExp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"warning_type": "Remote Code Execution",
|
||||||
|
"warning_code": 24,
|
||||||
|
"fingerprint": "55248822583e32826f88a68e27568416fe1f101d83b02791c10296d2393b83a5",
|
||||||
|
"check_name": "UnsafeReflection",
|
||||||
|
"message": "Unsafe reflection method `constantize` called with model attribute",
|
||||||
|
"file": "app/models/store/file.rb",
|
||||||
|
"line": 32,
|
||||||
|
"link": "https://brakemanscanner.org/docs/warning_types/remote_code_execution/",
|
||||||
|
"code": "\"Store::Provider::#{(Setting.get(\"storage_provider\") or \"DB\")}\".constantize",
|
||||||
|
"render_path": null,
|
||||||
|
"location": {
|
||||||
|
"type": "method",
|
||||||
|
"class": "File",
|
||||||
|
"method": "s(:self).add"
|
||||||
|
},
|
||||||
|
"user_input": "Setting.get(\"storage_provider\")",
|
||||||
|
"confidence": "Medium",
|
||||||
|
"note": "Setting.get('storage_provider') returns defined Store::Provider backend class names"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"warning_type": "Remote Code Execution",
|
||||||
|
"warning_code": 24,
|
||||||
|
"fingerprint": "582df3b442a09879f0c035b50f6c4fce9aa8285c907737476f16004246c67bc6",
|
||||||
|
"check_name": "UnsafeReflection",
|
||||||
|
"message": "Unsafe reflection method `safe_constantize` called with parameter value",
|
||||||
|
"file": "app/controllers/tests_controller.rb",
|
||||||
|
"line": 19,
|
||||||
|
"link": "https://brakemanscanner.org/docs/warning_types/remote_code_execution/",
|
||||||
|
"code": "params.fetch(:exception, \"StandardError\").safe_constantize",
|
||||||
|
"render_path": null,
|
||||||
|
"location": {
|
||||||
|
"type": "method",
|
||||||
|
"class": "TestsController",
|
||||||
|
"method": "error_raised_exception"
|
||||||
|
},
|
||||||
|
"user_input": "params.fetch(:exception, \"StandardError\")",
|
||||||
|
"confidence": "High",
|
||||||
|
"note": "Only for testing purposes"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"warning_type": "Denial of Service",
|
||||||
|
"warning_code": 76,
|
||||||
|
"fingerprint": "5840449fd32ff0c102ebe4b61132fbb129aae57636bbe407cbb809da7eb5a4ee",
|
||||||
|
"check_name": "RegexDoS",
|
||||||
|
"message": "Model attribute used in regular expression",
|
||||||
|
"file": "app/models/ticket/subject.rb",
|
||||||
|
"line": 61,
|
||||||
|
"link": "https://brakemanscanner.org/docs/warning_types/denial_of_service/",
|
||||||
|
"code": "/\\[#{Setting.get(\"ticket_hook\")}: #{number}\\](\\s+?|)/",
|
||||||
|
"render_path": null,
|
||||||
|
"location": {
|
||||||
|
"type": "method",
|
||||||
|
"class": "Ticket::Subject",
|
||||||
|
"method": "subject_clean"
|
||||||
|
},
|
||||||
|
"user_input": "Setting.get(\"ticket_hook\")",
|
||||||
|
"confidence": "Medium",
|
||||||
|
"note": "Admin configured RegExp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"warning_type": "Remote Code Execution",
|
||||||
|
"warning_code": 24,
|
||||||
|
"fingerprint": "73999042c4866cd2effe286fdd6a74c51659bc4a5fc760d1b96d35bd11b2bcda",
|
||||||
|
"check_name": "UnsafeReflection",
|
||||||
|
"message": "Unsafe reflection method `constantize` called with model attribute",
|
||||||
|
"file": "lib/transaction_dispatcher.rb",
|
||||||
|
"line": 37,
|
||||||
|
"link": "https://brakemanscanner.org/docs/warning_types/remote_code_execution/",
|
||||||
|
"code": "Setting.get(setting.name).constantize",
|
||||||
|
"render_path": null,
|
||||||
|
"location": {
|
||||||
|
"type": "method",
|
||||||
|
"class": "TransactionDispatcher",
|
||||||
|
"method": "s(:self).perform"
|
||||||
|
},
|
||||||
|
"user_input": "Setting.get(setting.name)",
|
||||||
|
"confidence": "Medium",
|
||||||
|
"note": "Setting.where(area: 'Transaction::Backend::Sync').order(:name) returns defined Transaction backend class names"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"warning_type": "Dangerous Send",
|
||||||
|
"warning_code": 23,
|
||||||
|
"fingerprint": "73f7454b7fdc88e0fb9cfc849b74006956a7a031836897a0b61d8d13dde94340",
|
||||||
|
"check_name": "Send",
|
||||||
|
"message": "User controlled method execution",
|
||||||
|
"file": "app/controllers/channels_sms_controller.rb",
|
||||||
|
"line": 48,
|
||||||
|
"link": "https://brakemanscanner.org/docs/warning_types/dangerous_send/",
|
||||||
|
"code": "Channel.driver_class(params[:options][:adapter]).new.send(params[:options], test_options)",
|
||||||
|
"render_path": null,
|
||||||
|
"location": {
|
||||||
|
"type": "method",
|
||||||
|
"class": "ChannelsSmsController",
|
||||||
|
"method": "test"
|
||||||
|
},
|
||||||
|
"user_input": "params[:options]",
|
||||||
|
"confidence": "High",
|
||||||
|
"note": "Channel#send is a custom implementation"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"warning_type": "Remote Code Execution",
|
||||||
|
"warning_code": 24,
|
||||||
|
"fingerprint": "7541faf8d3249dc4ac24f9c354024614ae79b0d6cd4c057f034ea88be1154bf7",
|
||||||
|
"check_name": "UnsafeReflection",
|
||||||
|
"message": "Unsafe reflection method `constantize` called with model attribute",
|
||||||
|
"file": "lib/application_lib.rb",
|
||||||
|
"line": 26,
|
||||||
|
"link": "https://brakemanscanner.org/docs/warning_types/remote_code_execution/",
|
||||||
|
"code": "Setting.get(setting).constantize",
|
||||||
|
"render_path": null,
|
||||||
|
"location": {
|
||||||
|
"type": "method",
|
||||||
|
"class": "ApplicationLib::ClassMethods",
|
||||||
|
"method": "load_adapter_by_setting"
|
||||||
|
},
|
||||||
|
"user_input": "Setting.get(setting)",
|
||||||
|
"confidence": "Medium",
|
||||||
|
"note": "ApplicationLib.load_adapter_by_setting works as designed"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"warning_type": "Denial of Service",
|
||||||
|
"warning_code": 76,
|
||||||
|
"fingerprint": "768e035d4bcb32ab79f5f747ccd5561d3c5f3a8ea74b2be08638d892be2249b2",
|
||||||
|
"check_name": "RegexDoS",
|
||||||
|
"message": "Model attribute used in regular expression",
|
||||||
|
"file": "app/models/ticket/number/date.rb",
|
||||||
|
"line": 49,
|
||||||
|
"link": "https://brakemanscanner.org/docs/warning_types/denial_of_service/",
|
||||||
|
"code": "/(?<=\\W|^)#{Regexp.quote(Setting.get(\"ticket_hook\"))}\\s{0,2}(\\d{4,10}#{(Setting.get(\"system_id\") or \"\")}\\d{2,40})\\b/i",
|
||||||
|
"render_path": null,
|
||||||
|
"location": {
|
||||||
|
"type": "method",
|
||||||
|
"class": "Ticket::Number::Date",
|
||||||
|
"method": "Ticket::Number::Date.check"
|
||||||
|
},
|
||||||
|
"user_input": "Setting.get(\"system_id\")",
|
||||||
|
"confidence": "Medium",
|
||||||
|
"note": "Admin configured RegExp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"warning_type": "SSL Verification Bypass",
|
||||||
|
"warning_code": 71,
|
||||||
|
"fingerprint": "7d088914c00f93dddb545ad9e567d59bf89dad493884b550ba72c014c0190011",
|
||||||
|
"check_name": "SSLVerify",
|
||||||
|
"message": "SSL certificate verification was bypassed",
|
||||||
|
"file": "lib/user_agent.rb",
|
||||||
|
"line": 335,
|
||||||
|
"link": "https://brakemanscanner.org/docs/warning_types/ssl_verification_bypass/",
|
||||||
|
"code": "(Net::HTTP.Proxy($1, $2, ((options[\"proxy_username\"] or Setting.get(\"proxy_username\")) or nil), ((options[\"proxy_password\"] or Setting.get(\"proxy_password\")) or nil)).new(uri.host, uri.port) or Net::HTTP.new(uri.host, uri.port)).verify_mode = OpenSSL::SSL::VERIFY_NONE",
|
||||||
|
"render_path": null,
|
||||||
|
"location": {
|
||||||
|
"type": "method",
|
||||||
|
"class": "UserAgent",
|
||||||
|
"method": "s(:self).get_http"
|
||||||
|
},
|
||||||
|
"user_input": null,
|
||||||
|
"confidence": "High",
|
||||||
|
"note": "SSL Verification can already be requested from callers. The default value should be switched to true at some point."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"warning_type": "Remote Code Execution",
|
||||||
|
"warning_code": 24,
|
||||||
|
"fingerprint": "8db3b4731daa1ef96c53729b2fca4cc91b47af058564f61cba24833aacaa55ae",
|
||||||
|
"check_name": "UnsafeReflection",
|
||||||
|
"message": "Unsafe reflection method `constantize` called with model attribute",
|
||||||
|
"file": "app/jobs/transaction_job.rb",
|
||||||
|
"line": 25,
|
||||||
|
"link": "https://brakemanscanner.org/docs/warning_types/remote_code_execution/",
|
||||||
|
"code": "Setting.get(setting.name).constantize",
|
||||||
|
"render_path": null,
|
||||||
|
"location": {
|
||||||
|
"type": "method",
|
||||||
|
"class": "TransactionJob",
|
||||||
|
"method": "perform"
|
||||||
|
},
|
||||||
|
"user_input": "Setting.get(setting.name)",
|
||||||
|
"confidence": "Medium",
|
||||||
|
"note": "Setting.where(area: 'Transaction::Backend::Async').order(:name) returns defined Transaction backend class names"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"warning_type": "Denial of Service",
|
||||||
|
"warning_code": 76,
|
||||||
|
"fingerprint": "949570adfbda072b1fa14632a6d7a0e829a632c699339dce93e1ff109bf79786",
|
||||||
|
"check_name": "RegexDoS",
|
||||||
|
"message": "Model attribute used in regular expression",
|
||||||
|
"file": "app/models/ticket/number/increment.rb",
|
||||||
|
"line": 41,
|
||||||
|
"link": "https://brakemanscanner.org/docs/warning_types/denial_of_service/",
|
||||||
|
"code": "/(?<=\\W|^)#{Regexp.quote(Setting.get(\"ticket_hook\"))}#{Regexp.quote(Setting.get(\"ticket_hook_divider\").to_s)}(#{(\"\" or Setting.get(\"system_id\").to_s)}\\d{2,48})\\b/i",
|
||||||
|
"render_path": null,
|
||||||
|
"location": {
|
||||||
|
"type": "method",
|
||||||
|
"class": "Ticket::Number::Increment",
|
||||||
|
"method": "Ticket::Number::Increment.check"
|
||||||
|
},
|
||||||
|
"user_input": "Setting.get(\"system_id\").to_s",
|
||||||
|
"confidence": "Medium",
|
||||||
|
"note": "Admin configured RegExp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"warning_type": "Denial of Service",
|
||||||
|
"warning_code": 76,
|
||||||
|
"fingerprint": "9bb8bfef12e845cf5264fc09d776c90c4458dee93f69d70689e1caa9a0dd4c8a",
|
||||||
|
"check_name": "RegexDoS",
|
||||||
|
"message": "Model attribute used in regular expression",
|
||||||
|
"file": "app/models/ticket/subject.rb",
|
||||||
|
"line": 68,
|
||||||
|
"link": "https://brakemanscanner.org/docs/warning_types/denial_of_service/",
|
||||||
|
"code": "/#{Setting.get(\"ticket_hook\")}#{Setting.get(\"ticket_hook_divider\")}#{number}(\\s+?|)/",
|
||||||
|
"render_path": null,
|
||||||
|
"location": {
|
||||||
|
"type": "method",
|
||||||
|
"class": "Ticket::Subject",
|
||||||
|
"method": "subject_clean"
|
||||||
|
},
|
||||||
|
"user_input": "Setting.get(\"ticket_hook\")",
|
||||||
|
"confidence": "Medium",
|
||||||
|
"note": "Admin configured RegExp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"warning_type": "SQL Injection",
|
||||||
|
"warning_code": 0,
|
||||||
|
"fingerprint": "9ec74dbe0ca90264aab31f05df4f0565f53e28477c93ced418e0249913c519fc",
|
||||||
|
"check_name": "SQL",
|
||||||
|
"message": "Possible SQL injection",
|
||||||
|
"file": "app/models/organization/search.rb",
|
||||||
|
"line": 116,
|
||||||
|
"link": "https://brakemanscanner.org/docs/warning_types/sql_injection/",
|
||||||
|
"code": "Organization.select(\"DISTINCT(organizations.id), #{::SqlHelper.new(:object => (self)).get_order_select(::SqlHelper.new(:object => (self)).get_sort_by(params, [\"active\", \"updated_at\"]), ::SqlHelper.new(:object => (self)).get_order_by(params, [\"desc\", \"desc\"]), \"organizations.updated_at\")}\")",
|
||||||
|
"render_path": null,
|
||||||
|
"location": {
|
||||||
|
"type": "method",
|
||||||
|
"class": "Organization",
|
||||||
|
"method": "search"
|
||||||
|
},
|
||||||
|
"user_input": "::SqlHelper.new(:object => (self)).get_order_select(::SqlHelper.new(:object => (self)).get_sort_by(params, [\"active\", \"updated_at\"]), ::SqlHelper.new(:object => (self)).get_order_by(params, [\"desc\", \"desc\"]), \"organizations.updated_at\")",
|
||||||
|
"confidence": "Medium",
|
||||||
|
"note": "SqlHelper does properly escape table and column names."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"warning_type": "Denial of Service",
|
||||||
|
"warning_code": 76,
|
||||||
|
"fingerprint": "a08cb6cbb584ab6bf0a1c068a0e99336b97bb68d98aa0294cc4e1184f15aaf9a",
|
||||||
|
"check_name": "RegexDoS",
|
||||||
|
"message": "Model attribute used in regular expression",
|
||||||
|
"file": "app/models/ticket/subject.rb",
|
||||||
|
"line": 66,
|
||||||
|
"link": "https://brakemanscanner.org/docs/warning_types/denial_of_service/",
|
||||||
|
"code": "/#{Setting.get(\"ticket_hook\")}: #{number}(\\s+?|)/",
|
||||||
|
"render_path": null,
|
||||||
|
"location": {
|
||||||
|
"type": "method",
|
||||||
|
"class": "Ticket::Subject",
|
||||||
|
"method": "subject_clean"
|
||||||
|
},
|
||||||
|
"user_input": "Setting.get(\"ticket_hook\")",
|
||||||
|
"confidence": "Medium",
|
||||||
|
"note": "Admin configured RegExp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"warning_type": "SQL Injection",
|
||||||
|
"warning_code": 0,
|
||||||
|
"fingerprint": "a5818edfcce4a3860c36ce71d434d1d4dd91fe3cac9ac945c71e4e2932ffe6cc",
|
||||||
|
"check_name": "SQL",
|
||||||
|
"message": "Possible SQL injection",
|
||||||
|
"file": "app/models/ticket/search.rb",
|
||||||
|
"line": 203,
|
||||||
|
"link": "https://brakemanscanner.org/docs/warning_types/sql_injection/",
|
||||||
|
"code": "Ticket.select(\"DISTINCT(tickets.id), #{::SqlHelper.new(:object => (self)).get_order_select(::SqlHelper.new(:object => (self)).get_sort_by(params, \"updated_at\"), ::SqlHelper.new(:object => (self)).get_order_by(params, \"desc\"), \"tickets.updated_at\")}\")",
|
||||||
|
"render_path": null,
|
||||||
|
"location": {
|
||||||
|
"type": "method",
|
||||||
|
"class": "Ticket::Search",
|
||||||
|
"method": "search"
|
||||||
|
},
|
||||||
|
"user_input": "::SqlHelper.new(:object => (self)).get_order_select(::SqlHelper.new(:object => (self)).get_sort_by(params, \"updated_at\"), ::SqlHelper.new(:object => (self)).get_order_by(params, \"desc\"), \"tickets.updated_at\")",
|
||||||
|
"confidence": "Medium",
|
||||||
|
"note": "SqlHelper does properly escape table and column names."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"warning_type": "SQL Injection",
|
||||||
|
"warning_code": 0,
|
||||||
|
"fingerprint": "a5818edfcce4a3860c36ce71d434d1d4dd91fe3cac9ac945c71e4e2932ffe6cc",
|
||||||
|
"check_name": "SQL",
|
||||||
|
"message": "Possible SQL injection",
|
||||||
|
"file": "app/models/ticket/search.rb",
|
||||||
|
"line": 212,
|
||||||
|
"link": "https://brakemanscanner.org/docs/warning_types/sql_injection/",
|
||||||
|
"code": "Ticket.select(\"DISTINCT(tickets.id), #{::SqlHelper.new(:object => (self)).get_order_select(::SqlHelper.new(:object => (self)).get_sort_by(params, \"updated_at\"), ::SqlHelper.new(:object => (self)).get_order_by(params, \"desc\"), \"tickets.updated_at\")}\")",
|
||||||
|
"render_path": null,
|
||||||
|
"location": {
|
||||||
|
"type": "method",
|
||||||
|
"class": "Ticket::Search",
|
||||||
|
"method": "search"
|
||||||
|
},
|
||||||
|
"user_input": "::SqlHelper.new(:object => (self)).get_order_select(::SqlHelper.new(:object => (self)).get_sort_by(params, \"updated_at\"), ::SqlHelper.new(:object => (self)).get_order_by(params, \"desc\"), \"tickets.updated_at\")",
|
||||||
|
"confidence": "Medium",
|
||||||
|
"note": "SqlHelper does properly escape table and column names."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"warning_type": "Dangerous Send",
|
||||||
|
"warning_code": 23,
|
||||||
|
"fingerprint": "b24120f184a097dbf931fd0c251e26b431fc4a0ac679f02ed2c85a9ebb338cc7",
|
||||||
|
"check_name": "Send",
|
||||||
|
"message": "User controlled method execution",
|
||||||
|
"file": "app/controllers/attachments_controller.rb",
|
||||||
|
"line": 87,
|
||||||
|
"link": "https://brakemanscanner.org/docs/warning_types/dangerous_send/",
|
||||||
|
"code": "Store.find(params[:id]).store_object.name.safe_constantize.send(\"can_#{params[:action]}_attachment?\", Store.find(params[:id]), current_user)",
|
||||||
|
"render_path": null,
|
||||||
|
"location": {
|
||||||
|
"type": "method",
|
||||||
|
"class": "AttachmentsController",
|
||||||
|
"method": "verify_object_permissions"
|
||||||
|
},
|
||||||
|
"user_input": "params[:action]",
|
||||||
|
"confidence": "High",
|
||||||
|
"note": "Save because 'before_action' is limited to defined actions"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"warning_type": "Remote Code Execution",
|
||||||
|
"warning_code": 24,
|
||||||
|
"fingerprint": "b4e5b1ad22930f849b12cbdf519dced6ec46b6cc653504f0a8e910c0a9590d61",
|
||||||
|
"check_name": "UnsafeReflection",
|
||||||
|
"message": "Unsafe reflection method `constantize` called with model attribute",
|
||||||
|
"file": "app/models/object_manager/attribute.rb",
|
||||||
|
"line": 806,
|
||||||
|
"link": "https://brakemanscanner.org/docs/warning_types/remote_code_execution/",
|
||||||
|
"code": "ObjectLookup.by_id(object_lookup_id).constantize",
|
||||||
|
"render_path": null,
|
||||||
|
"location": {
|
||||||
|
"type": "method",
|
||||||
|
"class": "ObjectManager::Attribute",
|
||||||
|
"method": "check_name"
|
||||||
|
},
|
||||||
|
"user_input": "ObjectLookup.by_id(object_lookup_id)",
|
||||||
|
"confidence": "Medium",
|
||||||
|
"note": "ObjectLookup.by_id works as designed"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"warning_type": "Denial of Service",
|
||||||
|
"warning_code": 76,
|
||||||
|
"fingerprint": "befcb5177e42e1d0c9184b046185ec84c7ecef8fc9b53822d8344f6a6a35860c",
|
||||||
|
"check_name": "RegexDoS",
|
||||||
|
"message": "Model attribute used in regular expression",
|
||||||
|
"file": "app/models/ticket/subject.rb",
|
||||||
|
"line": 62,
|
||||||
|
"link": "https://brakemanscanner.org/docs/warning_types/denial_of_service/",
|
||||||
|
"code": "/\\[#{Setting.get(\"ticket_hook\")}:#{number}\\](\\s+?|)/",
|
||||||
|
"render_path": null,
|
||||||
|
"location": {
|
||||||
|
"type": "method",
|
||||||
|
"class": "Ticket::Subject",
|
||||||
|
"method": "subject_clean"
|
||||||
|
},
|
||||||
|
"user_input": "Setting.get(\"ticket_hook\")",
|
||||||
|
"confidence": "Medium",
|
||||||
|
"note": "Admin configured RegExp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"warning_type": "SSL Verification Bypass",
|
||||||
|
"warning_code": 71,
|
||||||
|
"fingerprint": "cce91e3b231a7971f9f9d2298b8bba7b309610f4b98a88e530cac6fdd8efa1c4",
|
||||||
|
"check_name": "SSLVerify",
|
||||||
|
"message": "SSL certificate verification was bypassed",
|
||||||
|
"file": "app/controllers/integration/exchange_controller.rb",
|
||||||
|
"line": 17,
|
||||||
|
"link": "https://brakemanscanner.org/docs/warning_types/ssl_verification_bypass/",
|
||||||
|
"code": "Autodiscover::Client.new(:email => params[:user], :password => params[:password]).http.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE",
|
||||||
|
"render_path": null,
|
||||||
|
"location": {
|
||||||
|
"type": "method",
|
||||||
|
"class": "Integration::ExchangeController",
|
||||||
|
"method": "autodiscover"
|
||||||
|
},
|
||||||
|
"user_input": null,
|
||||||
|
"confidence": "High",
|
||||||
|
"note": "Only if requester sends `:disable_ssl_verify` param"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"warning_type": "Remote Code Execution",
|
||||||
|
"warning_code": 24,
|
||||||
|
"fingerprint": "d48809837203098f7be4803f19b4f180f93361030bcf145560c65582d44f8edc",
|
||||||
|
"check_name": "UnsafeReflection",
|
||||||
|
"message": "Unsafe reflection method `constantize` called with model attribute",
|
||||||
|
"file": "app/models/channel/email_parser.rb",
|
||||||
|
"line": 154,
|
||||||
|
"link": "https://brakemanscanner.org/docs/warning_types/remote_code_execution/",
|
||||||
|
"code": "Setting.get(setting.name).constantize",
|
||||||
|
"render_path": null,
|
||||||
|
"location": {
|
||||||
|
"type": "method",
|
||||||
|
"class": "Channel::EmailParser",
|
||||||
|
"method": "_process"
|
||||||
|
},
|
||||||
|
"user_input": "Setting.get(setting.name)",
|
||||||
|
"confidence": "Medium",
|
||||||
|
"note": "Setting.where(area: 'Postmaster::PreFilter').order(:name) returns defined postmaster backend class names"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"warning_type": "Remote Code Execution",
|
||||||
|
"warning_code": 24,
|
||||||
|
"fingerprint": "d48809837203098f7be4803f19b4f180f93361030bcf145560c65582d44f8edc",
|
||||||
|
"check_name": "UnsafeReflection",
|
||||||
|
"message": "Unsafe reflection method `constantize` called with model attribute",
|
||||||
|
"file": "app/models/channel/email_parser.rb",
|
||||||
|
"line": 318,
|
||||||
|
"link": "https://brakemanscanner.org/docs/warning_types/remote_code_execution/",
|
||||||
|
"code": "Setting.get(setting.name).constantize",
|
||||||
|
"render_path": null,
|
||||||
|
"location": {
|
||||||
|
"type": "method",
|
||||||
|
"class": "Channel::EmailParser",
|
||||||
|
"method": "_process"
|
||||||
|
},
|
||||||
|
"user_input": "Setting.get(setting.name)",
|
||||||
|
"confidence": "Medium",
|
||||||
|
"note": "Setting.where(area: 'Postmaster::PreFilter').order(:name) returns defined postmaster backend class names"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"warning_type": "Remote Code Execution",
|
||||||
|
"warning_code": 24,
|
||||||
|
"fingerprint": "e8789f715661836374232aa2ba4aa9eacbba8ea4961f5b26468a0d96c4c91e33",
|
||||||
|
"check_name": "UnsafeReflection",
|
||||||
|
"message": "Unsafe reflection method `safe_constantize` called with model attribute",
|
||||||
|
"file": "app/controllers/attachments_controller.rb",
|
||||||
|
"line": 86,
|
||||||
|
"link": "https://brakemanscanner.org/docs/warning_types/remote_code_execution/",
|
||||||
|
"code": "Store.find(params[:id]).store_object.name.safe_constantize",
|
||||||
|
"render_path": null,
|
||||||
|
"location": {
|
||||||
|
"type": "method",
|
||||||
|
"class": "AttachmentsController",
|
||||||
|
"method": "verify_object_permissions"
|
||||||
|
},
|
||||||
|
"user_input": "Store.find(params[:id]).store_object",
|
||||||
|
"confidence": "Medium",
|
||||||
|
"note": "Store#store_object returns defined Model objects"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"warning_type": "Denial of Service",
|
||||||
|
"warning_code": 76,
|
||||||
|
"fingerprint": "ea2a3af842a48c9ef4dc8d142abd56978baa4823a598d2a76dc8f840799d6967",
|
||||||
|
"check_name": "RegexDoS",
|
||||||
|
"message": "Model attribute used in regular expression",
|
||||||
|
"file": "app/models/ticket/number/date.rb",
|
||||||
|
"line": 44,
|
||||||
|
"link": "https://brakemanscanner.org/docs/warning_types/denial_of_service/",
|
||||||
|
"code": "/(?<=\\W|^)#{Regexp.quote(Setting.get(\"ticket_hook\"))}#{Regexp.quote((Setting.get(\"ticket_hook_divider\") or \"\"))}(\\d{4,10}#{(Setting.get(\"system_id\") or \"\")}\\d{2,40})\\b/i",
|
||||||
|
"render_path": null,
|
||||||
|
"location": {
|
||||||
|
"type": "method",
|
||||||
|
"class": "Ticket::Number::Date",
|
||||||
|
"method": "Ticket::Number::Date.check"
|
||||||
|
},
|
||||||
|
"user_input": "Setting.get(\"system_id\")",
|
||||||
|
"confidence": "Medium",
|
||||||
|
"note": "Admin configured RegExp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"warning_type": "Session Setting",
|
||||||
|
"warning_code": 29,
|
||||||
|
"fingerprint": "f0ee1cc1980474c82a013645508f002dcc801e00db5592f7dd8cd6bdb93c73fe",
|
||||||
|
"check_name": "SessionSettings",
|
||||||
|
"message": "Session secret should not be included in version control",
|
||||||
|
"file": "config/secrets.yml",
|
||||||
|
"line": 2,
|
||||||
|
"link": "https://brakemanscanner.org/docs/warning_types/session_setting/",
|
||||||
|
"code": null,
|
||||||
|
"render_path": null,
|
||||||
|
"location": null,
|
||||||
|
"user_input": null,
|
||||||
|
"confidence": "High",
|
||||||
|
"note": "Since Sessions are stored in the database and not in cookies, the session secret is not used / not relevant.\""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"warning_type": "SQL Injection",
|
||||||
|
"warning_code": 0,
|
||||||
|
"fingerprint": "fcad47a712a324ace0e97560767e5420500df03fd3de3057198800bdea5fd324",
|
||||||
|
"check_name": "SQL",
|
||||||
|
"message": "Possible SQL injection",
|
||||||
|
"file": "lib/models.rb",
|
||||||
|
"line": 171,
|
||||||
|
"link": "https://brakemanscanner.org/docs/warning_types/sql_injection/",
|
||||||
|
"code": "model_class.where(\"#{reflection_value.name}_id\" => object_id)",
|
||||||
|
"render_path": null,
|
||||||
|
"location": {
|
||||||
|
"type": "method",
|
||||||
|
"class": "Models",
|
||||||
|
"method": "s(:self).references"
|
||||||
|
},
|
||||||
|
"user_input": "reflection_value.name",
|
||||||
|
"confidence": "Weak",
|
||||||
|
"note": "Reflections come from the models themselves and are thus safe to use."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"warning_type": "SQL Injection",
|
||||||
|
"warning_code": 0,
|
||||||
|
"fingerprint": "fcad47a712a324ace0e97560767e5420500df03fd3de3057198800bdea5fd324",
|
||||||
|
"check_name": "SQL",
|
||||||
|
"message": "Possible SQL injection",
|
||||||
|
"file": "lib/models.rb",
|
||||||
|
"line": 184,
|
||||||
|
"link": "https://brakemanscanner.org/docs/warning_types/sql_injection/",
|
||||||
|
"code": "model_class.where(\"#{reflection_value.name}_id\" => object_id)",
|
||||||
|
"render_path": null,
|
||||||
|
"location": {
|
||||||
|
"type": "method",
|
||||||
|
"class": "Models",
|
||||||
|
"method": "s(:self).references"
|
||||||
|
},
|
||||||
|
"user_input": "reflection_value.name",
|
||||||
|
"confidence": "Weak",
|
||||||
|
"note": "Reflections come from the models themselves and are thus safe to use."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"warning_type": "Denial of Service",
|
||||||
|
"warning_code": 76,
|
||||||
|
"fingerprint": "fe906d9ee6b37c92b7deec029d6a4cca47071006440817e4a50292b2ca956a30",
|
||||||
|
"check_name": "RegexDoS",
|
||||||
|
"message": "Model attribute used in regular expression",
|
||||||
|
"file": "app/models/ticket.rb",
|
||||||
|
"line": 1612,
|
||||||
|
"link": "https://brakemanscanner.org/docs/warning_types/denial_of_service/",
|
||||||
|
"code": "/#{Setting.get(\"send_no_auto_response_reg_exp\")}/i",
|
||||||
|
"render_path": null,
|
||||||
|
"location": {
|
||||||
|
"type": "method",
|
||||||
|
"class": "Ticket",
|
||||||
|
"method": "send_email_notification"
|
||||||
|
},
|
||||||
|
"user_input": "Setting.get(\"send_no_auto_response_reg_exp\")",
|
||||||
|
"confidence": "Medium",
|
||||||
|
"note": "Admin configured RegExp"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"updated": "2021-07-20 13:22:48 +0200",
|
||||||
|
"brakeman_version": "5.0.4"
|
||||||
|
}
|
3
config/brakeman.yml
Normal file
3
config/brakeman.yml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
---
|
||||||
|
:skip_checks:
|
||||||
|
- CheckMassAssignment
|
|
@ -4,4 +4,6 @@
|
||||||
|
|
||||||
# Specify a serializer for the signed and encrypted cookie jars.
|
# Specify a serializer for the signed and encrypted cookie jars.
|
||||||
# Valid options are :json, :marshal, and :hybrid.
|
# Valid options are :json, :marshal, and :hybrid.
|
||||||
Rails.application.config.action_dispatch.cookies_serializer = :marshal
|
|
||||||
|
# Since sessions are stored in the database, the serializer is not used / not relevant.
|
||||||
|
# Rails.application.config.action_dispatch.cookies_serializer = :json
|
||||||
|
|
|
@ -24,6 +24,7 @@ class GitHub
|
||||||
log: {
|
log: {
|
||||||
facility: 'GitHub',
|
facility: 'GitHub',
|
||||||
},
|
},
|
||||||
|
verify_ssl: true,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ class GitLab
|
||||||
log: {
|
log: {
|
||||||
facility: 'GitLab',
|
facility: 'GitLab',
|
||||||
},
|
},
|
||||||
|
verify_ssl: true,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -145,7 +145,7 @@ returns
|
||||||
ref_attributes.each do |item|
|
ref_attributes.each do |item|
|
||||||
next if model_attributes[:attributes].exclude?(item)
|
next if model_attributes[:attributes].exclude?(item)
|
||||||
|
|
||||||
count = model_class.where("#{item} = ?", object_id).count
|
count = model_class.where(item => object_id).count
|
||||||
next if count.zero? && !include_zero
|
next if count.zero? && !include_zero
|
||||||
|
|
||||||
if !references[model_class.to_s][item]
|
if !references[model_class.to_s][item]
|
||||||
|
@ -168,7 +168,7 @@ returns
|
||||||
next if ref_attributes.include?(col_name)
|
next if ref_attributes.include?(col_name)
|
||||||
|
|
||||||
if reflection_value.options[:class_name] == object_name
|
if reflection_value.options[:class_name] == object_name
|
||||||
count = model_class.where("#{col_name} = ?", object_id).count
|
count = model_class.where(col_name => object_id).count
|
||||||
next if count.zero? && !include_zero
|
next if count.zero? && !include_zero
|
||||||
|
|
||||||
if !references[model_class.to_s][col_name]
|
if !references[model_class.to_s][col_name]
|
||||||
|
@ -181,7 +181,7 @@ returns
|
||||||
next if reflection_value.options[:class_name]
|
next if reflection_value.options[:class_name]
|
||||||
next if reflection_value.name != object_name.downcase.to_sym
|
next if reflection_value.name != object_name.downcase.to_sym
|
||||||
|
|
||||||
count = model_class.where("#{col_name} = ?", object_id).count
|
count = model_class.where(col_name => object_id).count
|
||||||
next if count.zero? && !include_zero
|
next if count.zero? && !include_zero
|
||||||
|
|
||||||
if !references[model_class.to_s][col_name]
|
if !references[model_class.to_s][col_name]
|
||||||
|
@ -256,7 +256,7 @@ returns
|
||||||
items_to_update = {}
|
items_to_update = {}
|
||||||
attributes.each_key do |attribute|
|
attributes.each_key do |attribute|
|
||||||
Rails.logger.debug { "#{object_name}: #{model}.#{attribute}->#{object_id_to_merge}->#{object_id_primary}" }
|
Rails.logger.debug { "#{object_name}: #{model}.#{attribute}->#{object_id_to_merge}->#{object_id_primary}" }
|
||||||
model_object.where("#{attribute} = ?", object_id_to_merge).each do |item|
|
model_object.where(attribute => object_id_to_merge).each do |item|
|
||||||
if !items_to_update[item.id]
|
if !items_to_update[item.id]
|
||||||
items_to_update[item.id] = item
|
items_to_update[item.id] = item
|
||||||
end
|
end
|
||||||
|
|
|
@ -43,6 +43,7 @@ class Sequencer
|
||||||
{
|
{
|
||||||
open_timeout: 20,
|
open_timeout: 20,
|
||||||
read_timeout: 240,
|
read_timeout: 240,
|
||||||
|
verify_ssl: true,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,7 @@ class Sequencer
|
||||||
{
|
{
|
||||||
open_timeout: 20,
|
open_timeout: 20,
|
||||||
read_timeout: 240,
|
read_timeout: 240,
|
||||||
|
verify_ssl: true,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,7 @@ class Sequencer
|
||||||
{
|
{
|
||||||
open_timeout: 20,
|
open_timeout: 20,
|
||||||
read_timeout: 240,
|
read_timeout: 240,
|
||||||
|
verify_ssl: true,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
|
@ -25,6 +25,7 @@ class Service::GeoCalendar::Zammad
|
||||||
open_timeout: 2,
|
open_timeout: 2,
|
||||||
read_timeout: 4,
|
read_timeout: 4,
|
||||||
total_timeout: 12,
|
total_timeout: 12,
|
||||||
|
verify_ssl: true,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
if !response.success? && response.code.to_s !~ %r{^40.$}
|
if !response.success? && response.code.to_s !~ %r{^40.$}
|
||||||
|
|
|
@ -23,6 +23,7 @@ class Service::GeoIp::Zammad
|
||||||
open_timeout: 2,
|
open_timeout: 2,
|
||||||
read_timeout: 4,
|
read_timeout: 4,
|
||||||
total_timeout: 4,
|
total_timeout: 4,
|
||||||
|
verify_ssl: true,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
if !response.success? && response.code.to_s !~ %r{^40.$}
|
if !response.success? && response.code.to_s !~ %r{^40.$}
|
||||||
|
|
|
@ -11,6 +11,7 @@ class Service::GeoLocation::Gmaps
|
||||||
open_timeout: 2,
|
open_timeout: 2,
|
||||||
read_timeout: 4,
|
read_timeout: 4,
|
||||||
total_timeout: 4,
|
total_timeout: 4,
|
||||||
|
verify_ssl: true,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
return if !response.success?
|
return if !response.success?
|
||||||
|
@ -36,6 +37,7 @@ class Service::GeoLocation::Gmaps
|
||||||
open_timeout: 2,
|
open_timeout: 2,
|
||||||
read_timeout: 4,
|
read_timeout: 4,
|
||||||
total_timeout: 4,
|
total_timeout: 4,
|
||||||
|
verify_ssl: true,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
return if !response.success?
|
return if !response.success?
|
||||||
|
|
|
@ -24,6 +24,7 @@ class Service::Image::Zammad
|
||||||
open_timeout: OPEN_TIMEOUT,
|
open_timeout: OPEN_TIMEOUT,
|
||||||
read_timeout: READ_TIMEOUT,
|
read_timeout: READ_TIMEOUT,
|
||||||
total_timeout: TOTAL_TIMEOUT,
|
total_timeout: TOTAL_TIMEOUT,
|
||||||
|
verify_ssl: true,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
if !response.success?
|
if !response.success?
|
||||||
|
@ -57,6 +58,7 @@ class Service::Image::Zammad
|
||||||
open_timeout: OPEN_TIMEOUT,
|
open_timeout: OPEN_TIMEOUT,
|
||||||
read_timeout: READ_TIMEOUT,
|
read_timeout: READ_TIMEOUT,
|
||||||
total_timeout: TOTAL_TIMEOUT,
|
total_timeout: TOTAL_TIMEOUT,
|
||||||
|
verify_ssl: true,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
if !response.success?
|
if !response.success?
|
||||||
|
|
|
@ -795,6 +795,7 @@ returns
|
||||||
{
|
{
|
||||||
open_timeout: 20,
|
open_timeout: 20,
|
||||||
read_timeout: 40,
|
read_timeout: 40,
|
||||||
|
verify_ssl: true,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
|
@ -779,6 +779,7 @@ download public media file from twitter
|
||||||
{
|
{
|
||||||
open_timeout: 20,
|
open_timeout: 20,
|
||||||
read_timeout: 40,
|
read_timeout: 40,
|
||||||
|
verify_ssl: true,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
|
@ -18,7 +18,7 @@ RSpec.describe Sequencer::Unit::Import::Zendesk::Ticket::Comment::Attachment::Re
|
||||||
|
|
||||||
it 'open timeout should be 20s and read timeout should be 240s' do
|
it 'open timeout should be 20s and read timeout should be 240s' do
|
||||||
allow(response).to receive(:success?).and_return(true)
|
allow(response).to receive(:success?).and_return(true)
|
||||||
allow(UserAgent).to receive(:get).with(any_args, { open_timeout: 20, read_timeout: 240 }).and_return(response)
|
allow(UserAgent).to receive(:get).with(any_args, { open_timeout: 20, read_timeout: 240, verify_ssl: true }).and_return(response)
|
||||||
process(mock_parameters)
|
process(mock_parameters)
|
||||||
expect(UserAgent).to have_received(:get)
|
expect(UserAgent).to have_received(:get)
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue