diff --git a/.sandstorm/changelog.md b/.sandstorm/changelog.md index 99ac9cb943..3e742969dd 100644 --- a/.sandstorm/changelog.md +++ b/.sandstorm/changelog.md @@ -1,3 +1,7 @@ +# 4.7.17.6 (API 0.9.2) + +- XSS issue in liability account redirect, found by [@0x2500](https://github.com/0x2500). + # 4.7.17.5 (API 0.9.2) - Several XSS issues, found by [@0x2500](https://github.com/0x2500). diff --git a/.sandstorm/sandstorm-pkgdef.capnp b/.sandstorm/sandstorm-pkgdef.capnp index eae7372e28..ee3ce6388e 100644 --- a/.sandstorm/sandstorm-pkgdef.capnp +++ b/.sandstorm/sandstorm-pkgdef.capnp @@ -15,8 +15,8 @@ const pkgdef :Spk.PackageDefinition = ( manifest = ( appTitle = (defaultText = "Firefly III"), - appVersion = 31, - appMarketingVersion = (defaultText = "4.7.17.5"), + appVersion = 32, + appMarketingVersion = (defaultText = "4.7.17.6"), actions = [ # Define your "new document" handlers here. diff --git a/app/Http/Controllers/Admin/LinkController.php b/app/Http/Controllers/Admin/LinkController.php index 73a23be304..4df4519bd8 100644 --- a/app/Http/Controllers/Admin/LinkController.php +++ b/app/Http/Controllers/Admin/LinkController.php @@ -91,7 +91,7 @@ class LinkController extends Controller public function delete(Request $request, LinkType $linkType) { if (!$linkType->editable) { - $request->session()->flash('error', (string)trans('firefly.cannot_edit_link_type', ['name' => $linkType->name])); + $request->session()->flash('error', (string)trans('firefly.cannot_edit_link_type', ['name' => e($linkType->name)])); return redirect(route('admin.links.index')); } @@ -148,7 +148,7 @@ class LinkController extends Controller public function edit(Request $request, LinkType $linkType) { if (!$linkType->editable) { - $request->session()->flash('error', (string)trans('firefly.cannot_edit_link_type', ['name' => $linkType->name])); + $request->session()->flash('error', (string)trans('firefly.cannot_edit_link_type', ['name' => e($linkType->name)])); return redirect(route('admin.links.index')); } @@ -247,7 +247,7 @@ class LinkController extends Controller public function update(LinkTypeFormRequest $request, LinkType $linkType) { if (!$linkType->editable) { - $request->session()->flash('error', (string)trans('firefly.cannot_edit_link_type', ['name' => $linkType->name])); + $request->session()->flash('error', (string)trans('firefly.cannot_edit_link_type', ['name' => e($linkType->name)])); return redirect(route('admin.links.index')); } diff --git a/app/Http/Controllers/CurrencyController.php b/app/Http/Controllers/CurrencyController.php index 8bde0b15aa..6aa462e6be 100644 --- a/app/Http/Controllers/CurrencyController.php +++ b/app/Http/Controllers/CurrencyController.php @@ -78,7 +78,7 @@ class CurrencyController extends Controller /** @var User $user */ $user = auth()->user(); if (!$this->userRepository->hasRole($user, 'owner')) { - $request->session()->flash('error', (string)trans('firefly.ask_site_owner', ['owner' => config('firefly.site_owner')])); + $request->session()->flash('error', (string)trans('firefly.ask_site_owner', ['owner' => e(config('firefly.site_owner'))])); return redirect(route('currencies.index')); } @@ -132,7 +132,7 @@ class CurrencyController extends Controller $user = auth()->user(); if (!$this->userRepository->hasRole($user, 'owner')) { // @codeCoverageIgnoreStart - $request->session()->flash('error', (string)trans('firefly.ask_site_owner', ['owner' => config('firefly.site_owner')])); + $request->session()->flash('error', (string)trans('firefly.ask_site_owner', ['owner' => e(config('firefly.site_owner'))])); Log::channel('audit')->info(sprintf('Tried to visit page to delete currency %s but is not site owner.', $currency->code)); return redirect(route('currencies.index')); @@ -140,7 +140,7 @@ class CurrencyController extends Controller } if ($this->repository->currencyInUse($currency)) { - $request->session()->flash('error', (string)trans('firefly.cannot_delete_currency', ['name' => $currency->name])); + $request->session()->flash('error', (string)trans('firefly.cannot_delete_currency', ['name' => e($currency->name)])); Log::channel('audit')->info(sprintf('Tried to visit page to delete currency %s but currency is in use.', $currency->code)); return redirect(route('currencies.index')); @@ -168,7 +168,7 @@ class CurrencyController extends Controller $user = auth()->user(); if (!$this->userRepository->hasRole($user, 'owner')) { // @codeCoverageIgnoreStart - $request->session()->flash('error', (string)trans('firefly.ask_site_owner', ['owner' => config('firefly.site_owner')])); + $request->session()->flash('error', (string)trans('firefly.ask_site_owner', ['owner' => e(config('firefly.site_owner'))])); Log::channel('audit')->info(sprintf('Tried to delete currency %s but is not site owner.', $currency->code)); return redirect(route('currencies.index')); @@ -176,7 +176,7 @@ class CurrencyController extends Controller } if ($this->repository->currencyInUse($currency)) { - $request->session()->flash('error', (string)trans('firefly.cannot_delete_currency', ['name' => $currency->name])); + $request->session()->flash('error', (string)trans('firefly.cannot_delete_currency', ['name' => e($currency->name)])); Log::channel('audit')->info(sprintf('Tried to delete currency %s but is in use.', $currency->code)); return redirect(route('currencies.index')); @@ -204,7 +204,7 @@ class CurrencyController extends Controller $user = auth()->user(); if (!$this->userRepository->hasRole($user, 'owner')) { // @codeCoverageIgnoreStart - $request->session()->flash('error', (string)trans('firefly.ask_site_owner', ['owner' => config('firefly.site_owner')])); + $request->session()->flash('error', (string)trans('firefly.ask_site_owner', ['owner' => e(config('firefly.site_owner'))])); Log::channel('audit')->info(sprintf('Tried to disable currency %s but is not site owner.', $currency->code)); return redirect(route('currencies.index')); @@ -212,7 +212,7 @@ class CurrencyController extends Controller } if ($this->repository->currencyInUse($currency)) { - $request->session()->flash('error', (string)trans('firefly.cannot_disable_currency', ['name' => $currency->name])); + $request->session()->flash('error', (string)trans('firefly.cannot_disable_currency', ['name' => e($currency->name)])); Log::channel('audit')->info(sprintf('Tried to disable currency %s but is in use.', $currency->code)); return redirect(route('currencies.index')); @@ -252,7 +252,7 @@ class CurrencyController extends Controller $user = auth()->user(); if (!$this->userRepository->hasRole($user, 'owner')) { // @codeCoverageIgnoreStart - $request->session()->flash('error', (string)trans('firefly.ask_site_owner', ['owner' => config('firefly.site_owner')])); + $request->session()->flash('error', (string)trans('firefly.ask_site_owner', ['owner' => e(config('firefly.site_owner'))])); Log::channel('audit')->info(sprintf('Tried to edit currency %s but is not owner.', $currency->code)); return redirect(route('currencies.index')); @@ -393,7 +393,7 @@ class CurrencyController extends Controller } if (!$this->userRepository->hasRole($user, 'owner')) { // @codeCoverageIgnoreStart - $request->session()->flash('error', (string)trans('firefly.ask_site_owner', ['owner' => config('firefly.site_owner')])); + $request->session()->flash('error', (string)trans('firefly.ask_site_owner', ['owner' => e(config('firefly.site_owner'))])); Log::channel('audit')->info('Tried to update (POST) currency without admin rights.', $data); return redirect(route('currencies.index')); diff --git a/app/Http/Controllers/Import/JobConfigurationController.php b/app/Http/Controllers/Import/JobConfigurationController.php index b8eefc8e17..dac7b2136f 100644 --- a/app/Http/Controllers/Import/JobConfigurationController.php +++ b/app/Http/Controllers/Import/JobConfigurationController.php @@ -77,7 +77,7 @@ class JobConfigurationController extends Controller $allowed = ['has_prereq', 'need_job_config']; if (null !== $importJob && !in_array($importJob->status, $allowed, true)) { Log::error(sprintf('Job has state "%s", but we only accept %s', $importJob->status, json_encode($allowed))); - session()->flash('error', (string)trans('import.bad_job_status', ['status' => $importJob->status])); + session()->flash('error', (string)trans('import.bad_job_status', ['status' => e($importJob->status)])); return redirect(route('import.index')); } @@ -127,7 +127,7 @@ class JobConfigurationController extends Controller // catch impossible status: $allowed = ['has_prereq', 'need_job_config']; if (null !== $importJob && !in_array($importJob->status, $allowed, true)) { - session()->flash('error', (string)trans('import.bad_job_status', ['status' => $importJob->status])); + session()->flash('error', (string)trans('import.bad_job_status', ['status' => e($importJob->status)])); return redirect(route('import.index')); } diff --git a/app/Http/Controllers/Import/PrerequisitesController.php b/app/Http/Controllers/Import/PrerequisitesController.php index 9bbcac7a0c..7a08d0519b 100644 --- a/app/Http/Controllers/Import/PrerequisitesController.php +++ b/app/Http/Controllers/Import/PrerequisitesController.php @@ -76,7 +76,7 @@ class PrerequisitesController extends Controller $allowed = ['new']; if (null !== $importJob && !in_array($importJob->status, $allowed, true)) { Log::error(sprintf('Job has state "%s" but this Prerequisites::index() only accepts %s', $importJob->status, json_encode($allowed))); - session()->flash('error', (string)trans('import.bad_job_status', ['status' => $importJob->status])); + session()->flash('error', (string)trans('import.bad_job_status', ['status' => e($importJob->status)])); return redirect(route('import.index')); } @@ -129,7 +129,7 @@ class PrerequisitesController extends Controller $allowed = ['new']; if (null !== $importJob && !in_array($importJob->status, $allowed, true)) { Log::error(sprintf('Job has state "%s" but this Prerequisites::post() only accepts %s', $importJob->status, json_encode($allowed))); - session()->flash('error', (string)trans('import.bad_job_status', ['status' => $importJob->status])); + session()->flash('error', (string)trans('import.bad_job_status', ['status' => e($importJob->status)])); return redirect(route('import.index')); } @@ -148,7 +148,7 @@ class PrerequisitesController extends Controller Log::debug(sprintf('Result of storePrerequisites has message count: %d', $result->count())); if ($result->count() > 0) { - $request->session()->flash('error', $result->first()); + $request->session()->flash('error', e($result->first())); // redirect back to job, if has job: return redirect(route('import.prerequisites.index', [$importProvider, $importJob->key ?? '']))->withInput(); diff --git a/app/Http/Controllers/PiggyBankController.php b/app/Http/Controllers/PiggyBankController.php index 618cd3c14e..4f51a874d9 100644 --- a/app/Http/Controllers/PiggyBankController.php +++ b/app/Http/Controllers/PiggyBankController.php @@ -321,7 +321,7 @@ class PiggyBankController extends Controller 'error', (string)trans( 'firefly.cannot_add_amount_piggy', - ['amount' => app('amount')->formatAnything($currency, $amount, false), 'name' => $piggyBank->name] + ['amount' => app('amount')->formatAnything($currency, $amount, false), 'name' => e($piggyBank->name)] ) ); @@ -364,7 +364,7 @@ class PiggyBankController extends Controller 'error', (string)trans( 'firefly.cannot_remove_from_piggy', - ['amount' => app('amount')->formatAnything($currency, $amount, false), 'name' => $piggyBank->name] + ['amount' => app('amount')->formatAnything($currency, $amount, false), 'name' => e($piggyBank->name)] ) ); diff --git a/app/Http/Controllers/ProfileController.php b/app/Http/Controllers/ProfileController.php index 282e0cebd0..88a1dc6269 100644 --- a/app/Http/Controllers/ProfileController.php +++ b/app/Http/Controllers/ProfileController.php @@ -90,7 +90,7 @@ class ProfileController extends Controller $loginProvider = config('firefly.login_provider'); if ('eloquent' !== $loginProvider) { // @codeCoverageIgnoreStart - $request->session()->flash('error', trans('firefly.login_provider_local_only', ['login_provider' => $loginProvider])); + $request->session()->flash('error', trans('firefly.login_provider_local_only', ['login_provider' => e($loginProvider)])); return redirect(route('profile.index')); // @codeCoverageIgnoreEnd @@ -116,7 +116,7 @@ class ProfileController extends Controller $loginProvider = config('firefly.login_provider'); if ('eloquent' !== $loginProvider) { // @codeCoverageIgnoreStart - $request->session()->flash('error', trans('firefly.login_provider_local_only', ['login_provider' => $loginProvider])); + $request->session()->flash('error', trans('firefly.login_provider_local_only', ['login_provider' => e($loginProvider)])); return redirect(route('profile.index')); // @codeCoverageIgnoreEnd @@ -201,7 +201,7 @@ class ProfileController extends Controller $loginProvider = config('firefly.login_provider'); if ('eloquent' !== $loginProvider) { // @codeCoverageIgnoreStart - $request->session()->flash('warning', trans('firefly.delete_local_info_only', ['login_provider' => $loginProvider])); + $request->session()->flash('warning', trans('firefly.delete_local_info_only', ['login_provider' => e($loginProvider)])); // @codeCoverageIgnoreEnd } $title = auth()->user()->email; @@ -297,7 +297,7 @@ class ProfileController extends Controller $loginProvider = config('firefly.login_provider'); if ('eloquent' !== $loginProvider) { // @codeCoverageIgnoreStart - $request->session()->flash('error', trans('firefly.login_provider_local_only', ['login_provider' => $loginProvider])); + $request->session()->flash('error', trans('firefly.login_provider_local_only', ['login_provider' => e($loginProvider)])); return redirect(route('profile.index')); // @codeCoverageIgnoreEnd @@ -351,7 +351,7 @@ class ProfileController extends Controller $loginProvider = config('firefly.login_provider'); if ('eloquent' !== $loginProvider) { // @codeCoverageIgnoreStart - $request->session()->flash('error', trans('firefly.login_provider_local_only', ['login_provider' => $loginProvider])); + $request->session()->flash('error', trans('firefly.login_provider_local_only', ['login_provider' => e($loginProvider)])); return redirect(route('profile.index')); // @codeCoverageIgnoreEnd diff --git a/app/Support/Http/Controllers/UserNavigation.php b/app/Support/Http/Controllers/UserNavigation.php index 2127771398..2f47b872ed 100644 --- a/app/Support/Http/Controllers/UserNavigation.php +++ b/app/Support/Http/Controllers/UserNavigation.php @@ -130,7 +130,7 @@ trait UserNavigation /** @var Transaction $transaction */ $transaction = $account->transactions()->first(); if (null === $transaction) { - app('session')->flash('error', trans('firefly.account_missing_transaction', ['name' => $account->name, 'id' => $account->id])); + app('session')->flash('error', trans('firefly.account_missing_transaction', ['name' => e($account->name), 'id' => $account->id])); Log::error(sprintf('Expected a transaction. Account #%d has none. BEEP, error.', $account->id)); return redirect(route('index')); @@ -141,7 +141,7 @@ trait UserNavigation $opposingTransaction = $journal->transactions()->where('transactions.id', '!=', $transaction->id)->first(); if (null === $opposingTransaction) { - app('session')->flash('error', trans('firefly.account_missing_transaction', ['name' => $account->name, 'id' => $account->id])); + app('session')->flash('error', trans('firefly.account_missing_transaction', ['name' => e($account->name), 'id' => $account->id])); Log::error(sprintf('Expected an opposing transaction. Account #%d has none. BEEP, error.', $account->id)); } diff --git a/changelog.md b/changelog.md index 01b7c9a969..47c7f4f1c3 100644 --- a/changelog.md +++ b/changelog.md @@ -2,6 +2,11 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +## [4.7.17.6 (API 0.9.2)] - 2019-08-02 + +### Security +- XSS issue in liability account redirect, found by [@0x2500](https://github.com/0x2500). + ## [4.7.17.5 (API 0.9.2)] - 2019-08-02 ### Security diff --git a/resources/views/v1/form/assetAccountCheckList.twig b/resources/views/v1/form/assetAccountCheckList.twig index 129dc11356..d47ea5d1e3 100644 --- a/resources/views/v1/form/assetAccountCheckList.twig +++ b/resources/views/v1/form/assetAccountCheckList.twig @@ -12,7 +12,7 @@ {% else %} {{ Form.checkbox(name~'[]', id, false, options) }} {% endif %} - {{ account }} + {{ account|escape }} {% endfor %} diff --git a/resources/views/v1/import/bunq/choose-accounts.twig b/resources/views/v1/import/bunq/choose-accounts.twig index 4d5f395f30..b43e6f3d48 100644 --- a/resources/views/v1/import/bunq/choose-accounts.twig +++ b/resources/views/v1/import/bunq/choose-accounts.twig @@ -64,7 +64,7 @@ {% endif %} {% endfor %} {% if account.status != 'ACTIVE' %} -