CVE-2023-50924: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79)
value: Englesystem is a shift planning system for chaos events. Engelsystem prior to v3.4.1 performed insufficient validation of user supplied data for the DECT number, mobile number, and work-log comment fields. The values of those fields would be displayed in corresponding log overviews, allowing the injection and execution of Javascript code in another user's context. This vulnerability enables an authenticated user to inject Javascript into other user's sessions. The injected JS will be executed during normal usage of the system when viewing, e.g., overview pages. This issue has been fixed in version 3.4.1.
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: 5.4
Published: 2023-12-22T21:15Z
Repository: https://github.com/engelsystem/engelsystem
Language: PHP
Files changed: includes/controller/angeltypes_controller.php, includes/controller/rooms_controller.php, includes/controller/shifts_controller.php, includes/controller/shifttypes_controller.php, includes/controller/user_angeltypes_controller.php, includes/controller/users_controller.php, includes/engelsystem.php, includes/helper/message_helper.php, includes/pages/admin_free.php, includes/pages/admin_groups.php, includes/pages/admin_shifts.php, includes/pages/admin_user.php, includes/pages/guest_login.php, includes/pages/user_shifts.php, includes/sys_form.php, includes/sys_menu.php, includes/sys_page.php, includes/sys_template.php, includes/view/AngelTypes_view.php, includes/view/PublicDashboard_view.php, includes/view/Rooms_view.php, includes/view/ShiftCalendarShiftRenderer.php, includes/view/ShiftEntry_view.php, includes/view/ShiftTypes_view.php, includes/view/Shifts_view.php, includes/view/UserAngelTypes_view.php, includes/view/UserHintsRenderer.php, includes/view/User_view.php, resources/views/emails/angeltype-added.twig, resources/views/emails/angeltype-confirmed.twig, resources/views/pages/login.twig
Commit date: 2023-12-06 18:18:05 +0100
Commit message: Escape text outputs in includes

Diff: diff --git a/includes/controller/angeltypes_controller.php b/includes/controller/angeltypes_controller.php
index 3d820446a..eced5a460 100644
--- a/includes/controller/angeltypes_controller.php
+++ b/includes/controller/angeltypes_controller.php
@@ -70,11 +70,11 @@ function angeltype_delete_controller()
         success(sprintf(__('Angeltype %s deleted.'), $angeltype->name));
         throw_redirect(page_link_to('angeltypes'));
     }
 
     return [
-        sprintf(__('Delete angeltype %s'), $angeltype->name),
+        sprintf(__('Delete angeltype %s'), htmlspecialchars($angeltype->name)),
         AngelType_delete_view($angeltype),
     ];
 }
 
 /**
@@ -150,11 +150,11 @@ function angeltype_edit_controller()
             throw_redirect(angeltype_link($angeltype->id));
         }
     }
 
     return [
-        sprintf(__('Edit %s'), $angeltype->name),
+        sprintf(__('Edit %s'), htmlspecialchars((string) $angeltype->name)),
         AngelType_edit_view($angeltype, $supporter_mode),
     ];
 }
 
 /**
@@ -191,11 +191,11 @@ function angeltype_controller()
         $tab = 1;
     }
 
     $isSupporter = !is_null($user_angeltype) && $user_angeltype->supporter;
     return [
-        sprintf(__('Team %s'), $angeltype->name),
+        sprintf(__('Team %s'), htmlspecialchars($angeltype->name)),
         AngelType_view(
             $angeltype,
             $members,
             $user_angeltype,
             auth()->can('admin_user_angeltypes') || $isSupporter,
@@ -321,11 +321,11 @@ function angeltypes_list_controller()
         $angeltype->no_self_signup_allowed = $angeltype->no_self_signup ? '' : icon('pencil-square');
 
         $angeltype->name = '<a href="'
             . page_link_to('angeltypes', ['action' => 'view', 'angeltype_id' => $angeltype->id])
             . '">'
-            . $angeltype->name
+            . htmlspecialchars($angeltype->name)
             . '</a>';
 
         $angeltype->actions = table_buttons($actions);
     }
 
diff --git a/includes/controller/rooms_controller.php b/includes/controller/rooms_controller.php
index 2136565ab..5fdca4a34 100644
--- a/includes/controller/rooms_controller.php
+++ b/includes/controller/rooms_controller.php
@@ -51,11 +51,11 @@ function room_controller(): array
     $shiftsFilterRenderer->enableDaySelection($days);
 
     $shiftCalendarRenderer = shiftCalendarRendererByShiftFilter($shiftsFilter);
 
     return [
-        $room->name,
+        htmlspecialchars($room->name),
         Room_view($room, $shiftsFilterRenderer, $shiftCalendarRenderer),
     ];
 }
 
 /**
diff --git a/includes/controller/shifts_controller.php b/includes/controller/shifts_controller.php
index fe3b8939b..99bf0e53b 100644
--- a/includes/controller/shifts_controller.php
+++ b/includes/controller/shifts_controller.php
@@ -192,11 +192,11 @@ function shift_edit_controller()
 
     $angel_types_spinner = '';
     foreach ($angeltypes as $angeltype_id => $angeltype_name) {
         $angel_types_spinner .= form_spinner(
             'angeltype_count_' . $angeltype_id,
-            $angeltype_name,
+            htmlspecialchars($angeltype_name),
             $needed_angel_types[$angeltype_id]
         );
     }
 
     return page_with_title(
@@ -211,11 +211,14 @@ function shift_edit_controller()
                 form_text('title', __('Title'), $title),
                 form_select('rid', __('Room:'), $rooms, $rid),
                 form_text('start', __('Start:'), $start->format('Y-m-d H:i')),
                 form_text('end', __('End:'), $end->format('Y-m-d H:i')),
                 form_textarea('description', __('Additional description'), $description),
-                form_info('', __('This description is for single shifts, otherwise please use the description in shift type.')),
+                form_info(
+                    '',
+                    __('This description is for single shifts, otherwise please use the description in shift type.')
+                ),
                 '<h2>' . __('Needed angels') . '</h2>',
                 $angel_types_spinner,
                 form_submit('submit', __('Save')),
             ]),
         ]
@@ -336,11 +339,11 @@ function shift_controller()
         $shift_signup_state->combineWith($angeltype_signup_state);
         $angeltype->shift_signup_state = $angeltype_signup_state;
     }
 
     return [
-        $shift->shiftType->name,
+        htmlspecialchars($shift->shiftType->name),
         Shift_view($shift, $shifttype, $room, $angeltypes, $shift_signup_state),
     ];
 }
 
 /**
diff --git a/includes/controller/shifttypes_controller.php b/includes/controller/shifttypes_controller.php
index 0f1cdfe46..efd11988a 100644
--- a/includes/controller/shifttypes_controller.php
+++ b/includes/controller/shifttypes_controller.php
@@ -31,11 +31,11 @@ function shifttype_delete_controller()
         $shifttype->delete();
         throw_redirect(page_link_to('shifttypes'));
     }
 
     return [
-        sprintf(__('Delete shifttype %s'), $shifttype->name),
+        sprintf(__('Delete shifttype %s'), htmlspecialchars($shifttype->name)),
         ShiftType_delete_view($shifttype),
     ];
 }
 
 /**
@@ -108,11 +108,11 @@ function shifttype_controller()
         throw_redirect(page_link_to('shifttypes'));
     }
     $shifttype = ShiftType::findOrFail($request->input('shifttype_id'));
 
     return [
-        $shifttype->name,
+        htmlspecialchars($shifttype->name),
         ShiftType_view($shifttype),
     ];
 }
 
 /**
diff --git a/includes/controller/user_angeltypes_controller.php b/includes/controller/user_angeltypes_controller.php
index 7b43d19fc..07d81dd61 100644
--- a/includes/controller/user_angeltypes_controller.php
+++ b/includes/controller/user_angeltypes_controller.php
@@ -37,11 +37,11 @@ function user_angeltypes_unconfirmed_hint()
 
     $unconfirmed_links = [];
     foreach ($unconfirmed_user_angeltypes as $user_angeltype) {
         $unconfirmed_links[] = '<a href="'
             . page_link_to('angeltypes', ['action' => 'view', 'angeltype_id' => $user_angeltype->angel_type_id])
-            . '">' . $user_angeltype->angelType->name
+            . '">' . htmlspecialchars($user_angeltype->angelType->name)
             . ' (+' . $user_angeltype->count . ')'
             . '</a>';
     }
 
     $count = $unconfirmed_user_angeltypes->count();
@@ -436,11 +436,11 @@ function user_angeltype_join_controller(AngelType $angeltype)
 
         throw_redirect(page_link_to('angeltypes', ['action' => 'view', 'angeltype_id' => $angeltype->id]));
     }
 
     return [
-        sprintf(__('Become a %s'), $angeltype->name),
+        sprintf(__('Become a %s'), htmlspecialchars($angeltype->name)),
         UserAngelType_join_view($user, $angeltype),
     ];
 }
 
 /**
diff --git a/includes/controller/users_controller.php b/includes/controller/users_controller.php
index 5ed7a7e6e..0e2dbe73d 100644
--- a/includes/controller/users_controller.php
+++ b/includes/controller/users_controller.php
@@ -89,11 +89,11 @@ function user_delete_controller()
             throw_redirect(users_link());
         }
     }
 
     return [
-        sprintf(__('Delete %s'), $user_source->displayName),
+        sprintf(__('Delete %s'), htmlspecialchars($user_source->displayName)),
         User_delete_view($user_source),
     ];
 }
 
 /**
@@ -180,11 +180,11 @@ function user_edit_vouchers_controller()
             throw_redirect(user_link($user_source->id));
         }
     }
 
     return [
-        sprintf(__('%s\'s vouchers'), $user_source->displayName),
+        sprintf(__('%s\'s vouchers'), htmlspecialchars($user_source->displayName)),
         User_edit_vouchers_view($user_source),
     ];
 }
 
 /**
@@ -242,11 +242,11 @@ function user_controller()
     } else {
         $tshirt_score = sprintf('%.2f', User_tshirt_score($user_source->id)) . '&nbsp;h';
     }
 
     return [
-        $user_source->displayName,
+        htmlspecialchars($user_source->displayName),
         User_view(
             $user_source,
             auth()->can('admin_user'),
             $user_source->isFreeloader(),
             $user_source->userAngelTypes,
diff --git a/includes/engelsystem.php b/includes/engelsystem.php
index b156c68a7..0c368dc81 100644
--- a/includes/engelsystem.php
+++ b/includes/engelsystem.php
@@ -21,10 +21,10 @@ require __DIR__ . '/includes.php';
 /** @var \Engelsystem\Application $app */
 if ($app->get('config')->get('maintenance')) {
     http_response_code(503);
     $url = $app->get(UrlGeneratorInterface::class);
     $maintenance = file_get_contents(__DIR__ . '/../resources/views/layouts/maintenance.html');
-    $maintenance = str_replace('%APP_NAME%', $app->get('config')->get('app_name'), $maintenance);
+    $maintenance = str_replace('%APP_NAME%', htmlspecialchars($app->get('config')->get('app_name')), $maintenance);
     $maintenance = str_replace('%ASSETS_PATH%', $url->to(''), $maintenance);
     echo $maintenance;
     die();
 }
diff --git a/includes/helper/message_helper.php b/includes/helper/message_helper.php
index 13526a630..d550fd44a 100644
--- a/includes/helper/message_helper.php
+++ b/includes/helper/message_helper.php
@@ -15,64 +15,70 @@ function msg()
 /**
  * Renders an information message
  *
  * @param string $msg
  * @param bool   $immediately
+ * @param bool   $immediatelyRaw
  * @return string
  */
-function info($msg, $immediately = false)
+function info($msg, $immediately = false, $immediatelyRaw = false)
 {
-    return alert(NotificationType::INFORMATION, $msg, $immediately);
+    return alert(NotificationType::INFORMATION, $msg, $immediately, $immediatelyRaw);
 }
 
 /**
  * Renders a warning message
  *
  * @param string $msg
  * @param bool   $immediately
+ * @param bool   $immediatelyRaw
  * @return string
  */
-function warning($msg, $immediately = false)
+function warning($msg, $immediately = false, $immediatelyRaw = false)
 {
-    return alert(NotificationType::WARNING, $msg, $immediately);
+    return alert(NotificationType::WARNING, $msg, $immediately, $immediatelyRaw);
 }
 
 /**
  * Renders an error message
  *
  * @param string $msg
  * @param bool   $immediately
+ * @param bool   $immediatelyRaw
  * @return string
  */
-function error($msg, $immediately = false)
+function error($msg, $immediately = false, $immediatelyRaw = false)
 {
-    return alert(NotificationType::ERROR, $msg, $immediately);
+    return alert(NotificationType::ERROR, $msg, $immediately, $immediatelyRaw);
 }
 
 /**
  * Renders a success message
  *
  * @param string $msg
  * @param bool   $immediately
+ * @param bool   $immediatelyRaw
  * @return string
  */
-function success($msg, $immediately = false)
+function success($msg, $immediately = false, $immediatelyRaw = false)
 {
-    return alert(NotificationType::MESSAGE, $msg, $immediately);
+    return alert(NotificationType::MESSAGE, $msg, $immediately, $immediatelyRaw);
 }
 
 /**
  * Renders an alert message with the given alert-* class or sets it in session
  *
- * @see \Engelsystem\Controllers\HasUserNotifications
- *
  * @param NotificationType $type
  * @param string           $msg
  * @param bool             $immediately
+ * @param bool             $immediatelyRaw
  * @return string
+ *
+ * @see \Engelsystem\Controllers\HasUserNotifications
+ *
  */
-function alert(NotificationType $type, $msg, $immediately = false)
+function alert(NotificationType $type, $msg, $immediately = false, $immediatelyRaw = false)
 {
     if (empty($msg)) {
         return '';
     }
 
@@ -85,10 +91,11 @@ function alert(NotificationType $type, $msg, $immediately = false)
                 NotificationType::MESSAGE->value,
             ],
             ['danger', 'warning', 'info', 'success'],
             $type->value
         );
+        $msg = $immediatelyRaw ? $msg : htmlspecialchars($msg);
         return '<div class="alert alert-' . $type . '" role="alert">' . $msg . '</div>';
     }
 
     $type = 'messages.' . $type->value;
     $session = session();
diff --git a/includes/pages/admin_free.php b/includes/pages/admin_free.php
index 7fd17faae..ff6859fe9 100644
--- a/includes/pages/admin_free.php
+++ b/includes/pages/admin_free.php
@@ -98,13 +98,13 @@ function admin_free()
         $email = $usr->contact->email ?: $usr->email;
         $free_users_table[] = [
             'name'        => User_Nick_render($usr) . User_Pronoun_render($usr),
             'shift_state' => User_shift_state_render($usr),
             'last_shift'  => User_last_shift_render($usr),
-            'dect'        => sprintf('<a href="tel:%s">%1$s</a>', $usr->contact->dect),
+            'dect'        => sprintf('<a href="tel:%s">%1$s</a>', htmlspecialchars((string) $usr->contact->dect)),
             'email'       => $usr->settings->email_human
-                ? sprintf('<a href="mailto:%s">%1$s</a>', $email)
+                ? sprintf('<a href="mailto:%s">%1$s</a>', htmlspecialchars((string) $email))
                 : icon('eye-slash'),
             'actions'     =>
                 auth()->can('admin_user')
                     ? button(page_link_to('admin_user', ['id' => $usr->id]), icon('pencil') . __('edit'), 'btn-sm')
                     : '',
diff --git a/includes/pages/admin_groups.php b/includes/pages/admin_groups.php
index 5e46d5ba0..6152475bb 100644
--- a/includes/pages/admin_groups.php
+++ b/includes/pages/admin_groups.php
@@ -29,15 +29,15 @@ function admin_groups()
             /** @var Privilege[]|Collection $privileges */
             $privileges = $group->privileges()->orderBy('name')->get();
             $privileges_html = [];
 
             foreach ($privileges as $privilege) {
-                $privileges_html[] = $privilege['name'];
+                $privileges_html[] = htmlspecialchars($privilege['name']);
             }
 
             $groups_table[] = [
-                'name'       => $group->name,
+                'name'       => htmlspecialchars($group->name),
                 'privileges' => join(', ', $privileges_html),
                 'actions'    => button(
                     page_link_to(
                         'admin_groups',
                         ['action' => 'edit', 'id' => $group->id]
@@ -70,19 +70,19 @@ function admin_groups()
                     $privileges = groupPrivilegesWithSelected($group);
                     $privileges_form = [];
                     foreach ($privileges as $privilege) {
                         $privileges_form[] = form_checkbox(
                             'privileges[]',
-                            $privilege->description . ' (' . $privilege->name . ')',
+                            htmlspecialchars($privilege->description . ' (' . $privilege->name . ')'),
                             $privilege->selected != '',
                             $privilege->id,
-                            'privilege-' . $privilege->name
+                            'privilege-' . htmlspecialchars($privilege->name)
                         );
                     }
 
                     $privileges_form[] = form_submit('submit', __('Save'));
-                    $html .= page_with_title(__('Edit group') . ' ' . $group->name, [
+                    $html .= page_with_title(__('Edit group') . ' ' . htmlspecialchars($group->name), [
                         form(
                             $privileges_form,
                             page_link_to('admin_groups', ['action' => 'save', 'id' => $group->id])
                         ),
                     ]);
diff --git a/includes/pages/admin_shifts.php b/includes/pages/admin_shifts.php
index 01cb7bdbd..2cc922565 100644
--- a/includes/pages/admin_shifts.php
+++ b/includes/pages/admin_shifts.php
@@ -331,11 +331,11 @@ function admin_shifts()
                         . ', ' . round($end->copy()->diffInMinutes($start) / 60, 2) . 'h'
                         . '<br>'
                         . Room_name_render(Room::find($shift['room_id'])),
                     'title'         =>
                         ShiftType_name_render(ShiftType::find($shifttype_id))
-                        . ($shift['title'] ? '<br />' . $shift['title'] : ''),
+                        . ($shift['title'] ? '<br />' . htmlspecialchars($shift['title']) : ''),
                     'needed_angels' => '',
                 ];
                 foreach ($types as $type) {
                     if (isset($needed_angel_types[$type->id]) && $needed_angel_types[$type->id] > 0) {
                         $shifts_table_entry['needed_angels'] .= '<b>' . AngelType_name_render($type) . ':</b> '
@@ -441,11 +441,11 @@ function admin_shifts()
     $angel_types = '';
     foreach ($types as $type) {
         $angel_types .= '<div class="col-sm-6 col-md-8 col-lg-6 col-xl-4 col-xxl-3">'
             . form_spinner(
                 'angeltype_count_' . $type->id,
-                $type->name,
+                htmlspecialchars($type->name),
                 $needed_angel_types[$type->id],
                 [
                     'radio-name'  => 'angelmode',
                     'radio-value' => 'manually',
                 ]
diff --git a/includes/pages/admin_user.php b/includes/pages/admin_user.php
index b02d74737..711790062 100644
--- a/includes/pages/admin_user.php
+++ b/includes/pages/admin_user.php
@@ -46,33 +46,45 @@ function admin_user()
                 $html .= ' ' . __('If the angel is active, it can claim a T-shirt. If T-shirt is set to \'Yes\', the angel already got their T-shirt.');
             } else {
                 $html .= ' ' . __('If the angel is active, it can claim a goodie. If goodie is set to \'Yes\', the angel already got their goodie.');
             }
         }
-        $html .= '<br /><br />';
+        $html .= '<br><br>';
         $html .= '<form action="'
             . page_link_to('admin_user', ['action' => 'save', 'id' => $user_id])
             . '" method="post">' . "\n";
         $html .= form_csrf();
         $html .= '<table>' . "\n";
         $html .= '<input type="hidden" name="Type" value="Normal">' . "\n";
         $html .= '<tr><td>' . "\n";
         $html .= '<table>' . "\n";
-        $html .= '  <tr><td>' . __('Nickname') . '</td><td>' . '<input size="40" name="eNick" value="' . $user_source->name . '" class="form-control" maxlength="24"></td></tr>' . "\n";
+        $html .= '  <tr><td>' . __('Nickname') . '</td><td>'
+            . '<input size="40" name="eNick" value="' . htmlspecialchars($user_source->name) . '" class="form-control" maxlength="24">'
+            . '</td></tr>' . "\n";
         $html .= '  <tr><td>' . __('Last login') . '</td><td><p class="help-block">'
             . ($user_source->last_login_at ? $user_source->last_login_at->format(__('Y-m-d H:i')) : '-')
             . '</p></td></tr>' . "\n";
         if (config('enable_user_name')) {
-            $html .= '  <tr><td>' . __('Prename') . '</td><td>' . '<input size="40" name="eName" value="' . $user_source->personalData->last_name . '" class="form-control" maxlength="64"></td></tr>' . "\n";
-            $html .= '  <tr><td>' . __('Last name') . '</td><td>' . '<input size="40" name="eVorname" value="' . $user_source->personalData->first_name . '" class="form-control" maxlength="64"></td></tr>' . "\n";
+            $html .= '  <tr><td>' . __('Prename') . '</td><td>'
+                . '<input size="40" name="eName" value="' . htmlspecialchars((string) $user_source->personalData->last_name) . '" class="form-control" maxlength="64">'
+                . '</td></tr>' . "\n";
+            $html .= '  <tr><td>' . __('Last name') . '</td><td>'
+                . '<input size="40" name="eVorname" value="' . htmlspecialchars((string) $user_source->personalData->first_name) . '" class="form-control" maxlength="64">'
+                . '</td></tr>' . "\n";
         }
-        $html .= '  <tr><td>' . __('Mobile') . '</td><td>' . '<input type= "tel" size="40" name="eHandy" value="' . $user_source->contact->mobile . '" class="form-control" maxlength="40"></td></tr>' . "\n";
+        $html .= '  <tr><td>' . __('Mobile') . '</td><td>'
+            . '<input type= "tel" size="40" name="eHandy" value="' . htmlspecialchars((string) $user_source->contact->mobile) . '" class="form-control" maxlength="40">'
+            . '</td></tr>' . "\n";
         if (config('enable_dect')) {
-            $html .= '  <tr><td>' . __('DECT') . '</td><td>' . '<input size="40" name="eDECT" value="' . $user_source->contact->dect . '" class="form-control" maxlength="40"></td></tr>' . "\n";
+            $html .= '  <tr><td>' . __('DECT') . '</td><td>'
+                . '<input size="40" name="eDECT" value="' . htmlspecialchars((string) $user_source->contact->dect) . '" class="form-control" maxlength="40">'
+                . '</td></tr>' . "\n";
         }
         if ($user_source->settings->email_human) {
-            $html .= '  <tr><td>' . __('settings.profile.email') . '</td><td>' . '<input type="email" size="40" name="eemail" value="' . $user_source->email . '" class="form-control" maxlength="254"></td></tr>' . "\n";
+            $html .= '  <tr><td>' . __('settings.profile.email') . '</td><td>'
+                . '<input type="email" size="40" name="eemail" value="' . htmlspecialchars($user_source->email) . '" class="form-control" maxlength="254">'
+                . '</td></tr>' . "\n";
         }
         if ($goodie_tshirt) {
             $html .= '  <tr><td>' . __('user.shirt_size') . '</td><td>'
                 . html_select_key(
                     'size',
@@ -118,31 +130,35 @@ function admin_user()
             $html .= html_options('eTshirt', $options, $user_source->state->got_shirt) . '</td></tr>' . "\n";
         }
         $html .= '</table>' . "\n" . '</td><td></td></tr>';
 
         $html .= '</td></tr>' . "\n";
-        $html .= '</table>' . "\n" . '<br />' . "\n";
+        $html .= '</table>' . "\n" . '<br>' . "\n";
         $html .= '<button type="submit" class="btn btn-primary">' . __('form.save') . '</button>' . "\n";
         $html .= '</form>';
 
-        $html .= '<hr />';
+        $html .= '<hr>';
 
         $html .= form_info('', __('Please visit the angeltypes page or the users profile to manage the users angeltypes.'));
 
         $html .= ' ' . __('Here you can reset the password of this angel:') . '<form action="'
             . page_link_to('admin_user', ['action' => 'change_pw', 'id' => $user_id])
             . '" method="post">' . "\n";
         $html .= form_csrf();
         $html .= '<table>' . "\n";
-        $html .= '  <tr><td>' . __('Password') . '</td><td>' . '<input type="password" size="40" name="new_pw" value="" class="form-control" autocomplete="new-password"></td></tr>' . "\n";
-        $html .= '  <tr><td>' . __('Confirm password') . '</td><td>' . '<input type="password" size="40" name="new_pw2" value="" class="form-control" autocomplete="new-password"></td></tr>' . "\n";
-
-        $html .= '</table>' . "\n" . '<br />' . "\n";
+        $html .= '  <tr><td>' . __('Password') . '</td><td>'
+            . '<input type="password" size="40" name="new_pw" value="" class="form-control" autocomplete="new-password">'
+            . '</td></tr>' . "\n";
+        $html .= '  <tr><td>' . __('Confirm password') . '</td><td>'
+            . '<input type="password" size="40" name="new_pw2" value="" class="form-control" autocomplete="new-password">'
+            . '</td></tr>' . "\n";
+
+        $html .= '</table>' . "\n" . '<br>' . "\n";
         $html .= '<button type="submit" class="btn btn-primary">' . __('form.save') . '</button>' . "\n";
         $html .= '</form>';
 
-        $html .= '<hr />';
+        $html .= '<hr>';
 
         /** @var Group $my_highest_group */
         $my_highest_group = $user->groups()->orderByDesc('id')->first();
         if (!empty($my_highest_group)) {
             $my_highest_group = $my_highest_group->id;
@@ -166,19 +182,21 @@ function admin_user()
             $groups = changeableGroups($my_highest_group, $user_id);
             foreach ($groups as $group) {
                 $html .= '<div class="form-check">'
                     . '<input class="form-check-input" type="checkbox" id="' . $group->id . '" name="groups[]" value="' . $group->id . '" '
                     . ($group->selected ? ' checked="checked"' : '')
-                    . ' /><label class="form-check-label" for="' . $group->id . '">' . $group->name . '</label></div>';
+                    . ' /><label class="form-check-label" for="' . $group->id . '">'
+                    . htmlspecialchars($group->name)
+                    . '</label></div>';
             }
 
             $html .= '</div><br>';
 
             $html .= '<button type="submit" class="btn btn-primary">' . __('form.save') . '</button>' . "\n";
             $html .= '</form>';
 
-            $html .= '<hr />';
+            $html .= '<hr>';
         }
 
         $html .= buttons([
             button(user_delete_link($user_source->id), icon('trash') . __('delete'), 'btn-danger'),
         ]);
diff --git a/includes/pages/guest_login.php b/includes/pages/guest_login.php
index 851e76707..c391f676e 100644
--- a/includes/pages/guest_login.php
+++ b/includes/pages/guest_login.php
@@ -84,11 +84,11 @@ function guest_register()
     }
     foreach ($angel_types_source as $angel_type) {
         if ($angel_type->hide_register) {
             continue;
         }
-        $angel_types[$angel_type->id] = $angel_type->name
+        $angel_types[$angel_type->id] = htmlspecialchars($angel_type->name)
             . ($angel_type->restricted ? ' (' . __('Requires introduction') . ')' : '');
         if (!$angel_type->restricted) {
             $selected_angel_types[] = $angel_type->id;
         }
     }
@@ -434,11 +434,11 @@ function guest_register()
                     ),
                     form_checkbox(
                         'email_shiftinfo',
                         __(
                             'settings.profile.email_shiftinfo',
-                            [config('app_name')]
+                            [htmlspecialchars(config('app_name'))]
                         ),
                         $email_shiftinfo
                     ),
                     form_checkbox(
                         'email_news',
@@ -457,11 +457,11 @@ function guest_register()
                     ),
                     $goodie_enabled ?
                         form_checkbox(
                             'email_goody',
                             __('To receive vouchers, give consent that nick, email address, worked hours and shirt size will be stored until the next similar event.')
-                            . (config('privacy_email') ? ' ' . __('To withdraw your approval, send an email to <a href="mailto:%s">%1$s</a>.', [config('privacy_email')]) : ''),
+                            . (config('privacy_email') ? ' ' . __('To withdraw your approval, send an email to <a href="mailto:%s">%1$s</a>.', [htmlspecialchars(config('privacy_email'))]) : ''),
                             $email_goody
                         ) : '',
                 ]),
 
                 $enable_dect ? div('col', [
diff --git a/includes/pages/user_shifts.php b/includes/pages/user_shifts.php
index d1b7a08f7..841ff8f25 100644
--- a/includes/pages/user_shifts.php
+++ b/includes/pages/user_shifts.php
@@ -375,19 +375,10 @@ function ical_hint()
             </button>'
         . '</p>'
         . '<p id="collapseApiKey" class="collapse"><code>' . $user->api_key . '</code></p>';
 }
 
-/**
- * @param array $array
- * @return array
- */
-function get_ids_from_array($array)
-{
-    return $array['id'];
-}
-
 /**
  * @param array  $items
  * @param array  $selected
  * @param string $name
  * @param string $title
@@ -416,11 +407,11 @@ function make_select($items, $selected, $name, $title = null, $ownSelect = [])
     foreach ($items as $i) {
         $id = $name . '_' . $i['id'];
         $htmlItems[] = '<div class="form-check">'
             . '<input class="form-check-input" type="checkbox" id="' . $id . '" name="' . $name . '[]" value="' . $i['id'] . '" '
             . (in_array($i['id'], $selected) ? ' checked="checked"' : '')
-            . '><label class="form-check-label" for="' . $id . '">' . $i['name'] . '</label>'
+            . '><label class="form-check-label" for="' . $id . '">' . htmlspecialchars($i['name']) . '</label>'
             . (!isset($i['enabled']) || $i['enabled'] ? '' : icon('mortarboard-fill'))
             . '</div>';
     }
     $html .= implode("\n", $htmlItems);
 
diff --git a/includes/sys_form.php b/includes/sys_form.php
index 2ef208a5a..fae7988ab 100644
--- a/includes/sys_form.php
+++ b/includes/sys_form.php
@@ -126,18 +126,19 @@ function form_checkbox($name, $label, $selected, $value = 'checked', $html_id =
     if (is_null($html_id)) {
         $html_id = $name;
     }
 
     return '<div class="form-check">'
-        . '<input class="form-check-input" type="checkbox" id="' . $html_id . '" name="' . $name . '" value="' . htmlspecialchars((string) $value) . '" '
+        . '<input class="form-check-input" type="checkbox" id="' . $html_id . '" '
+        . 'name="' . htmlspecialchars($name) . '" value="' . $value . '" '
         . ($selected ? ' checked="checked"' : '') . ' /><label class="form-check-label" for="' . $html_id . '">'
         . $label
         . '</label></div>';
 }
 
 /**
- * Rendert einen Radio
+ * Renders a radio button
  *
  * @param string $name
  * @param string $label
  * @param string $selected
  * @param string $value
@@ -230,30 +231,10 @@ function form_text($name, $label, $value, $disabled = false, $maxlength = null,
         'form_' . $name,
         $class
     );
 }
 
-/**
- * Renders a text input with placeholder instead of label.
- *
- * @param string  $name        Input name
- * @param string  $placeholder Placeholder
- * @param string  $value       The value
- * @param boolean $disabled    Is the field enabled?
- * @return string
- */
-function form_text_placeholder($name, $placeholder, $value, $disabled = false)
-{
-    $disabled = $disabled ? ' disabled="disabled"' : '';
-    return form_element(
-        '',
-        '<input class="form-control" id="form_' . $name . '" type="text" name="' . $name
-        . '" value="' . htmlspecialchars((string) $value) . '" placeholder="' . $placeholder
-        . '" ' . $disabled . '/>'
-    );
-}
-
 /**
  * Rendert ein Formular-Emailfeld
  *
  * @param string      $name
  * @param string      $label
@@ -275,26 +256,10 @@ function form_email($name, $label, $value, $disabled = false, $autocomplete = nu
         . htmlspecialchars((string) $value) . '" ' . $disabled . $autocomplete . $maxlength . '/>',
         'form_' . $name
     );
 }
 
-/**
- * Rendert ein Formular-Dateifeld
- *
- * @param string $name
- * @param string $label
- * @return string
- */
-function form_file($name, $label)
-{
-    return form_element(
-        $label,
-        sprintf('<input id="form_%1$s" type="file" name="%1$s" />', $name),
-        'form_' . $name
-    );
-}
-
 /**
  * Rendert ein Formular-Passwortfeld
  *
  * @param string $name
  * @param string $label
@@ -306,39 +271,20 @@ function form_password($name, $label, $autocomplete, $disabled = false)
 {
     $disabled = $disabled ? ' disabled="disabled"' : '';
     return form_element(
         $label,
         sprintf(
-            '<input class="form-control" id="form_%1$s" type="password" name="%1$s" minlength="%2$s" value="" autocomplete="%3$s"%4$s/>',
+            '<input class="form-control" id="form_%1$s" type="password" name="%1$s" minlength="%2$s" value="" autocomplete="%3$s" %4$s>',
             $name,
             config('min_password_length'),
             $autocomplete,
             $disabled
         ),
         'form_' . $name
     );
 }
 
-/**
- * Renders a password input with placeholder instead of label.
- *
- * @param string $name
- * @param string $placeholder
- * @param bool   $disabled
- * @return string
- */
-function form_password_placeholder($name, $placeholder, $disabled = false)
-{
-    $disabled = $disabled ? ' disabled="disabled"' : '';
-    return form_element(
-        '',
-        '<input class="form-control" id="form_' . $name . '" type="password" name="'
-        . $name . '" value="" placeholder="' . $placeholder . '" ' . $disabled . '/>',
-        'form_' . $name
-    );
-}
-
 /**
  * Rendert ein Formular-Textfeld
  *
  * @param string $name
  * @param string $label
@@ -461,13 +407,17 @@ function html_select_key($dom_id, $name, $rows, $selected, $selectText = '')
     if (!empty($selectText)) {
         $html .= '<option value="">' . $selectText . '</option>';
     }
     foreach ($rows as $key => $row) {
         if (($key == $selected) || ($row === $selected)) {
-            $html .= '<option value="' . $key . '" selected="selected">' . $row . '</option>';
+            $html .= '<option value="' . htmlspecialchars($key) . '" selected="selected">'
+                . htmlspecialchars($row)
+                . '</option>';
         } else {
-            $html .= '<option value="' . $key . '">' . $row . '</option>';
+            $html .= '<option value="' . htmlspecialchars($key) . '">'
+                . htmlspecialchars($row)
+                . '</option>';
         }
     }
     $html .= '</select>';
     return $html;
 }
diff --git a/includes/sys_menu.php b/includes/sys_menu.php
index 815c604cb..35b96a1b8 100644
--- a/includes/sys_menu.php
+++ b/includes/sys_menu.php
@@ -74,19 +74,26 @@ function make_navigation()
         if (!menu_is_allowed($menu_page, $options)) {
             continue;
         }
 
         $title = ((array) $options)[0];
-        $menu[] = toolbar_item_link(page_link_to($menu_page), '', $title, $menu_page == $page);
+        $menu[] = toolbar_item_link(
+            page_link_to($menu_page),
+            '',
+            $title,
+            $menu_page == $page
+        );
     }
 
     $menu = make_room_navigation($menu);
 
     $admin_menu = [];
     $admin_pages = [
-        // path              => name
-        // path              => [name, permission]
+        // Examples:
+        // path              => name,
+        // path              => [name, permission],
+
         'admin_arrive'       => 'Arrive angels',
         'admin_active'       => 'Active angels',
         'users'              => ['All Angels', 'admin_user'],
         'admin_free'         => 'Free angels',
         'admin/questions'    => ['Answer questions', 'question.edit'],
@@ -109,11 +116,11 @@ function make_navigation()
         }
 
         $title = ((array) $options)[0];
         $admin_menu[] = toolbar_dropdown_item(
             page_link_to($menu_page),
-            __($title),
+            htmlspecialchars(__($title)),
             $menu_page == $page
         );
     }
 
     if (count($admin_menu) > 0) {
diff --git a/includes/sys_page.php b/includes/sys_page.php
index a5eb71421..b0e7b4920 100644
--- a/includes/sys_page.php
+++ b/includes/sys_page.php
@@ -1,12 +1,10 @@
 <?php
 
 use Engelsystem\Helpers\Carbon;
 use Engelsystem\Http\Exceptions\HttpTemporaryRedirect;
-use Engelsystem\Models\BaseModel;
 use Engelsystem\ValidationResult;
-use Illuminate\Support\Collection;
 
 /**
  * Provide page/request helper functions
  */
 
@@ -61,45 +59,10 @@ function parse_date($pattern, $value)
 function throw_redirect($url)
 {
     throw new HttpTemporaryRedirect($url);
 }
 
-/**
- * Echoes given output and dies.
- *
- * @param string $output String to display
- */
-function raw_output($output = '')
-{
-    echo $output;
-    die();
-}
-
-/**
- * Helper function for transforming list of entities into array for select boxes.
- *
- * @param array|Collection $data       The data array
- * @param string           $key_name   name of the column to use as id/key
- * @param string           $value_name name of the column to use as displayed value
- *
- * @return array|Collection
- */
-function select_array($data, $key_name, $value_name)
-{
-    if ($data instanceof Collection) {
-        return $data->mapWithKeys(function (BaseModel $model) use ($key_name, $value_name) {
-            return [$model->{$key_name} => $model->{$value_name}];
-        });
-    }
-
-    $return = [];
-    foreach ($data as $value) {
-        $return[$value[$key_name]] = $value[$value_name];
-    }
-    return $return;
-}
-
 /**
  * Returns an int[] from given request param name.
  *
  * @param string $name    Name of the request param
  * @param array  $default Default return value, if param is not set
@@ -183,27 +146,10 @@ function strip_request_item($name, $default_value = null)
         return strip_item($request->input($name));
     }
     return $default_value;
 }
 
-/**
- * Returns REQUEST value or default value (null) if not set.
- *
- * @param string $name
- * @param string|null $default_value
- * @return mixed|null
- */
-function strip_request_tags($name, $default_value = null)
-{
-    $request = request();
-    if ($request->has($name)) {
-        return strip_tags($request->input($name));
-    }
-
-    return $default_value;
-}
-
 /**
  * Testet, ob der angegebene REQUEST Wert ein Integer ist, bzw.
  * eine ID sein könnte.
  *
  * @param string $name
diff --git a/includes/sys_template.php b/includes/sys_template.php
index bad1cf2a2..56df96e23 100644
--- a/includes/sys_template.php
+++ b/includes/sys_template.php
@@ -70,21 +70,10 @@ function tabs($tabs, $selected = 0)
         '<ul class="nav nav-tabs mb-3" role="tablist">' . join($tab_header) . '</ul>',
         '<div class="tab-content">' . join($tab_content) . '</div>',
     ]);
 }
 
-/**
- * Display muted (grey) text.
- *
- * @param string $text
- * @return string
- */
-function mute($text)
-{
-    return '<span class="text-muted">' . $text . '</span>';
-}
-
 /**
  * Renders a bootstrap label with given content and class.
  *
  * @param string $content The text
  * @param string $class default, primary, info, success, warning, danger
@@ -186,23 +175,23 @@ function toolbar_pills($items)
 function toolbar_item_link($href, $icon, $label, $active = false)
 {
     return '<li class="nav-item">'
         . '<a class="nav-link ' . ($active ? 'active" aria-current="page"' : '"') . ' href="' . $href . '">'
         . ($icon != '' ? '<span class="bi bi-' . $icon . '"></span> ' : '')
-        . $label
+        . htmlspecialchars($label)
         . '</a>'
         . '</li>';
 }
 
 function toolbar_dropdown_item(string $href, string $label, bool $active, string $icon = null): string
 {
     return strtr(
-        '<li><a class="dropdown-item{active}"{aria} href="{href}">{icon} {label}</a></li>',
+        '<li><a class="dropdown-item{active}" {aria} href="{href}">{icon} {label}</a></li>',
         [
             '{href}'   => $href,
             '{icon}'   => $icon === null ? '' : '<i class="bi bi-' . $icon . '"></i>',
-            '{label}'  => $label,
+            '{label}'  => htmlspecialchars($label),
             '{active}' => $active ? ' active' : '',
             '{aria}' => $active ? ' aria-current="page"' : '',
         ]
     );
 }
@@ -233,11 +222,11 @@ EOT;
 
     return strtr(
         $template,
         [
             '{class}'   => $active ? ' active' : '',
-            '{label}'   => $label,
+            '{label}'   => htmlspecialchars($label),
             '{submenu}' => join("\n", $submenu),
         ]
     );
 }
 
diff --git a/includes/view/AngelTypes_view.php b/includes/view/AngelTypes_view.php
index 290e93ae7..81e6bfd5a 100644
--- a/includes/view/AngelTypes_view.php
+++ b/includes/view/AngelTypes_view.php
@@ -24,11 +24,11 @@ function AngelType_name_render(AngelType $angeltype, $plain = false)
     if ($plain) {
         return sprintf('%s (%u)', $angeltype->name, $angeltype->id);
     }
 
     return '<a href="' . angeltype_link($angeltype->id) . '">'
-        . ($angeltype->restricted ? icon('mortarboard-fill') : '') . $angeltype->name
+        . ($angeltype->restricted ? icon('mortarboard-fill') : '') . htmlspecialchars($angeltype->name)
         . '</a>';
 }
 
 /**
  * Render angeltype membership state
@@ -58,11 +58,11 @@ function AngelType_render_membership(AngelType $user_angeltype)
  * @param AngelType $angeltype
  * @return string
  */
 function AngelType_delete_view(AngelType $angeltype)
 {
-    return page_with_title(sprintf(__('Delete angeltype %s'), $angeltype->name), [
+    return page_with_title(sprintf(__('Delete angeltype %s'), htmlspecialchars($angeltype->name)), [
         info(sprintf(__('Do you want to delete angeltype %s?'), $angeltype->name), true),
         form([
             buttons([
                 button(page_link_to('angeltypes'), icon('x-lg') . __('cancel')),
                 form_submit('delete', icon('trash') . __('delete'), 'btn-danger', false),
@@ -78,18 +78,18 @@ function AngelType_delete_view(AngelType $angeltype)
  * @param boolean   $supporter_mode Is the user a supporter of this angeltype?
  * @return string
  */
 function AngelType_edit_view(AngelType $angeltype, bool $supporter_mode)
 {
-    return page_with_title(sprintf(__('Edit %s'), $angeltype->name), [
+    return page_with_title(sprintf(__('Edit %s'), htmlspecialchars((string) $angeltype->name)), [
         buttons([
             button(page_link_to('angeltypes'), icon('person-lines-fill') . __('Angeltypes'), 'back'),
         ]),
         msg(),
         form([
             $supporter_mode
-                ? form_info(__('Name'), $angeltype->name)
+                ? form_info(__('Name'), htmlspecialchars($angeltype->name))
                 : form_text('name', __('Name'), $angeltype->name),
             $supporter_mode
                 ? form_info(__('Requires introduction'), $angeltype->restricted ? __('Yes') : __('No'))
                 : form_checkbox('restricted', __('Requires introduction'), $angeltype->restricted),
             form_info(
@@ -242,11 +242,11 @@ function AngelType_view_members(AngelType $angeltype, $members, $admin_user_ange
     $members_confirmed = [];
     $members_unconfirmed = [];
     foreach ($members as $member) {
         $member->name = User_Nick_render($member) . User_Pronoun_render($member);
         if (config('enable_dect')) {
-            $member['dect'] = $member->contact->dect;
+            $member['dect'] = htmlspecialchars((string) $member->contact->dect);
         }
         if ($angeltype->requires_driver_license) {
             $member['wants_to_drive'] = icon_bool($member->license->wantsToDrive());
             $member['has_car'] = icon_bool($member->license->has_car);
             $member['has_license_car'] = icon_bool($member->license->drive_car);
@@ -403,11 +403,11 @@ function AngelType_view(
     $user,
     ShiftsFilterRenderer $shiftsFilterRenderer,
     ShiftCalendarRenderer $shiftCalendarRenderer,
     $tab
 ) {
-    return page_with_title(sprintf(__('Team %s'), $angeltype->name), [
+    return page_with_title(sprintf(__('Team %s'), htmlspecialchars($angeltype->name)), [
         AngelType_view_buttons($angeltype, $user_angeltype, $admin_angeltypes, $supporter, $user_driver_license, $user),
         msg(),
         tabs([
             __('Info')   => AngelType_view_info(
                 $angeltype,
@@ -463,11 +463,11 @@ function AngelType_view_info(
     }
 
     $info[] = '<h3>' . __('Description') . '</h3>';
     $parsedown = new Parsedown();
     if ($angeltype->description != '') {
-        $info[] = $parsedown->parse($angeltype->description);
+        $info[] = $parsedown->parse(htmlspecialchars($angeltype->description));
     }
 
     list($supporters, $members_confirmed, $members_unconfirmed) = AngelType_view_members(
         $angeltype,
         $members,
@@ -537,13 +537,24 @@ function AngelType_view_info(
  * @return string HTML
  */
 function AngelTypes_render_contact_info(AngelType $angeltype)
 {
     $info = [
-        __('Name')   => [$angeltype->contact_name, $angeltype->contact_name],
-        __('DECT')   => config('enable_dect') ? [sprintf('<a href="tel:%s">%1$s</a>', $angeltype->contact_dect), $angeltype->contact_dect] : null,
-        __('E-Mail') => [sprintf('<a href="mailto:%s">%1$s</a>', $angeltype->contact_email), $angeltype->contact_email],
+        __('Name')  => [
+            htmlspecialchars($angeltype->contact_name),
+            htmlspecialchars($angeltype->contact_name),
+        ],
+        __('DECT')  => config('enable_dect')
+            ? [
+                sprintf('<a href="tel:%s">%1$s</a>', htmlspecialchars($angeltype->contact_dect)),
+                htmlspecialchars($angeltype->contact_dect),
+            ]
+            : null,
+        __('E-Mail') => [
+            sprintf('<a href="mailto:%s">%1$s</a>', htmlspecialchars($angeltype->contact_email)),
+            htmlspecialchars($angeltype->contact_email),
+        ],
     ];
     $contactInfo = [];
     foreach ($info as $name => $data) {
         if (!empty($data[1])) {
             $contactInfo[$name] = $data[0];
diff --git a/includes/view/PublicDashboard_view.php b/includes/view/PublicDashboard_view.php
index a39946bfd..b77d9152c 100644
--- a/includes/view/PublicDashboard_view.php
+++ b/includes/view/PublicDashboard_view.php
@@ -17,11 +17,13 @@ function public_dashboard_view($stats, $free_shifts, $important_news)
     $needed_angels = '';
     $news = '';
     if ($important_news->isNotEmpty()) {
         $first_news = $important_news->first();
         $news = div('alert alert-warning text-center', [
-            '<a href="' . url('/news/' . $first_news->id) . '"><strong>' . $first_news->title . '</strong></a>',
+            '<a href="' . url('/news/' . $first_news->id) . '">'
+            . '<strong>' . htmlspecialchars($first_news->title) . '</strong>'
+            . '</a>',
         ]);
     }
 
     if (count($free_shifts) > 0) {
         $shift_panels = [
@@ -91,21 +93,21 @@ function public_dashboard_view($stats, $free_shifts, $important_news)
 function public_dashboard_shift_render($shift)
 {
     $panel_body = icon('clock-history') . $shift['start'] . ' - ' . $shift['end'];
     $panel_body .= ' (' . $shift['duration'] . '&nbsp;h)';
 
-    $panel_body .= '<br>' . icon('list-task') . $shift['shifttype_name'];
+    $panel_body .= '<br>' . icon('list-task') . htmlspecialchars($shift['shifttype_name']);
     if (!empty($shift['title'])) {
-        $panel_body .= ' (' . $shift['title'] . ')';
+        $panel_body .= ' (' . htmlspecialchars($shift['title']) . ')';
     }
 
-    $panel_body .= '<br>' . icon('pin-map-fill') . $shift['room_name'];
+    $panel_body .= '<br>' . icon('pin-map-fill') . htmlspecialchars($shift['room_name']);
 
     foreach ($shift['needed_angels'] as $needed_angels) {
         $panel_body .= '<br>' . icon('person')
             . '<span class="text-' . $shift['style'] . '">'
-            . $needed_angels['need'] . ' &times; ' . $needed_angels['angeltype_name']
+            . $needed_angels['need'] . ' &times; ' . htmlspecialchars($needed_angels['angeltype_name'])
             . '</span>';
     }
 
     $type = 'bg-dark';
     if (theme_type() == 'light') {
diff --git a/includes/view/Rooms_view.php b/includes/view/Rooms_view.php
index f1ba4c4c5..2693b9011 100644
--- a/includes/view/Rooms_view.php
+++ b/includes/view/Rooms_view.php
@@ -22,26 +22,26 @@ function Room_view(Room $room, ShiftsFilterRenderer $shiftsFilterRenderer, Shift
 
     $description = '';
     if ($room->description) {
         $description = '<h3>' . __('Description') . '</h3>';
         $parsedown = new Parsedown();
-        $description .= $parsedown->parse($room->description);
+        $description .= $parsedown->parse(htmlspecialchars($room->description));
     }
 
     $dect = '';
     if (config('enable_dect') && $room->dect) {
         $dect = heading(__('Contact'), 3)
-            . description([__('DECT') => sprintf('<a href="tel:%s">%1$s</a>', $room->dect)]);
+            . description([__('DECT') => sprintf('<a href="tel:%s">%1$s</a>', htmlspecialchars($room->dect))]);
     }
 
     $tabs = [];
     if ($room->map_url) {
         $tabs[__('Map')] = sprintf(
             '<div class="map">'
             . '<iframe style="width: 100%%; min-height: 400px; border: 0 none;" src="%s"></iframe>'
             . '</div>',
-            $room->map_url
+            htmlspecialchars($room->map_url)
         );
     }
 
     $tabs[__('Shifts')] = div('first', [
         $shiftsFilterRenderer->render(page_link_to('rooms', [
@@ -55,11 +55,11 @@ function Room_view(Room $room, ShiftsFilterRenderer $shiftsFilterRenderer, Shift
     $request = request();
     if ($request->has('shifts_filter_day')) {
         $selected_tab = count($tabs) - 1;
     }
 
-    return page_with_title(icon('pin-map-fill') . $room->name, [
+    return page_with_title(icon('pin-map-fill') . htmlspecialchars($room->name), [
         $assignNotice,
         auth()->can('admin_rooms') ? buttons([
             button(
                 page_link_to('admin/rooms/edit/' . $room->id),
                 icon('pencil') . __('edit')
@@ -77,10 +77,10 @@ function Room_view(Room $room, ShiftsFilterRenderer $shiftsFilterRenderer, Shift
  * @return string
  */
 function Room_name_render(Room $room)
 {
     if (auth()->can('view_rooms')) {
-        return '<a href="' . room_link($room) . '">' . icon('pin-map-fill') . $room->name . '</a>';
+        return '<a href="' . room_link($room) . '">' . icon('pin-map-fill') . htmlspecialchars($room->name) . '</a>';
     }
 
-    return icon('pin-map-fill') . $room->name;
+    return icon('pin-map-fill') . htmlspecialchars($room->name);
 }
diff --git a/includes/view/ShiftCalendarShiftRenderer.php b/includes/view/ShiftCalendarShiftRenderer.php
index 3ab89147c..5caa89760 100644
--- a/includes/view/ShiftCalendarShiftRenderer.php
+++ b/includes/view/ShiftCalendarShiftRenderer.php
@@ -27,11 +27,11 @@ class ShiftCalendarShiftRenderer
      */
     public function render(Shift $shift, $needed_angeltypes, $shift_entries, $user)
     {
         $info_text = '';
         if ($shift->title != '') {
-            $info_text = icon('info-circle') . $shift->title . '<br>';
+            $info_text = icon('info-circle') . htmlspecialchars($shift->title) . '<br>';
         }
         list($shift_signup_state, $shifts_row) = $this->renderShiftNeededAngeltypes(
             $shift,
             $needed_angeltypes,
             $shift_entries,
@@ -197,11 +197,11 @@ class ShiftCalendarShiftRenderer
                 ? $inner_text . icon('mortarboard-fill')
                 // Add link to join the angeltype first
                 : $inner_text . '<br />'
                 . button(
                     page_link_to('user_angeltypes', ['action' => 'add', 'angeltype_id' => $angeltype->id]),
-                    sprintf(__('Become %s'), $angeltype->name),
+                    sprintf(__('Become %s'), htmlspecialchars($angeltype->name)),
                     'btn-sm'
                 ),
             // Shift collides or user is already signed up: No signup allowed
             ShiftSignupStatus::COLLIDES, ShiftSignupStatus::SIGNED_UP => $inner_text,
             // Shift is full
@@ -260,11 +260,11 @@ class ShiftCalendarShiftRenderer
                     ),
                 ]) . '</div>';
         }
         $shift_heading = $shift->start->format('H:i') . ' &dash; '
             . $shift->end->format('H:i') . ' &mdash; '
-            . $shift->shiftType->name;
+            . htmlspecialchars($shift->shiftType->name);
 
         if ($needed_angeltypes_count > 0) {
             $shift_heading = '<span class="badge bg-light text-danger me-1">' . $needed_angeltypes_count . '</span> ' . $shift_heading;
         }
 
diff --git a/includes/view/ShiftEntry_view.php b/includes/view/ShiftEntry_view.php
index 31242b46c..4d8f33f96 100644
--- a/includes/view/ShiftEntry_view.php
+++ b/includes/view/ShiftEntry_view.php
@@ -17,11 +17,11 @@ use Engelsystem\Models\User\User;
 function ShiftEntry_delete_view_admin(Shift $shift, AngelType $angeltype, User $signoff_user)
 {
     return page_with_title(ShiftEntry_delete_title(), [
         info(sprintf(
             __('Do you want to sign off %s from shift %s from %s to %s as %s?'),
-            User_Nick_render($signoff_user),
+            $signoff_user->displayName,
             $shift->shiftType->name,
             $shift->start->format(__('Y-m-d H:i')),
             $shift->end->format(__('Y-m-d H:i')),
             $angeltype->name
         ), true),
@@ -90,11 +90,11 @@ function ShiftEntry_create_view_admin(
     $signup_user,
     $users_select
 ) {
     $start = $shift->start->format(__('Y-m-d H:i'));
     return page_with_title(
-        ShiftEntry_create_title() . ': ' . $shift->shiftType->name
+        ShiftEntry_create_title() . ': ' . htmlspecialchars($shift->shiftType->name)
         . ' <small title="' . $start . '" data-countdown-ts="' . $shift->start->timestamp . '">%c</small>',
         [
             Shift_view_header($shift, $room),
             info(__('Do you want to sign up the following user for this shift?'), true),
             form([
@@ -118,11 +118,11 @@ function ShiftEntry_create_view_admin(
  */
 function ShiftEntry_create_view_supporter(Shift $shift, Room $room, AngelType $angeltype, $signup_user, $users_select)
 {
     $start = $shift->start->format(__('Y-m-d H:i'));
     return page_with_title(
-        ShiftEntry_create_title() . ': ' . $shift->shiftType->name
+        ShiftEntry_create_title() . ': ' . htmlspecialchars($shift->shiftType->name)
         . ' <small title="' . $start . '" data-countdown-ts="' . $shift->start->timestamp . '">%c</small>',
         [
             Shift_view_header($shift, $room),
             info(sprintf(
                 __('Do you want to sign up the following user for this shift as %s?'),
@@ -147,11 +147,11 @@ function ShiftEntry_create_view_supporter(Shift $shift, Room $room, AngelType $a
  */
 function ShiftEntry_create_view_user(Shift $shift, Room $room, AngelType $angeltype, $comment)
 {
     $start = $shift->start->format(__('Y-m-d H:i'));
     return page_with_title(
-        ShiftEntry_create_title() . ': ' . $shift->shiftType->name
+        ShiftEntry_create_title() . ': ' . htmlspecialchars($shift->shiftType->name)
         . ' <small title="' . $start . '" data-countdown-ts="' . $shift->start->timestamp . '">%c</small>',
         [
             Shift_view_header($shift, $room),
             info(sprintf(__('Do you want to sign up for this shift as %s?'), $angeltype->name), true),
             form([
@@ -216,13 +216,13 @@ function ShiftEntry_edit_view(
     return page_with_title(__('Edit shift entry'), [
         msg(),
         form([
             form_info(__('Angel:'), User_Nick_render($angel)),
             form_info(__('Date, Duration:'), $date),
-            form_info(__('Location:'), $location),
-            form_info(__('Title:'), $title),
-            form_info(__('Type:'), $type),
+            form_info(__('Location:'), htmlspecialchars($location)),
+            form_info(__('Title:'), htmlspecialchars($title)),
+            form_info(__('Type:'), htmlspecialchars($type)),
             $comment,
             join('', $freeload_form),
             form_submit('submit', __('Save')),
         ]),
     ]);
diff --git a/includes/view/ShiftTypes_view.php b/includes/view/ShiftTypes_view.php
index 4f2a7b071..f19f883ed 100644
--- a/includes/view/ShiftTypes_view.php
+++ b/includes/view/ShiftTypes_view.php
@@ -8,22 +8,22 @@ use Illuminate\Support\Collection;
  * @return string
  */
 function ShiftType_name_render(ShiftType $shifttype)
 {
     if (auth()->can('shifttypes')) {
-        return '<a href="' . shifttype_link($shifttype) . '">' . $shifttype->name . '</a>';
+        return '<a href="' . shifttype_link($shifttype) . '">' . htmlspecialchars($shifttype->name) . '</a>';
     }
     return $shifttype->name;
 }
 
 /**
  * @param ShiftType $shifttype
  * @return string
  */
 function ShiftType_delete_view(ShiftType $shifttype)
 {
-    return page_with_title(sprintf(__('Delete shifttype %s'), $shifttype->name), [
+    return page_with_title(sprintf(__('Delete shifttype %s'), htmlspecialchars($shifttype->name)), [
         info(sprintf(__('Do you want to delete shifttype %s?'), $shifttype->name), true),
         form([
             buttons([
                 button(page_link_to('shifttypes'), icon('x-lg') . __('cancel')),
                 form_submit(
@@ -65,11 +65,11 @@ function ShiftType_edit_view($name, $description, $shifttype_id)
  */
 function ShiftType_view(ShiftType $shifttype)
 {
     $parsedown = new Parsedown();
     $title = $shifttype->name;
-    return page_with_title($title, [
+    return page_with_title(htmlspecialchars($title), [
         msg(),
         buttons([
             button(page_link_to('shifttypes'), shifttypes_title(), 'back'),
             button(
                 page_link_to('shifttypes', ['action' => 'edit', 'shifttype_id' => $shifttype->id]),
@@ -79,11 +79,11 @@ function ShiftType_view(ShiftType $shifttype)
                 page_link_to('shifttypes', ['action' => 'delete', 'shifttype_id' => $shifttype->id]),
                 icon('trash') . __('delete'),
             ),
         ]),
         heading(__('Description'), 2),
-        $parsedown->parse($shifttype->description),
+        $parsedown->parse(htmlspecialchars($shifttype->description)),
     ], true);
 }
 
 /**
  * @param ShiftType[]|array[]|Collection $shifttypes
@@ -93,11 +93,11 @@ function ShiftTypes_list_view($shifttypes)
 {
     foreach ($shifttypes as $shifttype) {
         $shifttype->name = '<a href="'
             . page_link_to('shifttypes', ['action' => 'view', 'shifttype_id' => $shifttype->id])
             . '">'
-            . $shifttype->name
+            . htmlspecialchars($shifttype->name)
             . '</a>';
         $shifttype->actions = table_buttons([
             button(
                 page_link_to(
                     'shifttypes',
diff --git a/includes/view/Shifts_view.php b/includes/view/Shifts_view.php
index 5e27dc0f6..e0c99b538 100644
--- a/includes/view/Shifts_view.php
+++ b/includes/view/Shifts_view.php
@@ -22,12 +22,12 @@ function Shift_view_header(Shift $shift, Room $room)
     return div('row', [
         div('col-sm-3 col-xs-6', [
             '<h4>' . __('Title') . '</h4>',
             '<p class="lead">'
             . ($shift->url != ''
-                ? '<a href="' . $shift->url . '">' . $shift->title . '</a>'
-                : $shift->title)
+                ? '<a href="' . htmlspecialchars($shift->url) . '">' . htmlspecialchars($shift->title) . '</a>'
+                : htmlspecialchars($shift->title))
             . '</p>',
         ]),
         div('col-sm-3 col-xs-6', [
             '<h4>' . __('Start') . '</h4>',
             '<p class="lead' . (time() >= $shift->start->timestamp ? ' text-success' : '') . '">',
@@ -96,11 +96,11 @@ function Shift_signup_button_render(Shift $shift, AngelType $angeltype)
     } elseif (empty($user_angeltype)) {
         return button(
             page_link_to('angeltypes', ['action' => 'view', 'angeltype_id' => $angeltype->id]),
             sprintf(
                 __('Become %s'),
-                $angeltype->name
+                htmlspecialchars($angeltype->name)
             )
         );
     }
 
     return '';
@@ -168,12 +168,19 @@ function Shift_view(Shift $shift, ShiftType $shifttype, Room $room, $angeltypes_
     $buttons = [];
     if ($shift_admin || $admin_shifttypes || $admin_rooms) {
         $buttons = [
             $shift_admin ? button(shift_edit_link($shift), icon('pencil') . __('edit')) : '',
             $shift_admin ? button(shift_delete_link($shift), icon('trash') . __('delete')) : '',
-            $admin_shifttypes ? button(shifttype_link($shifttype), $shifttype->name) : '',
-            $admin_rooms ? button(room_link($room), icon('pin-map-fill') . $room->name) : '',
+            $admin_shifttypes
+                ? button(shifttype_link($shifttype), htmlspecialchars($shifttype->name))
+                : '',
+            $admin_rooms
+                ? button(
+                    room_link($room),
+                    icon('pin-map-fill') . htmlspecialchars($room->name)
+                )
+                : '',
         ];
     }
     $buttons[] = button(user_link(auth()->user()->id), '<span class="icon-icon_angel"></span> ' . __('My shifts'));
     $content[] = buttons($buttons);
 
@@ -183,23 +190,24 @@ function Shift_view(Shift $shift, ShiftType $shifttype, Room $room, $angeltypes_
             '<h2>' . __('Needed angels') . '</h2>',
             '<div class="list-group">' . $needed_angels . '</div>',
         ]),
         div('col-sm-6', [
             '<h2>' . __('Description') . '</h2>',
-            $parsedown->parse($shifttype->description),
-            $parsedown->parse($shift->description),
+            $parsedown->parse(htmlspecialchars($shifttype->description)),
+            $parsedown->parse(htmlspecialchars($shift->description)),
         ]),
     ]);
 
     if ($shift_admin) {
         $content[] = Shift_editor_info_render($shift);
     }
 
     $start = $shift->start->format(__('Y-m-d H:i'));
 
     return page_with_title(
-        $shift->shiftType->name . ' <small title="' . $start . '" data-countdown-ts="' . $shift->start->timestamp . '">%c</small>',
+        htmlspecialchars($shift->shiftType->name)
+        . ' <small title="' . $start . '" data-countdown-ts="' . $shift->start->timestamp . '">%c</small>',
         $content
     );
 }
 
 /**
diff --git a/includes/view/UserAngelTypes_view.php b/includes/view/UserAngelTypes_view.php
index e50e1f045..9f41b86ad 100644
--- a/includes/view/UserAngelTypes_view.php
+++ b/includes/view/UserAngelTypes_view.php
@@ -136,11 +136,11 @@ function UserAngelType_delete_view(UserAngelType $user_angeltype, User $user, An
  */
 function UserAngelType_add_view(AngelType $angeltype, $users_source, $user_id)
 {
     $users = [];
     foreach ($users_source as $user_source) {
-        $users[$user_source->id] = User_Nick_render($user_source);
+        $users[$user_source->id] = $user_source->displayName;
     }
 
     return page_with_title(__('Add user to angeltype'), [
         msg(),
         buttons([
@@ -149,11 +149,11 @@ function UserAngelType_add_view(AngelType $angeltype, $users_source, $user_id)
                 __('back'),
                 'back'
             ),
         ]),
         form([
-            form_info(__('Angeltype'), $angeltype->name),
+            form_info(__('Angeltype'), htmlspecialchars($angeltype->name)),
             form_checkbox('auto_confirm_user', __('Confirm user'), true),
             form_select('user_id', __('User'), $users, $user_id),
             form_submit('submit', __('Add')),
         ]),
     ]);
@@ -164,11 +164,11 @@ function UserAngelType_add_view(AngelType $angeltype, $users_source, $user_id)
  * @param AngelType $angeltype
  * @return string
  */
 function UserAngelType_join_view($user, AngelType $angeltype)
 {
-    return page_with_title(sprintf(__('Become a %s'), $angeltype->name), [
+    return page_with_title(sprintf(__('Become a %s'), htmlspecialchars($angeltype->name)), [
         msg(),
         info(sprintf(
             __('Do you really want to add %s to %s?'),
             $user->displayName,
             $angeltype->name
diff --git a/includes/view/UserHintsRenderer.php b/includes/view/UserHintsRenderer.php
index 55c655959..4a06686f6 100644
--- a/includes/view/UserHintsRenderer.php
+++ b/includes/view/UserHintsRenderer.php
@@ -18,13 +18,13 @@ class UserHintsRenderer
     public function addHint($hint, $important = false)
     {
         if (!empty($hint)) {
             if ($important) {
                 $this->important = true;
-                $this->hints[] = error($hint, true);
+                $this->hints[] = error($hint, true, true);
             } else {
-                $this->hints[] = info($hint, true);
+                $this->hints[] = info($hint, true, true);
             }
         }
     }
 
     /**
diff --git a/includes/view/User_view.php b/includes/view/User_view.php
index 97ea6c0ca..d9a553e32 100644
--- a/includes/view/User_view.php
+++ b/includes/view/User_view.php
@@ -90,13 +90,13 @@ function Users_view(
     $goodie_tshirt = $goodie === GoodieType::Tshirt;
     $usersList = [];
     foreach ($users as $user) {
         $u = [];
         $u['name'] = User_Nick_render($user) . User_Pronoun_render($user);
-        $u['first_name'] = $user->personalData->first_name;
-        $u['last_name'] = $user->personalData->last_name;
-        $u['dect'] = sprintf('<a href="tel:%s">%1$s</a>', $user->contact->dect);
+        $u['first_name'] = htmlspecialchars((string) $user->personalData->first_name);
+        $u['last_name'] = htmlspecialchars((string) $user->personalData->last_name);
+        $u['dect'] = sprintf('<a href="tel:%s">%1$s</a>', htmlspecialchars((string) $user->contact->dect));
         $u['arrived'] = icon_bool($user->state->arrived);
         if (config('enable_voucher')) {
             $u['got_voucher'] = $user->state->got_voucher;
         }
         $u['freeloads'] = $user->getAttribute('freeloads');
@@ -271,11 +271,11 @@ function User_last_shift_render($user)
  */
 function User_view_shiftentries($needed_angel_type)
 {
     $shift_info = '<br><b><a href="'
         . page_link_to('angeltypes', ['action' => 'view', 'angeltype_id' => $needed_angel_type['id']])
-        . '">' . $needed_angel_type['name'] . '</a>:</b> ';
+        . '">' . htmlspecialchars($needed_angel_type['name']) . '</a>:</b> ';
 
     $shift_entries = [];
     foreach ($needed_angel_type['users'] as $user_shift) {
         $member = User_Nick_render($user_shift);
         if ($user_shift['freeloaded']) {
@@ -297,13 +297,13 @@ function User_view_shiftentries($needed_angel_type)
  * @param bool  $its_me
  * @return array
  */
 function User_view_myshift(Shift $shift, $user_source, $its_me)
 {
-    $shift_info = '<a href="' . shift_link($shift) . '">' . $shift->shiftType->name . '</a>';
+    $shift_info = '<a href="' . shift_link($shift) . '">' . htmlspecialchars($shift->shiftType->name) . '</a>';
     if ($shift->title) {
-        $shift_info .= '<br /><a href="' . shift_link($shift) . '">' . $shift->title . '</a>';
+        $shift_info .= '<br /><a href="' . shift_link($shift) . '">' . htmlspecialchars($shift->title) . '</a>';
     }
     foreach ($shift->needed_angeltypes as $needed_angel_type) {
         $shift_info .= User_view_shiftentries($needed_angel_type);
     }
 
@@ -318,20 +318,22 @@ function User_view_myshift(Shift $shift, $user_source, $its_me)
         'shift_info' => $shift_info,
         'comment'    => '',
     ];
 
     if ($its_me) {
-        $myshift['comment'] = $shift->user_comment;
+        $myshift['comment'] = htmlspecialchars($shift->user_comment);
     }
 
     if ($shift->freeloaded) {
         $myshift['duration'] = '<p class="text-danger">'
             . sprintf('%.2f', -($shift->end->timestamp - $shift->start->timestamp) / 3600 * 2) . '&nbsp;h'
             . '</p>';
         if (auth()->can('user_shifts_admin')) {
             $myshift['comment'] .= '<br />'
-                . '<p class="text-danger">' . __('Freeloaded') . ': ' . $shift->freeloaded_comment . '</p>';
+                . '<p class="text-danger">'
+                . __('Freeloaded') . ': ' . htmlspecialchars($shift->freeloaded_comment)
+                . '</p>';
         } else {
             $myshift['comment'] .= '<br /><p class="text-danger">' . __('Freeloaded') . '</p>';
         }
     }
 
@@ -452,11 +454,11 @@ function User_view_worklog(Worklog $worklog, $admin_user_worklog_privilege)
     return [
         'date'       => icon('calendar-event') . date(__('Y-m-d'), $worklog->worked_at->timestamp),
         'duration'   => sprintf('%.2f', $worklog->hours) . ' h',
         'room'       => '',
         'shift_info' => __('Work log entry'),
-        'comment'    => $worklog->comment . '<br>'
+        'comment'    => htmlspecialchars($worklog->comment) . '<br>'
             . sprintf(
                 __('Added by %s at %s'),
                 User_Nick_render($worklog->creator),
                 $worklog->created_at->format(__('Y-m-d H:i'))
             ),
@@ -614,21 +616,21 @@ function User_view(
             div('row user-info', [
                 div('col-md-2', [
                     config('enable_dect') && $user_source->contact->dect ?
                         heading(
                             icon('phone')
-                            . ' <a href="tel:' . $user_source->contact->dect . '">'
-                            . $user_source->contact->dect
+                            . ' <a href="tel:' . htmlspecialchars($user_source->contact->dect) . '">'
+                            . htmlspecialchars($user_source->contact->dect)
                             . '</a>'
                         )
                         : '',
                     config('enable_mobile_show') && $user_source->contact->mobile ?
                         $user_source->settings->mobile_show ?
                             heading(
                                 icon('phone')
-                                . ' <a href="tel:' . $user_source->contact->mobile . '">'
-                                . $user_source->contact->mobile
+                                . ' <a href="tel:' . htmlspecialchars($user_source->contact->mobile) . '">'
+                                . htmlspecialchars($user_source->contact->mobile)
                                 . '</a>'
                             )
                             : ''
                         : '',
                     $auth->can('user_messages') ?
@@ -645,22 +647,23 @@ function User_view(
                 $admin_user_privilege ? User_oauth_render($user_source) : '',
             ]),
             ($its_me || $admin_user_privilege) ? '<h2>' . __('Shifts') . '</h2>' : '',
             $myshifts_table,
             ($its_me && $nightShiftsConfig['enabled'] && $goodie_enabled) ? info(
-                icon('info-circle') . sprintf(
-                    __('Your night shifts between %d and %d am count twice.'),
+                sprintf(
+                    icon('info-circle') . __('Your night shifts between %d and %d am count twice.'),
                     $nightShiftsConfig['start'],
                     $nightShiftsConfig['end']
                 ),
+                true,
                 true
             ) : '',
             $its_me && count($shifts) == 0
                 ? error(sprintf(
                     __('Go to the <a href="%s">shifts table</a> to sign yourself up for some shifts.'),
                     page_link_to('user_shifts')
-                ), true)
+                ), true, true)
                 : '',
             $its_me ? ical_hint() : '',
         ]
     );
 }
@@ -786,11 +789,11 @@ function User_angeltypes_render($user_angeltypes)
         $class = 'text-success';
         if ($angeltype->restricted && !$angeltype->pivot->confirm_user_id) {
             $class = 'text-warning';
         }
         $output[] = '<a href="' . angeltype_link($angeltype->id) . '" class="' . $class . '">'
-            . ($angeltype->pivot->supporter ? icon('patch-check') : '') . $angeltype->name
+            . ($angeltype->pivot->supporter ? icon('patch-check') : '') . htmlspecialchars($angeltype->name)
             . '</a>';
     }
     return div('col-md-2', [
         heading(__('Angeltypes'), 4),
         join('<br>', $output),
@@ -803,11 +806,11 @@ function User_angeltypes_render($user_angeltypes)
  */
 function User_groups_render($user_groups)
 {
     $output = [];
     foreach ($user_groups as $group) {
-        $output[] = __($group->name);
+        $output[] = __(htmlspecialchars($group->name));
     }
 
     return div('col-md-2', [
         '<h4>' . __('Rights') . '</h4>',
         join('<br>', $output),
@@ -823,13 +826,15 @@ function User_oauth_render(User $user)
     $config = config('oauth');
 
     $output = [];
     foreach ($user->oauth as $oauth) {
         $output[] = __(
-            isset($config[$oauth->provider]['name'])
-                ? $config[$oauth->provider]['name']
-                : Str::ucfirst($oauth->provider)
+            htmlspecialchars(
+                isset($config[$oauth->provider]['name'])
+                    ? $config[$oauth->provider]['name']
+                    : Str::ucfirst($oauth->provider)
+            )
         );
     }
 
     if (!$output) {
         return '';
@@ -966,11 +971,14 @@ function render_user_tshirt_hint()
  * @return string|null
  */
 function render_user_dect_hint()
 {
     $user = auth()->user();
-    if ($user->state->arrived && config('enable_dect') && !$user->contact->dect) {
+    if (
+        $user->state->arrived
+        && config('enable_dect') && !$user->contact->dect
+    ) {
         $text = __('You need to specify a DECT phone number in your settings! If you don\'t have a DECT phone, just enter \'-\'.');
         return render_profile_link($text);
     }
 
     return null;
diff --git a/resources/views/emails/angeltype-added.twig b/resources/views/emails/angeltype-added.twig
index 5ce3fc831..a66a4eb31 100644
--- a/resources/views/emails/angeltype-added.twig
+++ b/resources/views/emails/angeltype-added.twig
@@ -1,11 +1,11 @@
 {% extends "emails/mail.twig" %}
 
 {% set url=url('/angeltypes', {'action': 'view', 'angeltype_id': angeltype.id}) %}
 
 {% block introduction %}
-{{ __('notification.angeltype.added.introduction', [angeltype.name, url])|raw }}
+{{ __('notification.angeltype.added.introduction', [angeltype.name|e, url])|raw }}
 {% endblock %}
 
 {% block message %}
-{{ __('notification.angeltype.added.text', [angeltype.name, url])|raw }}
+{{ __('notification.angeltype.added.text', [angeltype.name|e, url])|raw }}
 {% endblock %}
diff --git a/resources/views/emails/angeltype-confirmed.twig b/resources/views/emails/angeltype-confirmed.twig
index 1fd2d0b19..8f2c3e179 100644
--- a/resources/views/emails/angeltype-confirmed.twig
+++ b/resources/views/emails/angeltype-confirmed.twig
@@ -1,11 +1,11 @@
 {% extends "emails/mail.twig" %}
 
 {% set url=url('/angeltypes', {'action': 'view', 'angeltype_id': angeltype.id}) %}
 
 {% block introduction %}
-{{ __('notification.angeltype.confirmed.introduction', [angeltype.name, url])|raw }}
+{{ __('notification.angeltype.confirmed.introduction', [angeltype.name|e, url])|raw }}
 {% endblock %}
 
 {% block message %}
-{{ __('notification.angeltype.confirmed.text', [angeltype.name, url])|raw }}
+{{ __('notification.angeltype.confirmed.text', [angeltype.name|e, url])|raw }}
 {% endblock %}
diff --git a/resources/views/pages/login.twig b/resources/views/pages/login.twig
index 27400ffce..1d50401a7 100644
--- a/resources/views/pages/login.twig
+++ b/resources/views/pages/login.twig
@@ -5,11 +5,11 @@
 
 {% block content %}
     <div class="col-md-12">
         <div class="row mb-3 mt-5">
             <div class="col-sm-12 text-center" id="welcome-title">
-                <h2>{{ __('Welcome to the %s!', [config('name') ~ m.angel() ~ (config('app_name')|upper) ])|raw }}</h2>
+                <h2>{{ __('Welcome to the %s!', [config('name')|e ~ m.angel() ~ (config('app_name')|upper|e) ])|raw }}</h2>
             </div>
         </div>
 
         <div class="row mb-3">
             {% for name,date in {

Vulnerable code:         sprintf(__('Delete angeltype %s'), $angeltype->name),
        sprintf(__('Edit %s'), $angeltype->name),
        sprintf(__('Team %s'), $angeltype->name),
            . $angeltype->name
        $room->name,
            $angeltype_name,
                form_info('', __('This description is for single shifts, otherwise please use the description in shift type.')),
        $shift->shiftType->name,
        sprintf(__('Delete shifttype %s'), $shifttype->name),
        $shifttype->name,
            . '">' . $user_angeltype->angelType->name
        sprintf(__('Become a %s'), $angeltype->name),
        sprintf(__('Delete %s'), $user_source->displayName),
        sprintf(__('%s\'s vouchers'), $user_source->displayName),
        $user_source->displayName,
    $maintenance = str_replace('%APP_NAME%', $app->get('config')->get('app_name'), $maintenance);
function info($msg, $immediately = false)
    return alert(NotificationType::INFORMATION, $msg, $immediately);
function warning($msg, $immediately = false)
    return alert(NotificationType::WARNING, $msg, $immediately);
function error($msg, $immediately = false)
    return alert(NotificationType::ERROR, $msg, $immediately);
function success($msg, $immediately = false)
    return alert(NotificationType::MESSAGE, $msg, $immediately);
 * @see \Engelsystem\Controllers\HasUserNotifications
 *
function alert(NotificationType $type, $msg, $immediately = false)
            'dect'        => sprintf('<a href="tel:%s">%1$s</a>', $usr->contact->dect),
                ? sprintf('<a href="mailto:%s">%1$s</a>', $email)
                $privileges_html[] = $privilege['name'];
                'name'       => $group->name,
                            $privilege->description . ' (' . $privilege->name . ')',
                            'privilege-' . $privilege->name
                    $html .= page_with_title(__('Edit group') . ' ' . $group->name, [
                        . ($shift['title'] ? '<br />' . $shift['title'] : ''),
                $type->name,
        $html .= '<br /><br />';
        $html .= '  <tr><td>' . __('Nickname') . '</td><td>' . '<input size="40" name="eNick" value="' . $user_source->name . '" class="form-control" maxlength="24"></td></tr>' . "\n";
            $html .= '  <tr><td>' . __('Prename') . '</td><td>' . '<input size="40" name="eName" value="' . $user_source->personalData->last_name . '" class="form-control" maxlength="64"></td></tr>' . "\n";
            $html .= '  <tr><td>' . __('Last name') . '</td><td>' . '<input size="40" name="eVorname" value="' . $user_source->personalData->first_name . '" class="form-control" maxlength="64"></td></tr>' . "\n";
        $html .= '  <tr><td>' . __('Mobile') . '</td><td>' . '<input type= "tel" size="40" name="eHandy" value="' . $user_source->contact->mobile . '" class="form-control" maxlength="40"></td></tr>' . "\n";
            $html .= '  <tr><td>' . __('DECT') . '</td><td>' . '<input size="40" name="eDECT" value="' . $user_source->contact->dect . '" class="form-control" maxlength="40"></td></tr>' . "\n";
            $html .= '  <tr><td>' . __('settings.profile.email') . '</td><td>' . '<input type="email" size="40" name="eemail" value="' . $user_source->email . '" class="form-control" maxlength="254"></td></tr>' . "\n";
        $html .= '</table>' . "\n" . '<br />' . "\n";
        $html .= '<hr />';
        $html .= '  <tr><td>' . __('Password') . '</td><td>' . '<input type="password" size="40" name="new_pw" value="" class="form-control" autocomplete="new-password"></td></tr>' . "\n";
        $html .= '  <tr><td>' . __('Confirm password') . '</td><td>' . '<input type="password" size="40" name="new_pw2" value="" class="form-control" autocomplete="new-password"></td></tr>' . "\n";

        $html .= '</table>' . "\n" . '<br />' . "\n";
        $html .= '<hr />';
                    . ' /><label class="form-check-label" for="' . $group->id . '">' . $group->name . '</label></div>';
            $html .= '<hr />';
        $angel_types[$angel_type->id] = $angel_type->name
                            [config('app_name')]
                            . (config('privacy_email') ? ' ' . __('To withdraw your approval, send an email to <a href="mailto:%s">%1$s</a>.', [config('privacy_email')]) : ''),
/**
 * @param array $array
 * @return array
 */
function get_ids_from_array($array)
{
    return $array['id'];
}

            . '><label class="form-check-label" for="' . $id . '">' . $i['name'] . '</label>'
        . '<input class="form-check-input" type="checkbox" id="' . $html_id . '" name="' . $name . '" value="' . htmlspecialchars((string) $value) . '" '
 * Rendert einen Radio
/**
 * Renders a text input with placeholder instead of label.
 *
 * @param string  $name        Input name
 * @param string  $placeholder Placeholder
 * @param string  $value       The value
 * @param boolean $disabled    Is the field enabled?
 * @return string
 */
function form_text_placeholder($name, $placeholder, $value, $disabled = false)
{
    $disabled = $disabled ? ' disabled="disabled"' : '';
    return form_element(
        '',
        '<input class="form-control" id="form_' . $name . '" type="text" name="' . $name
        . '" value="' . htmlspecialchars((string) $value) . '" placeholder="' . $placeholder
        . '" ' . $disabled . '/>'
    );
}

/**
 * Rendert ein Formular-Dateifeld
 *
 * @param string $name
 * @param string $label
 * @return string
 */
function form_file($name, $label)
{
    return form_element(
        $label,
        sprintf('<input id="form_%1$s" type="file" name="%1$s" />', $name),
        'form_' . $name
    );
}

            '<input class="form-control" id="form_%1$s" type="password" name="%1$s" minlength="%2$s" value="" autocomplete="%3$s"%4$s/>',
/**
 * Renders a password input with placeholder instead of label.
 *
 * @param string $name
 * @param string $placeholder
 * @param bool   $disabled
 * @return string
 */
function form_password_placeholder($name, $placeholder, $disabled = false)
{
    $disabled = $disabled ? ' disabled="disabled"' : '';
    return form_element(
        '',
        '<input class="form-control" id="form_' . $name . '" type="password" name="'
        . $name . '" value="" placeholder="' . $placeholder . '" ' . $disabled . '/>',
        'form_' . $name
    );
}

            $html .= '<option value="' . $key . '" selected="selected">' . $row . '</option>';
            $html .= '<option value="' . $key . '">' . $row . '</option>';
        $menu[] = toolbar_item_link(page_link_to($menu_page), '', $title, $menu_page == $page);
        // path              => name
        // path              => [name, permission]
            __($title),
use Engelsystem\Models\BaseModel;
use Illuminate\Support\Collection;
/**
 * Echoes given output and dies.
 *
 * @param string $output String to display
 */
function raw_output($output = '')
{
    echo $output;
    die();
}

/**
 * Helper function for transforming list of entities into array for select boxes.
 *
 * @param array|Collection $data       The data array
 * @param string           $key_name   name of the column to use as id/key
 * @param string           $value_name name of the column to use as displayed value
 *
 * @return array|Collection
 */
function select_array($data, $key_name, $value_name)
{
    if ($data instanceof Collection) {
        return $data->mapWithKeys(function (BaseModel $model) use ($key_name, $value_name) {
            return [$model->{$key_name} => $model->{$value_name}];
        });
    }

    $return = [];
    foreach ($data as $value) {
        $return[$value[$key_name]] = $value[$value_name];
    }
    return $return;
}

/**
 * Returns REQUEST value or default value (null) if not set.
 *
 * @param string $name
 * @param string|null $default_value
 * @return mixed|null
 */
function strip_request_tags($name, $default_value = null)
{
    $request = request();
    if ($request->has($name)) {
        return strip_tags($request->input($name));
    }

    return $default_value;
}

/**
 * Display muted (grey) text.
 *
 * @param string $text
 * @return string
 */
function mute($text)
{
    return '<span class="text-muted">' . $text . '</span>';
}

        . $label
        '<li><a class="dropdown-item{active}"{aria} href="{href}">{icon} {label}</a></li>',
            '{label}'  => $label,
            '{label}'   => $label,
        . ($angeltype->restricted ? icon('mortarboard-fill') : '') . $angeltype->name
    return page_with_title(sprintf(__('Delete angeltype %s'), $angeltype->name), [
    return page_with_title(sprintf(__('Edit %s'), $angeltype->name), [
                ? form_info(__('Name'), $angeltype->name)
            $member['dect'] = $member->contact->dect;
    return page_with_title(sprintf(__('Team %s'), $angeltype->name), [
        $info[] = $parsedown->parse($angeltype->description);
        __('Name')   => [$angeltype->contact_name, $angeltype->contact_name],
        __('DECT')   => config('enable_dect') ? [sprintf('<a href="tel:%s">%1$s</a>', $angeltype->contact_dect), $angeltype->contact_dect] : null,
        __('E-Mail') => [sprintf('<a href="mailto:%s">%1$s</a>', $angeltype->contact_email), $angeltype->contact_email],
            '<a href="' . url('/news/' . $first_news->id) . '"><strong>' . $first_news->title . '</strong></a>',
    $panel_body .= '<br>' . icon('list-task') . $shift['shifttype_name'];
        $panel_body .= ' (' . $shift['title'] . ')';
    $panel_body .= '<br>' . icon('pin-map-fill') . $shift['room_name'];
            . $needed_angels['need'] . ' &times; ' . $needed_angels['angeltype_name']
        $description .= $parsedown->parse($room->description);
            . description([__('DECT') => sprintf('<a href="tel:%s">%1$s</a>', $room->dect)]);
            $room->map_url
    return page_with_title(icon('pin-map-fill') . $room->name, [
        return '<a href="' . room_link($room) . '">' . icon('pin-map-fill') . $room->name . '</a>';
    return icon('pin-map-fill') . $room->name;
            $info_text = icon('info-circle') . $shift->title . '<br>';
                    sprintf(__('Become %s'), $angeltype->name),
            . $shift->shiftType->name;
            User_Nick_render($signoff_user),
        ShiftEntry_create_title() . ': ' . $shift->shiftType->name
        ShiftEntry_create_title() . ': ' . $shift->shiftType->name
        ShiftEntry_create_title() . ': ' . $shift->shiftType->name
            form_info(__('Location:'), $location),
            form_info(__('Title:'), $title),
            form_info(__('Type:'), $type),
        return '<a href="' . shifttype_link($shifttype) . '">' . $shifttype->name . '</a>';
    return page_with_title(sprintf(__('Delete shifttype %s'), $shifttype->name), [
    return page_with_title($title, [
        $parsedown->parse($shifttype->description),
            . $shifttype->name
                ? '<a href="' . $shift->url . '">' . $shift->title . '</a>'
                : $shift->title)
                $angeltype->name
            $admin_shifttypes ? button(shifttype_link($shifttype), $shifttype->name) : '',
            $admin_rooms ? button(room_link($room), icon('pin-map-fill') . $room->name) : '',
            $parsedown->parse($shifttype->description),
            $parsedown->parse($shift->description),
        $shift->shiftType->name . ' <small title="' . $start . '" data-countdown-ts="' . $shift->start->timestamp . '">%c</small>',
        $users[$user_source->id] = User_Nick_render($user_source);
            form_info(__('Angeltype'), $angeltype->name),
    return page_with_title(sprintf(__('Become a %s'), $angeltype->name), [
                $this->hints[] = error($hint, true);
                $this->hints[] = info($hint, true);
        $u['first_name'] = $user->personalData->first_name;
        $u['last_name'] = $user->personalData->last_name;
        $u['dect'] = sprintf('<a href="tel:%s">%1$s</a>', $user->contact->dect);
        . '">' . $needed_angel_type['name'] . '</a>:</b> ';
    $shift_info = '<a href="' . shift_link($shift) . '">' . $shift->shiftType->name . '</a>';
        $shift_info .= '<br /><a href="' . shift_link($shift) . '">' . $shift->title . '</a>';
        $myshift['comment'] = $shift->user_comment;
                . '<p class="text-danger">' . __('Freeloaded') . ': ' . $shift->freeloaded_comment . '</p>';
        'comment'    => $worklog->comment . '<br>'
                            . ' <a href="tel:' . $user_source->contact->dect . '">'
                            . $user_source->contact->dect
                                . ' <a href="tel:' . $user_source->contact->mobile . '">'
                                . $user_source->contact->mobile
                icon('info-circle') . sprintf(
                    __('Your night shifts between %d and %d am count twice.'),
                ), true)
            . ($angeltype->pivot->supporter ? icon('patch-check') : '') . $angeltype->name
        $output[] = __($group->name);
            isset($config[$oauth->provider]['name'])
                ? $config[$oauth->provider]['name']
                : Str::ucfirst($oauth->provider)
    if ($user->state->arrived && config('enable_dect') && !$user->contact->dect) {
{{ __('notification.angeltype.added.introduction', [angeltype.name, url])|raw }}
{{ __('notification.angeltype.added.text', [angeltype.name, url])|raw }}
{{ __('notification.angeltype.confirmed.introduction', [angeltype.name, url])|raw }}
{{ __('notification.angeltype.confirmed.text', [angeltype.name, url])|raw }}
                <h2>{{ __('Welcome to the %s!', [config('name') ~ m.angel() ~ (config('app_name')|upper) ])|raw }}</h2>
Fixed code:         sprintf(__('Delete angeltype %s'), htmlspecialchars($angeltype->name)),
        sprintf(__('Edit %s'), htmlspecialchars((string) $angeltype->name)),
        sprintf(__('Team %s'), htmlspecialchars($angeltype->name)),
            . htmlspecialchars($angeltype->name)
        htmlspecialchars($room->name),
            htmlspecialchars($angeltype_name),
                form_info(
                    '',
                    __('This description is for single shifts, otherwise please use the description in shift type.')
                ),
        htmlspecialchars($shift->shiftType->name),
        sprintf(__('Delete shifttype %s'), htmlspecialchars($shifttype->name)),
        htmlspecialchars($shifttype->name),
            . '">' . htmlspecialchars($user_angeltype->angelType->name)
        sprintf(__('Become a %s'), htmlspecialchars($angeltype->name)),
        sprintf(__('Delete %s'), htmlspecialchars($user_source->displayName)),
        sprintf(__('%s\'s vouchers'), htmlspecialchars($user_source->displayName)),
        htmlspecialchars($user_source->displayName),
    $maintenance = str_replace('%APP_NAME%', htmlspecialchars($app->get('config')->get('app_name')), $maintenance);
 * @param bool   $immediatelyRaw
function info($msg, $immediately = false, $immediatelyRaw = false)
    return alert(NotificationType::INFORMATION, $msg, $immediately, $immediatelyRaw);
 * @param bool   $immediatelyRaw
function warning($msg, $immediately = false, $immediatelyRaw = false)
    return alert(NotificationType::WARNING, $msg, $immediately, $immediatelyRaw);
 * @param bool   $immediatelyRaw
function error($msg, $immediately = false, $immediatelyRaw = false)
    return alert(NotificationType::ERROR, $msg, $immediately, $immediatelyRaw);
 * @param bool   $immediatelyRaw
function success($msg, $immediately = false, $immediatelyRaw = false)
    return alert(NotificationType::MESSAGE, $msg, $immediately, $immediatelyRaw);
 * @param bool             $immediatelyRaw
 *
 * @see \Engelsystem\Controllers\HasUserNotifications
 *
function alert(NotificationType $type, $msg, $immediately = false, $immediatelyRaw = false)
        $msg = $immediatelyRaw ? $msg : htmlspecialchars($msg);
            'dect'        => sprintf('<a href="tel:%s">%1$s</a>', htmlspecialchars((string) $usr->contact->dect)),
                ? sprintf('<a href="mailto:%s">%1$s</a>', htmlspecialchars((string) $email))
                $privileges_html[] = htmlspecialchars($privilege['name']);
                'name'       => htmlspecialchars($group->name),
                            htmlspecialchars($privilege->description . ' (' . $privilege->name . ')'),
                            'privilege-' . htmlspecialchars($privilege->name)
                    $html .= page_with_title(__('Edit group') . ' ' . htmlspecialchars($group->name), [
                        . ($shift['title'] ? '<br />' . htmlspecialchars($shift['title']) : ''),
                htmlspecialchars($type->name),
        $html .= '<br><br>';
        $html .= '  <tr><td>' . __('Nickname') . '</td><td>'
            . '<input size="40" name="eNick" value="' . htmlspecialchars($user_source->name) . '" class="form-control" maxlength="24">'
            . '</td></tr>' . "\n";
            $html .= '  <tr><td>' . __('Prename') . '</td><td>'
                . '<input size="40" name="eName" value="' . htmlspecialchars((string) $user_source->personalData->last_name) . '" class="form-control" maxlength="64">'
                . '</td></tr>' . "\n";
            $html .= '  <tr><td>' . __('Last name') . '</td><td>'
                . '<input size="40" name="eVorname" value="' . htmlspecialchars((string) $user_source->personalData->first_name) . '" class="form-control" maxlength="64">'
                . '</td></tr>' . "\n";
        $html .= '  <tr><td>' . __('Mobile') . '</td><td>'
            . '<input type= "tel" size="40" name="eHandy" value="' . htmlspecialchars((string) $user_source->contact->mobile) . '" class="form-control" maxlength="40">'
            . '</td></tr>' . "\n";
            $html .= '  <tr><td>' . __('DECT') . '</td><td>'
                . '<input size="40" name="eDECT" value="' . htmlspecialchars((string) $user_source->contact->dect) . '" class="form-control" maxlength="40">'
                . '</td></tr>' . "\n";
            $html .= '  <tr><td>' . __('settings.profile.email') . '</td><td>'
                . '<input type="email" size="40" name="eemail" value="' . htmlspecialchars($user_source->email) . '" class="form-control" maxlength="254">'
                . '</td></tr>' . "\n";
        $html .= '</table>' . "\n" . '<br>' . "\n";
        $html .= '<hr>';
        $html .= '  <tr><td>' . __('Password') . '</td><td>'
            . '<input type="password" size="40" name="new_pw" value="" class="form-control" autocomplete="new-password">'
            . '</td></tr>' . "\n";
        $html .= '  <tr><td>' . __('Confirm password') . '</td><td>'
            . '<input type="password" size="40" name="new_pw2" value="" class="form-control" autocomplete="new-password">'
            . '</td></tr>' . "\n";

        $html .= '</table>' . "\n" . '<br>' . "\n";
        $html .= '<hr>';
                    . ' /><label class="form-check-label" for="' . $group->id . '">'
                    . htmlspecialchars($group->name)
                    . '</label></div>';
            $html .= '<hr>';
        $angel_types[$angel_type->id] = htmlspecialchars($angel_type->name)
                            [htmlspecialchars(config('app_name'))]
                            . (config('privacy_email') ? ' ' . __('To withdraw your approval, send an email to <a href="mailto:%s">%1$s</a>.', [htmlspecialchars(config('privacy_email'))]) : ''),
            . '><label class="form-check-label" for="' . $id . '">' . htmlspecialchars($i['name']) . '</label>'
        . '<input class="form-check-input" type="checkbox" id="' . $html_id . '" '
        . 'name="' . htmlspecialchars($name) . '" value="' . $value . '" '
 * Renders a radio button
            '<input class="form-control" id="form_%1$s" type="password" name="%1$s" minlength="%2$s" value="" autocomplete="%3$s" %4$s>',
            $html .= '<option value="' . htmlspecialchars($key) . '" selected="selected">'
                . htmlspecialchars($row)
                . '</option>';
            $html .= '<option value="' . htmlspecialchars($key) . '">'
                . htmlspecialchars($row)
                . '</option>';
        $menu[] = toolbar_item_link(
            page_link_to($menu_page),
            '',
            $title,
            $menu_page == $page
        );
        // Examples:
        // path              => name,
        // path              => [name, permission],

            htmlspecialchars(__($title)),
        . htmlspecialchars($label)
        '<li><a class="dropdown-item{active}" {aria} href="{href}">{icon} {label}</a></li>',
            '{label}'  => htmlspecialchars($label),
            '{label}'   => htmlspecialchars($label),
        . ($angeltype->restricted ? icon('mortarboard-fill') : '') . htmlspecialchars($angeltype->name)
    return page_with_title(sprintf(__('Delete angeltype %s'), htmlspecialchars($angeltype->name)), [
    return page_with_title(sprintf(__('Edit %s'), htmlspecialchars((string) $angeltype->name)), [
                ? form_info(__('Name'), htmlspecialchars($angeltype->name))
            $member['dect'] = htmlspecialchars((string) $member->contact->dect);
    return page_with_title(sprintf(__('Team %s'), htmlspecialchars($angeltype->name)), [
        $info[] = $parsedown->parse(htmlspecialchars($angeltype->description));
        __('Name')  => [
            htmlspecialchars($angeltype->contact_name),
            htmlspecialchars($angeltype->contact_name),
        ],
        __('DECT')  => config('enable_dect')
            ? [
                sprintf('<a href="tel:%s">%1$s</a>', htmlspecialchars($angeltype->contact_dect)),
                htmlspecialchars($angeltype->contact_dect),
            ]
            : null,
        __('E-Mail') => [
            sprintf('<a href="mailto:%s">%1$s</a>', htmlspecialchars($angeltype->contact_email)),
            htmlspecialchars($angeltype->contact_email),
        ],
            '<a href="' . url('/news/' . $first_news->id) . '">'
            . '<strong>' . htmlspecialchars($first_news->title) . '</strong>'
            . '</a>',
    $panel_body .= '<br>' . icon('list-task') . htmlspecialchars($shift['shifttype_name']);
        $panel_body .= ' (' . htmlspecialchars($shift['title']) . ')';
    $panel_body .= '<br>' . icon('pin-map-fill') . htmlspecialchars($shift['room_name']);
            . $needed_angels['need'] . ' &times; ' . htmlspecialchars($needed_angels['angeltype_name'])
        $description .= $parsedown->parse(htmlspecialchars($room->description));
            . description([__('DECT') => sprintf('<a href="tel:%s">%1$s</a>', htmlspecialchars($room->dect))]);
            htmlspecialchars($room->map_url)
    return page_with_title(icon('pin-map-fill') . htmlspecialchars($room->name), [
        return '<a href="' . room_link($room) . '">' . icon('pin-map-fill') . htmlspecialchars($room->name) . '</a>';
    return icon('pin-map-fill') . htmlspecialchars($room->name);
            $info_text = icon('info-circle') . htmlspecialchars($shift->title) . '<br>';
                    sprintf(__('Become %s'), htmlspecialchars($angeltype->name)),
            . htmlspecialchars($shift->shiftType->name);
            $signoff_user->displayName,
        ShiftEntry_create_title() . ': ' . htmlspecialchars($shift->shiftType->name)
        ShiftEntry_create_title() . ': ' . htmlspecialchars($shift->shiftType->name)
        ShiftEntry_create_title() . ': ' . htmlspecialchars($shift->shiftType->name)
            form_info(__('Location:'), htmlspecialchars($location)),
            form_info(__('Title:'), htmlspecialchars($title)),
            form_info(__('Type:'), htmlspecialchars($type)),
        return '<a href="' . shifttype_link($shifttype) . '">' . htmlspecialchars($shifttype->name) . '</a>';
    return page_with_title(sprintf(__('Delete shifttype %s'), htmlspecialchars($shifttype->name)), [
    return page_with_title(htmlspecialchars($title), [
        $parsedown->parse(htmlspecialchars($shifttype->description)),
            . htmlspecialchars($shifttype->name)
                ? '<a href="' . htmlspecialchars($shift->url) . '">' . htmlspecialchars($shift->title) . '</a>'
                : htmlspecialchars($shift->title))
                htmlspecialchars($angeltype->name)
            $admin_shifttypes
                ? button(shifttype_link($shifttype), htmlspecialchars($shifttype->name))
                : '',
            $admin_rooms
                ? button(
                    room_link($room),
                    icon('pin-map-fill') . htmlspecialchars($room->name)
                )
                : '',
            $parsedown->parse(htmlspecialchars($shifttype->description)),
            $parsedown->parse(htmlspecialchars($shift->description)),
        htmlspecialchars($shift->shiftType->name)
        . ' <small title="' . $start . '" data-countdown-ts="' . $shift->start->timestamp . '">%c</small>',
        $users[$user_source->id] = $user_source->displayName;
            form_info(__('Angeltype'), htmlspecialchars($angeltype->name)),
    return page_with_title(sprintf(__('Become a %s'), htmlspecialchars($angeltype->name)), [
                $this->hints[] = error($hint, true, true);
                $this->hints[] = info($hint, true, true);
        $u['first_name'] = htmlspecialchars((string) $user->personalData->first_name);
        $u['last_name'] = htmlspecialchars((string) $user->personalData->last_name);
        $u['dect'] = sprintf('<a href="tel:%s">%1$s</a>', htmlspecialchars((string) $user->contact->dect));
        . '">' . htmlspecialchars($needed_angel_type['name']) . '</a>:</b> ';
    $shift_info = '<a href="' . shift_link($shift) . '">' . htmlspecialchars($shift->shiftType->name) . '</a>';
        $shift_info .= '<br /><a href="' . shift_link($shift) . '">' . htmlspecialchars($shift->title) . '</a>';
        $myshift['comment'] = htmlspecialchars($shift->user_comment);
                . '<p class="text-danger">'
                . __('Freeloaded') . ': ' . htmlspecialchars($shift->freeloaded_comment)
                . '</p>';
        'comment'    => htmlspecialchars($worklog->comment) . '<br>'
                            . ' <a href="tel:' . htmlspecialchars($user_source->contact->dect) . '">'
                            . htmlspecialchars($user_source->contact->dect)
                                . ' <a href="tel:' . htmlspecialchars($user_source->contact->mobile) . '">'
                                . htmlspecialchars($user_source->contact->mobile)
                sprintf(
                    icon('info-circle') . __('Your night shifts between %d and %d am count twice.'),
                true,
                ), true, true)
            . ($angeltype->pivot->supporter ? icon('patch-check') : '') . htmlspecialchars($angeltype->name)
        $output[] = __(htmlspecialchars($group->name));
            htmlspecialchars(
                isset($config[$oauth->provider]['name'])
                    ? $config[$oauth->provider]['name']
                    : Str::ucfirst($oauth->provider)
            )
    if (
        $user->state->arrived
        && config('enable_dect') && !$user->contact->dect
    ) {
{{ __('notification.angeltype.added.introduction', [angeltype.name|e, url])|raw }}
{{ __('notification.angeltype.added.text', [angeltype.name|e, url])|raw }}
{{ __('notification.angeltype.confirmed.introduction', [angeltype.name|e, url])|raw }}
{{ __('notification.angeltype.confirmed.text', [angeltype.name|e, url])|raw }}
                <h2>{{ __('Welcome to the %s!', [config('name')|e ~ m.angel() ~ (config('app_name')|upper|e) ])|raw }}</h2>