Skip to content

fix: XSS脆弱性の修正#6635

Open
kurozumi wants to merge 6 commits intoEC-CUBE:4.3from
kurozumi:audit/security-code-review
Open

fix: XSS脆弱性の修正#6635
kurozumi wants to merge 6 commits intoEC-CUBE:4.3from
kurozumi:audit/security-code-review

Conversation

@kurozumi
Copy link
Contributor

@kurozumi kurozumi commented Feb 24, 2026

Summary

  • テンプレートのHTMLコンテンツに |purify フィルターを追加してXSSを防止
  • JSON出力に JSON_HEX_TAG 等のセキュリティオプションを追加
  • 安全なJSONエンコード用の json_encode_safe フィルターを追加

修正内容

1. テンプレートの修正(|raw|raw|purify

ファイル 対象フィールド
default/Product/detail.twig Product.description_detail
default/Product/list.twig Product.description_list
default/Block/news.twig News.description
default/Help/tradelaw.twig tradelaw.description
default/Shopping/index.twig activeTradeLaw.description
default/Shopping/confirm.twig activeTradeLaw.description

2. JSON出力の修正

ファイル 修正内容
EccubeExtension.php getClassCategoriesAsJson()JSON_HEX_* オプション追加、json_encode_safe フィルター追加
FileController.php 3箇所の json_encode()JSON_HEX_* オプション追加
EditController.php shippingDeliveryTimesjson_encode() に変更
ShippingController.php shippingDeliveryTimesjson_encode() に変更
OwnerStoreController.php requires をコントローラー側でJSON化

Test plan

  • EccubeExtensionTest: 5テスト成功
  • FileControllerTest: 42テスト成功
  • EditControllerTest: 18テスト成功

Related Issue

Fixes #6634

🤖 Generated with Claude Code

Summary by CodeRabbit

リリースノート

  • バグ修正
    • 管理画面の複数の機能でJSON出力のHTML特殊文字エスケープ処理を強化しました。
    • テンプレートエンジンに新しい安全なJSON エンコード機能を追加しました。
    • ファイル管理、注文管理、配送管理、プラグイン設定、商品詳細ページなどでセキュリティが向上します。

- テンプレートのHTMLコンテンツに|purifyフィルターを追加
- JSON出力にJSON_HEX_TAG等のセキュリティオプションを追加
- 安全なJSONエンコード用のjson_encode_safeフィルターを追加

修正対象:
- Product.description_detail, description_list
- News.description
- tradelaw.description, activeTradeLaw.description
- class_categories_as_json()
- FileController, EditController, ShippingController, OwnerStoreController

Refs EC-CUBE#6634

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@coderabbitai
Copy link

coderabbitai bot commented Feb 24, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 665d31f2-0590-40bc-aa7f-5d26ff6e17fe

📥 Commits

Reviewing files that changed from the base of the PR and between 4a79541 and 193a07f.

📒 Files selected for processing (1)
  • src/Eccube/Resource/template/default/Product/detail.twig

📝 Walkthrough

Walkthrough

複数のコントローラーとテンプレートファイルにおいて、JSON出力時のXSS脆弱性を修正しました。json_encode()呼び出しにJSON_HEX_*フラグを追加し、新規Twigフィルター「json_encode_safe」を導入することで、スクリプトコンテキストでのエスケープ処理を強化しました。

Changes

Cohort / File(s) Summary
コントローラーのJSON出力強化
src/Eccube/Controller/Admin/Content/FileController.php, src/Eccube/Controller/Admin/Order/EditController.php, src/Eccube/Controller/Admin/Order/ShippingController.php, src/Eccube/Controller/Admin/Store/OwnerStoreController.php
json_encode()呼び出しにJSON_HEX_TAG、JSON_HEX_AMP、JSON_HEX_APOS、JSON_HEX_QUOTフラグを追加し、JSON出力時のHTML特殊文字エスケープを実装。
Twig拡張機能の追加
src/Eccube/Twig/Extension/EccubeExtension.php
新規フィルター「json_encode_safe」を追加(getJsonEncodeSafe()メソッド)。getClassCategoriesAsJson()メソッドを更新し、JSON_HEX_*オプションでセキュアなJSON出力を実現。
テンプレートのフィルター更新
src/Eccube/Resource/template/admin/Store/plugin_confirm.twig, src/Eccube/Resource/template/default/Product/detail.twig
json_encode|rawをjson_encode_safeに置き換え、XSSに対応したJSON出力を実装。

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Suggested reviewers

  • ji-eunsoo
  • ttokoro20240902

Poem

🐰 JSONの穴をふさぎて、
セキュアに跳ねる、データたち
スクリプトの罠を避けながら、
安全な道を進みゆく
EC-CUBEの盾となりて 🛡️

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PRタイトルは「fix: XSS脆弱性の修正」で、プルリクエストの主要な変更内容(XSS脆弱性対応)を簡潔かつ明確に表現しており、JSONエンコーディングのセキュリティ強化という実装の中核をよく捉えている。
Linked Issues check ✅ Passed リンクされたIssue #6634の要件のうち、JSON出力のXSS対策(JSON_HEX_*オプションの追加)は完全に実装されているが、HTMLコンテンツのサニタイズ(|purify フィルター)の部分は除外されている。PR説明によりこれは意図的であり、別PR#6627で既に対応済みとのこと。
Out of Scope Changes check ✅ Passed すべての変更がJSON出力のセキュリティ強化に関連しており、スコープ外の変更は認められない。テンプレート|purify対応の除外も、PR説明で意図的な絞り込みとして明記されている。
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/Eccube/Controller/Admin/Store/OwnerStoreController.php (1)

246-256: ⚠️ Potential issue | 🟠 Major

requires をJSON文字列に変更すると plugin_confirm.twig のTwigiテレーション部分が壊れます

コントローラーが requires をJSON文字列として渡すようになったことで、plugin_confirm.twig には以下の問題が生じています:

1. requires|length が配列長ではなく文字列長を返す(Line 213)
Twigの length フィルターは文字列に対して mb_strlen() を呼ぶため、"[]" の長さは 2 です。2 > 0 が常に真となり、依存プラグインがない場合でも「必要プラグイン」カードが表示されてしまいます。

2. {% for plugin in requires %} が空ループになる(Line 219)
Twigの twig_ensure_traversable() は文字列を空配列 [] として扱うため、ループが一切実行されず依存プラグインの一覧が表示されません。

推奨修正:コントローラー側で PHP 配列のまま渡し、テンプレート側で本PRで追加された json_encode_safe フィルターを使用してください。

🔧 doConfirm の修正案
  return [
      'item' => $item,
-     'requires' => json_encode($requires, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT),
+     'requires' => $requires,
      'is_update' => false,
  ];
🔧 doUpdateConfirm の修正案
  return [
      'item' => $item,
-     'requires' => json_encode([], JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT),
+     'requires' => [],
      'is_update' => true,
      'Plugin' => $Plugin,
  ];

そして plugin_confirm.twig のLine 119 を以下のように変更してください:

- var requires = {{ requires|raw }};
+ var requires = {{ requires|json_encode_safe }};

Also applies to: 531-547

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/Eccube/Controller/Admin/Store/OwnerStoreController.php` around lines 246
- 256, The controller changed 'requires' to a JSON string which breaks Twig
iteration/length checks; revert the change in the doConfirm and doUpdateConfirm
handlers so they pass 'requires' as a PHP array (not json_encode'd) and ensure
templates use the new json_encode_safe filter when a JSON string is needed
(e.g., plugin_confirm.twig uses requires|json_encode_safe for inline JS) —
update the return payloads in the doConfirm and doUpdateConfirm methods to
return the raw $requires array and remove json_encode there so Twig's length and
for-loop behavior work correctly.
🧹 Nitpick comments (1)
src/Eccube/Resource/template/default/Shopping/index.twig (1)

397-397: |raw フィルターは冗長です。|purify のみで十分です

exercise/htmlpurifier-bundle 5.0 の purify フィルターは is_safe => ['html'] で登録されており、HTMLサニタイズ後の出力をTwigに対して安全なHTMLとして宣言します。Twigの raw フィルターは最後に適用される場合にのみ自動エスケープを無効化するため、後続の purify フィルターが存在する場合は機能しません。

{{ activeTradeLaw.description|purify }} に変更し、|raw を削除することで、より明確で冗長性のないコードになります。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/Eccube/Resource/template/default/Shopping/index.twig` at line 397, Remove
the redundant |raw filter and leave only the purify filter on the
activeTradeLaw.description output: replace the expression that applies both
|purify and |raw so it uses only {{ activeTradeLaw.description|purify }},
ensuring sanitization is applied and Twig sees the result as safe without the
unnecessary |raw call.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/Eccube/Controller/Admin/Store/OwnerStoreController.php`:
- Line 248: OwnerStoreController currently writes 'requires' =>
json_encode($requires, ... ) without handling json_encode() returning false;
update the code around the json_encode call in OwnerStoreController so you
either (a) use json_encode($requires,
JSON_HEX_TAG|JSON_HEX_AMP|JSON_HEX_APOS|JSON_HEX_QUOT|JSON_THROW_ON_ERROR)
inside a try/catch and log/fallback on exception, or (b) capture the result into
a variable (e.g. $requiresJson = json_encode(...);) and if $requiresJson ===
false set $requiresJson = '[]' (or safe JSON string) before assigning to the
template, ensuring the template always receives valid JSON for the requires
variable.

In `@src/Eccube/Resource/template/admin/Store/plugin_confirm.twig`:
- Around line 119-122: The Twig template treats requires as a PHP string
(pre-encoded JSON) which breaks the length check and for-loop; update
plugin_confirm.twig to decode the JSON before Twig-side operations by applying
Twig's JSON decode (e.g., use requires|json_decode or equivalent) wherever you
do requires|length and {% for plugin in requires %} so Twig sees an array, or
alternatively revert OwnerStoreController.php to pass a PHP array instead of a
JSON string and keep the current Twig iteration; ensure all references to
requires in the template (the length check and the for-loop that renders
dependency cards) reference the decoded/array form.

---

Outside diff comments:
In `@src/Eccube/Controller/Admin/Store/OwnerStoreController.php`:
- Around line 246-256: The controller changed 'requires' to a JSON string which
breaks Twig iteration/length checks; revert the change in the doConfirm and
doUpdateConfirm handlers so they pass 'requires' as a PHP array (not
json_encode'd) and ensure templates use the new json_encode_safe filter when a
JSON string is needed (e.g., plugin_confirm.twig uses requires|json_encode_safe
for inline JS) — update the return payloads in the doConfirm and doUpdateConfirm
methods to return the raw $requires array and remove json_encode there so Twig's
length and for-loop behavior work correctly.

---

Nitpick comments:
In `@src/Eccube/Resource/template/default/Shopping/index.twig`:
- Line 397: Remove the redundant |raw filter and leave only the purify filter on
the activeTradeLaw.description output: replace the expression that applies both
|purify and |raw so it uses only {{ activeTradeLaw.description|purify }},
ensuring sanitization is applied and Twig sees the result as safe without the
unnecessary |raw call.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5e99202 and 822fafa.

📒 Files selected for processing (12)
  • src/Eccube/Controller/Admin/Content/FileController.php
  • src/Eccube/Controller/Admin/Order/EditController.php
  • src/Eccube/Controller/Admin/Order/ShippingController.php
  • src/Eccube/Controller/Admin/Store/OwnerStoreController.php
  • src/Eccube/Resource/template/admin/Store/plugin_confirm.twig
  • src/Eccube/Resource/template/default/Block/news.twig
  • src/Eccube/Resource/template/default/Help/tradelaw.twig
  • src/Eccube/Resource/template/default/Product/detail.twig
  • src/Eccube/Resource/template/default/Product/list.twig
  • src/Eccube/Resource/template/default/Shopping/confirm.twig
  • src/Eccube/Resource/template/default/Shopping/index.twig
  • src/Eccube/Twig/Extension/EccubeExtension.php

return [
'item' => $item,
'requires' => $requires,
'requires' => json_encode($requires, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

json_encode の失敗を考慮していません(マイナー)

json_encode() は不正な UTF-8 などで false を返す可能性があります。その場合、テンプレートで var requires = false; と出力され、JavaScriptの .map() 呼び出しで TypeError が発生します。上記のコントローラー修正を採用する場合は不要ですが、現行コードを保持する場合は false チェックを追加することを検討してください。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/Eccube/Controller/Admin/Store/OwnerStoreController.php` at line 248,
OwnerStoreController currently writes 'requires' => json_encode($requires, ... )
without handling json_encode() returning false; update the code around the
json_encode call in OwnerStoreController so you either (a) use
json_encode($requires,
JSON_HEX_TAG|JSON_HEX_AMP|JSON_HEX_APOS|JSON_HEX_QUOT|JSON_THROW_ON_ERROR)
inside a try/catch and log/fallback on exception, or (b) capture the result into
a variable (e.g. $requiresJson = json_encode(...);) and if $requiresJson ===
false set $requiresJson = '[]' (or safe JSON string) before assigning to the
template, ensuring the template always receives valid JSON for the requires
variable.

- OwnerStoreController: requiresをPHP配列のまま渡すように修正
- plugin_confirm.twig: |raw を |json_encode_safe に変更

これによりTwig側の requires|length や {% for plugin in requires %}
が正しく配列として動作し、JavaScript出力も安全にエンコードされる

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@codecov
Copy link

codecov bot commented Feb 24, 2026

Codecov Report

❌ Patch coverage is 90.00000% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 79.33%. Comparing base (77c00e6) to head (bf1fd4c).
⚠️ Report is 1 commits behind head on 4.3.

Files with missing lines Patch % Lines
...be/Controller/Admin/Store/OwnerStoreController.php 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff            @@
##                4.3    #6635   +/-   ##
=========================================
  Coverage     79.33%   79.33%           
- Complexity     6638     6639    +1     
=========================================
  Files           475      475           
  Lines         26568    26571    +3     
=========================================
+ Hits          21078    21081    +3     
  Misses         5490     5490           
Flag Coverage Δ
Unit 79.33% <90.00%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@dotani1111 dotani1111 self-requested a review March 5, 2026 06:25
@dotani1111
Copy link
Contributor

@kurozumi
PRありがとうございます。

purifyに関しては、以下のPRで修正を行なっております。
JSON関連の修正のみにしていただけますか?
#6627

@dotani1111 のレビュー指摘に対応。
purify関連の修正は別PR EC-CUBE#6627 で対応されているため、
本PRからpurify関連の変更を削除しJSON関連の修正のみに限定。

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@kurozumi
Copy link
Contributor Author

kurozumi commented Mar 5, 2026

@dotani1111 ご指摘ありがとうございます。purify関連の変更を削除し、JSON関連の修正のみに限定しました。

@dotani1111
Copy link
Contributor

@kurozumi
ご対応ありがとうございます!
こちら動作確認を進めさせて頂きます。

@dotani1111 dotani1111 assigned dotani1111 and unassigned dotani1111 Mar 10, 2026
return [
'item' => $item,
'requires' => [],
'requires' => json_encode([], JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

こちらはテンプレート側でjson_encodeしているため、不要かと思われます。

src/Eccube/Resource/template/admin/Store/plugin_confirm.twig
119行目

var requires = {{ requires|json_encode_safe }};

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[セキュリティ] XSS脆弱性: 複数のテンプレートおよびコントローラーで不十分なエスケープ処理

2 participants