diff --git a/.github/workflows/brakeman.yml b/.github/workflows/brakeman.yml new file mode 100644 index 000000000..d820e8c86 --- /dev/null +++ b/.github/workflows/brakeman.yml @@ -0,0 +1,25 @@ +name: Brakeman Security Scan + +on: + pull_request: + workflow_dispatch: + +jobs: + brakeman: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: .ruby-version + bundler-cache: true + + - name: Install dependencies + run: bundle install --jobs 4 --retry 3 + + - name: Run Brakeman + run: bundle exec brakeman --ignore-config config/brakeman.ignore --exit-on-warn --quiet diff --git a/Gemfile b/Gemfile index 8c0bf4a43..b56578b32 100644 --- a/Gemfile +++ b/Gemfile @@ -79,4 +79,6 @@ group :development, :test do # NOTE: This enable GitHub Codespaces. Uncomment for YAGNI. # https://github.com/coderdojo-japan/coderdojo.jp/pull/1526 #gem 'mini_racer' + + gem 'brakeman', require: false end diff --git a/Gemfile.lock b/Gemfile.lock index d370cfb37..19ccb1e89 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -109,6 +109,8 @@ GEM bootstrap-sass (3.4.1) autoprefixer-rails (>= 5.2.1) sassc (>= 2.0.0) + brakeman (7.1.0) + racc builder (3.3.0) capybara (3.40.0) addressable @@ -489,6 +491,7 @@ DEPENDENCIES aws-sdk-s3 (~> 1) bootsnap bootstrap-sass + brakeman capybara connpass_api_v2 csv diff --git a/app/views/pokemons/show.html.erb b/app/views/pokemons/show.html.erb index eb4d26ed5..794fb34f3 100644 --- a/app/views/pokemons/show.html.erb +++ b/app/views/pokemons/show.html.erb @@ -12,7 +12,7 @@

ボタンをクリックして、
ポケモン素材をダウンロードしよう!

- <%=# link_to @presigned_url, class: "btn-blue", style: "max-width:320px; display:block; margin:20px auto 100px;" do %> + <% # link_to @presigned_url, class: "btn-blue", style: "max-width:320px; display:block; margin:20px auto 100px;" do %> ポケモン素材をダウンロードする <%# end %> diff --git a/config/brakeman.ignore b/config/brakeman.ignore new file mode 100644 index 000000000..4b3ac0252 --- /dev/null +++ b/config/brakeman.ignore @@ -0,0 +1,273 @@ +{ + "ignored_warnings": [ + { + "warning_type": "Dynamic Render Path", + "warning_code": 15, + "fingerprint": "69b5a133fab8ea617d2581423cefaf077b9366e683c5fac715647bddeec7f50a", + "check_name": "Render", + "message": "Render path contains parameter value", + "file": "app/controllers/sotechsha_pages_controller.rb", + "line": 5, + "link": "https://brakemanscanner.org/docs/warning_types/dynamic_render_path/", + "code": "render(action => \"sotechsha_pages/#{params[:page]}\", {})", + "render_path": null, + "location": { + "type": "method", + "class": "SotechshaPagesController", + "method": "show" + }, + "user_input": "params[:page]", + "confidence": "Medium", + "cwe_id": [ + 22 + ], + "note": "" + }, + { + "warning_type": "Command Injection", + "warning_code": 14, + "fingerprint": "7307f11036b1ab86f410d8d967d3972618705df73cafdd17f8e311c10c76c1f1", + "check_name": "Execute", + "message": "Possible command injection", + "file": "lib/statistics/aggregation.rb", + "line": 163, + "link": "https://brakemanscanner.org/docs/warning_types/command_injection/", + "code": "`curl -X POST -H 'Content-type: application/json' --data '{\"text\":\"#{msg}\"}' #{slack_hook_url} -o /dev/null -w \"slack: %{http_code}\"`", + "render_path": null, + "location": { + "type": "method", + "class": "Statistics::Statistics::Aggregation::Notifier", + "method": "s(:self).notify" + }, + "user_input": "msg", + "confidence": "Medium", + "cwe_id": [ + 77 + ], + "note": "" + }, + { + "warning_type": "Cross-Site Scripting", + "warning_code": 4, + "fingerprint": "8ba988098c444755698e4e65d38a94f4095948c1a9bc6220c7e2a4636c3c04d7", + "check_name": "LinkToHref", + "message": "Potentially unsafe model attribute in `link_to` href", + "file": "app/views/shared/_dojo.html.erb", + "line": 6, + "link": "https://brakemanscanner.org/docs/warning_types/link_to_href", + "code": "link_to(\"#{Dojo.new.name} (#{Dojo.new.prefecture.name})\", Dojo.new.url, :target => \"_blank\", :rel => \"external noopener\")", + "render_path": [ + { + "type": "controller", + "class": "HomeController", + "method": "show", + "line": 7, + "file": "app/controllers/home_controller.rb", + "rendered": { + "name": "home/show", + "file": "app/views/home/show.html.erb" + } + }, + { + "type": "template", + "name": "home/show", + "line": 161, + "file": "app/views/home/show.html.erb", + "rendered": { + "name": "shared/_dojos", + "file": "app/views/shared/_dojos.html.erb" + } + }, + { + "type": "template", + "name": "shared/_dojos", + "line": 2, + "file": "app/views/shared/_dojos.html.erb", + "rendered": { + "name": "shared/_dojo", + "file": "app/views/shared/_dojo.html.erb" + } + } + ], + "location": { + "type": "template", + "template": "shared/_dojo" + }, + "user_input": "Dojo.new.url", + "confidence": "Weak", + "cwe_id": [ + 79 + ], + "note": "" + }, + { + "warning_type": "Cross-Site Scripting", + "warning_code": 2, + "fingerprint": "b22a549fb14a7e6b3a9c34991ffcacd354dc768d74d50a8f6901e23c3ea19538", + "check_name": "CrossSiteScripting", + "message": "Unescaped model attribute", + "file": "app/views/podcasts/show.html.erb", + "line": 39, + "link": "https://brakemanscanner.org/docs/warning_types/cross_site_scripting", + "code": "Rinku.auto_link(Kramdown::Document.new(self.convert_shownote(Podcast.find_by(:id => params[:id]).content), :input => \"GFM\").to_html)", + "render_path": [ + { + "type": "controller", + "class": "PodcastsController", + "method": "show", + "line": 31, + "file": "app/controllers/podcasts_controller.rb", + "rendered": { + "name": "podcasts/show", + "file": "app/views/podcasts/show.html.erb" + } + } + ], + "location": { + "type": "template", + "template": "podcasts/show" + }, + "user_input": "Podcast.find_by(:id => params[:id]).content", + "confidence": "Weak", + "cwe_id": [ + 79 + ], + "note": "" + }, + { + "warning_type": "Cross-Site Scripting", + "warning_code": 4, + "fingerprint": "b29f98f4da690ffb7c663390c21db3a71174dae17d06234deab9d6655af6babe", + "check_name": "LinkToHref", + "message": "Potentially unsafe model attribute in `link_to` href", + "file": "app/views/shared/_dojo.html.erb", + "line": 3, + "link": "https://brakemanscanner.org/docs/warning_types/link_to_href", + "code": "link_to(lazy_image_tag(Dojo.new.logo, :alt => (\"CoderDojo #{Dojo.new.name}\"), :class => \"dojo-picture\"), Dojo.new.url, :target => \"_blank\", :rel => \"external noopener\")", + "render_path": [ + { + "type": "controller", + "class": "HomeController", + "method": "show", + "line": 7, + "file": "app/controllers/home_controller.rb", + "rendered": { + "name": "home/show", + "file": "app/views/home/show.html.erb" + } + }, + { + "type": "template", + "name": "home/show", + "line": 161, + "file": "app/views/home/show.html.erb", + "rendered": { + "name": "shared/_dojos", + "file": "app/views/shared/_dojos.html.erb" + } + }, + { + "type": "template", + "name": "shared/_dojos", + "line": 2, + "file": "app/views/shared/_dojos.html.erb", + "rendered": { + "name": "shared/_dojo", + "file": "app/views/shared/_dojo.html.erb" + } + } + ], + "location": { + "type": "template", + "template": "shared/_dojo" + }, + "user_input": "Dojo.new.url", + "confidence": "Weak", + "cwe_id": [ + 79 + ], + "note": "" + }, + { + "warning_type": "Dynamic Render Path", + "warning_code": 15, + "fingerprint": "c54623ebce2c2053b95088b9da8112aee962e7cadd79bd9b4b9afdedaddc15b1", + "check_name": "Render", + "message": "Render path contains parameter value", + "file": "app/controllers/sotechsha2_pages_controller.rb", + "line": 5, + "link": "https://brakemanscanner.org/docs/warning_types/dynamic_render_path/", + "code": "render(action => \"sotechsha2_pages/#{params[:page]}\", {})", + "render_path": null, + "location": { + "type": "method", + "class": "Sotechsha2PagesController", + "method": "show" + }, + "user_input": "params[:page]", + "confidence": "Medium", + "cwe_id": [ + 22 + ], + "note": "" + }, + { + "warning_type": "Cross-Site Scripting", + "warning_code": 2, + "fingerprint": "e4187193a881ef4e98b77f205c86fcafbef3d65d9269bba30e8612f6a59273ed", + "check_name": "CrossSiteScripting", + "message": "Unescaped model attribute", + "file": "app/views/docs/show.html.erb", + "line": 12, + "link": "https://brakemanscanner.org/docs/warning_types/cross_site_scripting", + "code": "Kramdown::Document.new(Document.new(params[:id]).content, :input => \"GFM\").to_html", + "render_path": [ + { + "type": "controller", + "class": "DocsController", + "method": "show", + "line": 42, + "file": "app/controllers/docs_controller.rb", + "rendered": { + "name": "docs/show", + "file": "app/views/docs/show.html.erb" + } + } + ], + "location": { + "type": "template", + "template": "docs/show" + }, + "user_input": "Document.new(params[:id]).content", + "confidence": "Weak", + "cwe_id": [ + 79 + ], + "note": "" + }, + { + "warning_type": "Command Injection", + "warning_code": 14, + "fingerprint": "e5394a11f2e9bb6bc213b7ebd34fbcead20048858592aa19e5ae2961f33c636d", + "check_name": "Execute", + "message": "Possible command injection", + "file": "lib/upcoming_events/aggregation.rb", + "line": 89, + "link": "https://brakemanscanner.org/docs/warning_types/command_injection/", + "code": "`curl -X POST -H 'Content-type: application/json' --data '{\"text\":\"#{msg}\"}' #{slack_hook_url} -o /dev/null -w \"slack: %{http_code}\"`", + "render_path": null, + "location": { + "type": "method", + "class": "UpcomingEvents::UpcomingEvents::Aggregation::Notifier", + "method": "s(:self).notify" + }, + "user_input": "msg", + "confidence": "Medium", + "cwe_id": [ + 77 + ], + "note": "" + } + ], + "brakeman_version": "7.1.0" +}