CVE-2019-14667: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79)
value: Firefly III 4.7.17.4 is vulnerable to multiple stored XSS issues due to the lack of filtration of user-supplied data in the transaction description field and the asset account name. The JavaScript code is executed during a convert transaction action.
CWE description: The product does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.
CVSS v3 base score: 6.1
Published: 2019-08-05T20:15Z
Repository: https://github.com/firefly-iii/firefly-iii
Language: Other
Files changed: resources/views/v1/transactions/convert.twig
Commit date: 2019-08-02 16:42:16 +0200
Commit message: Fix #2363

Diff: diff --git a/resources/views/v1/transactions/convert.twig b/resources/views/v1/transactions/convert.twig
index ff71b59d6..051f843a4 100644
--- a/resources/views/v1/transactions/convert.twig
+++ b/resources/views/v1/transactions/convert.twig
@@ -20,71 +20,71 @@
                         {{ ExpandedForm.staticText('description', '<a href="'~route('transactions.show', journal.id)~'">'~journal.description~'</a>') }}
                         {{ ExpandedForm.staticText('date', journal.date.formatLocalized(monthAndDayFormat)) }}
 
                         {# in case of withdrawal #}
                         {% if sourceType.type == "Withdrawal" %}
-                            {{ ExpandedForm.staticText('source_account_asset', '<a href="'~route('accounts.show',[sourceAccount.id])~'">'~sourceAccount.name~'</a>') }}
+                            {{ ExpandedForm.staticText('source_account_asset', '<a href="'~route('accounts.show',[sourceAccount.id])~'">'~sourceAccount.name|escape~'</a>') }}
                             {# if destination is cash, show (cash) #}
                             {% if destinationAccount.accountType.type == "Cash account" %}
                                 {{ ExpandedForm.staticText('destination_account_expense', '<span class="text-success">(cash)</a>') }}
                             {% else %}
-                                {{ ExpandedForm.staticText('destination_account_expense', '<a href="'~route('accounts.show',[destinationAccount.id])~'">'~destinationAccount.name~'</a>') }}
+                                {{ ExpandedForm.staticText('destination_account_expense', '<a href="'~route('accounts.show',[destinationAccount.id])~'">'~destinationAccount.name|escape~'</a>') }}
                             {% endif %}
 
                         {% endif %}
 
                         {# in case of deposit #}
                         {% if sourceType.type == "Deposit" %}
                             {# if source is cash, show (cash) #}
                             {% if sourceAccount.accountType.type == "Cash account" %}
                                 {{ ExpandedForm.staticText('source_account_revenue', '<span class="text-success">(cash)</a>') }}
                             {% else %}
-                                {{ ExpandedForm.staticText('source_account_revenue', '<a href="'~route('accounts.show',[sourceAccount.id])~'">'~sourceAccount.name~'</a>') }}
+                                {{ ExpandedForm.staticText('source_account_revenue', '<a href="'~route('accounts.show',[sourceAccount.id])~'">'~sourceAccount.name|escape~'</a>') }}
                             {% endif %}
-                            {{ ExpandedForm.staticText('destination_account_asset', '<a href="'~route('accounts.show',[destinationAccount.id])~'">'~destinationAccount.name~'</a>') }}
+                            {{ ExpandedForm.staticText('destination_account_asset', '<a href="'~route('accounts.show',[destinationAccount.id])~'">'~destinationAccount.name|escape~'</a>') }}
                         {% endif %}
 
                         {# in case of transfer #}
                         {% if sourceType.type == "Transfer" %}
-                            {{ ExpandedForm.staticText('source_account_asset', '<a href="'~route('accounts.show',[sourceAccount.id])~'">'~sourceAccount.name~'</a>') }}
-                            {{ ExpandedForm.staticText('destination_account_asset', '<a href="'~route('accounts.show',[destinationAccount.id])~'">'~destinationAccount.name~'</a>') }}
+                            {{ ExpandedForm.staticText('source_account_asset', '<a href="'~route('accounts.show',[sourceAccount.id])~'">'~sourceAccount.name|escape~'</a>') }}
+                            {{ ExpandedForm.staticText('destination_account_asset', '<a href="'~route('accounts.show',[destinationAccount.id])~'">'~destinationAccount.name|escape~'</a>') }}
                         {% endif %}
 
                         {# ONE #}
                         {% if sourceType.type == 'Withdrawal' and destinationType.type == 'Deposit' %}
                             <p><em>
                                     {{ trans('firefly.convert_explanation_withdrawal_deposit',
                                         {
                                             amount: positiveAmount|formatAmount,
                                             sourceRoute: route('accounts.show', [sourceAccount.id]),
-                                            sourceName: sourceAccount.name,
+                                            sourceName: sourceAccount.name|escape,
                                             destinationRoute: route('accounts.show', [destinationAccount.id]),
-                                            destinationName: destinationAccount.name,
+                                            destinationName: destinationAccount.name|escape,
                                         })|raw }}
                                 </em>
                             </p>
                             <p><em>
                                     {{ 'convert_please_set_revenue_source'|_ }}
                                 </em>
                             </p>
                             {% if destinationAccount.accountType.type == "Cash account" %}
                                 {{ ExpandedForm.text('source_account_revenue', '') }}
                             {% else %}
-                                {{ ExpandedForm.text('source_account_revenue', destinationAccount.name) }}
+                                {{ ExpandedForm.text('source_account_revenue', destinationAccount.name|escape) }}
                             {% endif %}
                         {% endif %}
 
                         {# TWO #}
                         {% if sourceType.type == 'Withdrawal' and destinationType.type == 'Transfer' %}
                             <p><em>
                                     {{ trans('firefly.convert_explanation_withdrawal_transfer',
                                         {
                                             amount: positiveAmount|formatAmount,
                                             sourceRoute: route('accounts.show', [sourceAccount.id]),
-                                            sourceName: sourceAccount.name,
+                                            sourceName: sourceAccount.name|escape,
                                             destinationRoute: route('accounts.show', [destinationAccount.id]),
-                                            destinationName: destinationAccount.name,
+                                            destinationName: destinationAccount.name|escape,
                                         })|raw }}
                                 </em></p>
 
                             <p>
                                 <em>
@@ -102,13 +102,13 @@
                                 <em>
                                     {{ trans('firefly.convert_explanation_deposit_withdrawal',
                                         {
                                             amount: positiveAmount|formatAmount,
                                             sourceRoute: route('accounts.show', [sourceAccount.id]),
-                                            sourceName: sourceAccount.name,
+                                            sourceName: sourceAccount.name|escape,
                                             destinationRoute: route('accounts.show', [destinationAccount.id]),
-                                            destinationName: destinationAccount.name,
+                                            destinationName: destinationAccount.name|escape,
                                         })|raw }}
                                 </em>
                             </p>
                             <p>
                                 <em>
@@ -117,11 +117,11 @@
                                 </em>
                             </p>
                             {% if sourceAccount.accountType.type == "Cash account" %}
                                 {{ ExpandedForm.text('destination_account_expense', '') }}
                             {% else %}
-                                {{ ExpandedForm.text('destination_account_expense', destinationAccount.name) }}
+                                {{ ExpandedForm.text('destination_account_expense', destinationAccount.name|escape) }}
                             {% endif %}
 
                         {% endif %}
 
                         {# FOUR #}
@@ -131,13 +131,13 @@
                                 <em>
                                     {{ trans('firefly.convert_explanation_deposit_transfer',
                                         {
                                             amount: positiveAmount|formatAmount,
                                             sourceRoute: route('accounts.show', [sourceAccount.id]),
-                                            sourceName: sourceAccount.name,
+                                            sourceName: sourceAccount.name|escape,
                                             destinationRoute: route('accounts.show', [destinationAccount.id]),
-                                            destinationName: destinationAccount.name,
+                                            destinationName: destinationAccount.name|escape,
                                         })|raw }}
                                 </em>
                             </p>
                             <p>
                                 <em>
@@ -155,24 +155,24 @@
                                 <em>
                                     {{ trans('firefly.convert_explanation_transfer_withdrawal',
                                         {
                                             amount: positiveAmount|formatAmount,
                                             sourceRoute: route('accounts.show', [sourceAccount.id]),
-                                            sourceName: sourceAccount.name,
+                                            sourceName: sourceAccount.name|escape,
                                             destinationRoute: route('accounts.show', [destinationAccount.id]),
-                                            destinationName: destinationAccount.name,
+                                            destinationName: destinationAccount.name|escape,
                                         })|raw }}
                                 </em>
                             </p>
 
                             <p>
                                 <em>
                                     {{ 'convert_please_set_expense_destination'|_ }}
                                 </em>
                             </p>
 
-                            {{ ExpandedForm.text('destination_account_expense', destinationAccount.name) }}
+                            {{ ExpandedForm.text('destination_account_expense', destinationAccount.name|escape) }}
 
                         {% endif %}
 
                         {# SIX #}
                         {% if sourceType.type == 'Transfer' and destinationType.type == 'Deposit' %}
@@ -182,24 +182,24 @@
                                 <em>
                                     {{ trans('firefly.convert_explanation_transfer_deposit',
                                         {
                                             amount: positiveAmount|formatAmount,
                                             sourceRoute: route('accounts.show', [sourceAccount.id]),
-                                            sourceName: sourceAccount.name,
+                                            sourceName: sourceAccount.name|escape,
                                             destinationRoute: route('accounts.show', [destinationAccount.id]),
-                                            destinationName: destinationAccount.name,
+                                            destinationName: destinationAccount.name|escape,
                                         })|raw }}
                                 </em>
                             </p>
 
                             <p>
                                 <em>
                                     {{ 'convert_please_set_revenue_source'|_ }}
                                 </em>
                             </p>
 
-                            {{ ExpandedForm.text('source_account_revenue', sourceAccount.name) }}
+                            {{ ExpandedForm.text('source_account_revenue', sourceAccount.name|escape) }}
 
                         {% endif %}
 
                     </div>
                     <div class="box-footer">

Vulnerable code:                             {{ ExpandedForm.staticText('source_account_asset', '<a href="'~route('accounts.show',[sourceAccount.id])~'">'~sourceAccount.name~'</a>') }}
                                {{ ExpandedForm.staticText('destination_account_expense', '<a href="'~route('accounts.show',[destinationAccount.id])~'">'~destinationAccount.name~'</a>') }}
                                {{ ExpandedForm.staticText('source_account_revenue', '<a href="'~route('accounts.show',[sourceAccount.id])~'">'~sourceAccount.name~'</a>') }}
                            {{ ExpandedForm.staticText('destination_account_asset', '<a href="'~route('accounts.show',[destinationAccount.id])~'">'~destinationAccount.name~'</a>') }}
                            {{ ExpandedForm.staticText('source_account_asset', '<a href="'~route('accounts.show',[sourceAccount.id])~'">'~sourceAccount.name~'</a>') }}
                            {{ ExpandedForm.staticText('destination_account_asset', '<a href="'~route('accounts.show',[destinationAccount.id])~'">'~destinationAccount.name~'</a>') }}
                                            sourceName: sourceAccount.name,
                                            destinationName: destinationAccount.name,
                                {{ ExpandedForm.text('source_account_revenue', destinationAccount.name) }}
                                            sourceName: sourceAccount.name,
                                            destinationName: destinationAccount.name,
                                            sourceName: sourceAccount.name,
                                            destinationName: destinationAccount.name,
                                {{ ExpandedForm.text('destination_account_expense', destinationAccount.name) }}
                                            sourceName: sourceAccount.name,
                                            destinationName: destinationAccount.name,
                                            sourceName: sourceAccount.name,
                                            destinationName: destinationAccount.name,
                            {{ ExpandedForm.text('destination_account_expense', destinationAccount.name) }}
                                            sourceName: sourceAccount.name,
                                            destinationName: destinationAccount.name,
                            {{ ExpandedForm.text('source_account_revenue', sourceAccount.name) }}
Fixed code:                             {{ ExpandedForm.staticText('source_account_asset', '<a href="'~route('accounts.show',[sourceAccount.id])~'">'~sourceAccount.name|escape~'</a>') }}
                                {{ ExpandedForm.staticText('destination_account_expense', '<a href="'~route('accounts.show',[destinationAccount.id])~'">'~destinationAccount.name|escape~'</a>') }}
                                {{ ExpandedForm.staticText('source_account_revenue', '<a href="'~route('accounts.show',[sourceAccount.id])~'">'~sourceAccount.name|escape~'</a>') }}
                            {{ ExpandedForm.staticText('destination_account_asset', '<a href="'~route('accounts.show',[destinationAccount.id])~'">'~destinationAccount.name|escape~'</a>') }}
                            {{ ExpandedForm.staticText('source_account_asset', '<a href="'~route('accounts.show',[sourceAccount.id])~'">'~sourceAccount.name|escape~'</a>') }}
                            {{ ExpandedForm.staticText('destination_account_asset', '<a href="'~route('accounts.show',[destinationAccount.id])~'">'~destinationAccount.name|escape~'</a>') }}
                                            sourceName: sourceAccount.name|escape,
                                            destinationName: destinationAccount.name|escape,
                                {{ ExpandedForm.text('source_account_revenue', destinationAccount.name|escape) }}
                                            sourceName: sourceAccount.name|escape,
                                            destinationName: destinationAccount.name|escape,
                                            sourceName: sourceAccount.name|escape,
                                            destinationName: destinationAccount.name|escape,
                                {{ ExpandedForm.text('destination_account_expense', destinationAccount.name|escape) }}
                                            sourceName: sourceAccount.name|escape,
                                            destinationName: destinationAccount.name|escape,
                                            sourceName: sourceAccount.name|escape,
                                            destinationName: destinationAccount.name|escape,
                            {{ ExpandedForm.text('destination_account_expense', destinationAccount.name|escape) }}
                                            sourceName: sourceAccount.name|escape,
                                            destinationName: destinationAccount.name|escape,
                            {{ ExpandedForm.text('source_account_revenue', sourceAccount.name|escape) }}