CVE-2023-47350 (published 2023-11-22T16:15Z)

Cross-Site Request Forgery (CSRF) vulnerability in SwiftyEdit Content Management System prior to v1.2.0, allows remote attackers to escalate privileges via the user password update functionality.

CVSS v3 base score: 8.8, HIGH (CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H)

Weakness information:
cwe_id: CWE-352
cwe_name: Cross-Site Request Forgery (CSRF)
description: The web application does not, or can not, sufficiently verify whether a well-formed, valid, consistent request was intentionally provided by the user who submitted the request.
extended_description: When a web server is designed to receive a request from a client without any mechanism for verifying that it was intentionally sent, then it might be possible for an attacker to trick a client into making an unintentional request to the web server which will be treated as an authentic request. This can be done via a URL, image load, XMLHttpRequest, etc. and can result in exposure of data or unintended code execution.
         

Fix information:
repo_url: https://github.com/SwiftyEdit/SwiftyEdit
commit_details: repo_url: https://github.com/SwiftyEdit/SwiftyEdit
author: Patrick
author_date: 2023-11-02 19:30:50+01:00
msg: Add a hidden CSRF token to all forms

This update fixes a vulnerability that allows a potential attacker to make changes to the database via forms. In the worst case, for example, changing passwords.
@mechaneus thank you for finding and reporting this vulnerability.
repository: repo_url: https://github.com/SwiftyEdit/SwiftyEdit
repo_name: SwiftyEdit/SwiftyEdit
description: Web Content Management System for Websites, Blogs and Shops
repo_language: PHP
owner: SwiftyEdit
file_changes: filename: func_userdata.php
change_type: ModificationType.MODIFY
diff: @@ -256,9 +256,11 @@ function se_start_user_session($ud) {
 	$_SESSION['user_hash'] = md5($ud['user_nick']);
 	
 	/* CSRF Protection */
-	$token = md5(uniqid(rand(), TRUE));
-	$_SESSION['token']      = $token;
-	$_SESSION['token_time'] = time();
+    if(empty($_SESSION['token'])) {
+        $token = md5(uniqid(rand(), TRUE));
+        $_SESSION['token'] = $token;
+        $_SESSION['token_time'] = time();
+    }
 	
 	$arr_drm = explode("|", $ud['user_drm']);
 	

programming_language: PHP
filename: index.php
change_type: ModificationType.MODIFY
diff: @@ -33,10 +33,22 @@ $mod_slug = '';
 
 const SE_SECTION = "frontend";
 
-if(empty($_SESSION['visitor_csrf_token'])) {
-	$_SESSION['visitor_csrf_token'] = md5(uniqid(rand(), TRUE));
+if(empty($_SESSION['token'])) {
+	$_SESSION['token'] = md5(uniqid(rand(), TRUE));
+    $_SESSION['token_time'] = time();
 }
 
+/* stop all $_POST actions if csrf token is empty or invalid */
+if(!empty($_POST)) {
+    if(empty($_POST['csrf_token'])) {
+        die('Error: CSRF Token is empty');
+    }
+    if($_POST['csrf_token'] !== $_SESSION['token']) {
+        die('Error: CSRF Token is invalid');
+    }
+}
+
+
 /**
  * if there is no database config we start the installer
  * @var string $se_db_content SQLite file from config.php or /content/config.php
@@ -336,6 +348,9 @@ if($se_prefs['prefs_smarty_compile_check'] == 1) {
 	$smarty->compile_check = false;
 }
 
+$hidden_csrf_token = '<input type="hidden" name="csrf_token" value="'.$_SESSION['token'].'">';
+$smarty->assign('hidden_csrf_token', "$hidden_csrf_token", true);
+
 
 /* reset of the user-defined theme */
 if(isset($_POST['reset_theme'])) {

programming_language: PHP
filename: comment_form.tpl
change_type: ModificationType.MODIFY
diff: @@ -24,6 +24,7 @@
 	  <input type="hidden" name="page_id" value="{$page_id}">
 	  <input type="hidden" name="post_id" value="{$post_id}">
 		<input type="hidden" name="parent_id" value="{$parent_id}">
+		{$hidden_csrf_token}
 	</form>
 	
 	<div class="m-3">

programming_language: Perl
filename: download.tpl
change_type: ModificationType.MODIFY
diff: @@ -6,4 +6,5 @@
 	<button class="btn btn-success" type="submit" name="download" value="{$file_src}">
 		<i class="bi-arrow-down-circle"></i> Download
 	</button>
+	{$hidden_csrf_token}
 </form>
\ No newline at end of file

programming_language: HTML
filename: loginbox.tpl
change_type: ModificationType.MODIFY
diff: @@ -32,6 +32,7 @@
                 {/if}
 
                 <p>{$show_forgotten_psw_link}</p>
+                {$hidden_csrf_token}
             </form>
 
 			{if $show_register_link != ''}

programming_language: HTML
filename: navigation.tpl
change_type: ModificationType.MODIFY
diff: @@ -18,6 +18,7 @@
 		
 		<form class="form-inline" action="{$search_uri}" method="POST">
     		<input class="form-control mr-sm-2 searchbox" name="s" type="search" aria-label="Search" value="{$search_string}">
+			{$hidden_csrf_token}
   		</form>
 		
 	</div>

programming_language: HTML
filename: orders.tpl
change_type: ModificationType.MODIFY
diff: @@ -61,6 +61,7 @@
 											</div>
 											<input type="hidden" name="order" value="{$order.nbr}">
 											<input type="hidden" name="pos" value="{$product.pos}">
+											{$hidden_csrf_token}
 										</form>
 										{/if}
 										{* we provide no preview, but user can download the file  *}
@@ -69,6 +70,7 @@
 												<button type="submit" class="btn btn-sm btn-primary" name="download_user_file">Download</button>
 												<input type="hidden" name="order" value="{$order.nbr}">
 												<input type="hidden" name="pos" value="{$product.pos}">
+												{$hidden_csrf_token}
 											</form>
 										{/if}
 									</td>
@@ -80,12 +82,14 @@
 											<form action="{$order_page_uri}" method="POST" class="d-inline">
 												<button class="btn btn-primary" type="submit" name="dl_p_file" value="{$product.post_id}"><i class="bi bi-download"></i> DOWNLOAD</button>
 												<input type="hidden" name="order_id" value="{$order.nbr}">
+												{$hidden_csrf_token}
 											</form>
 										{/if}
 										{if $product.dl_file_ext != '' AND $order.status_payment == '2'}
 											<form action="{$order_page_uri}" method="POST" class="d-inline">
 												<button class="btn btn-primary" type="submit" name="dl_p_file_ext" value="{$product.post_id}"><i class="bi bi-cloud-download"></i> DOWNLOAD</button>
 												<input type="hidden" name="order_id" value="{$order.nbr}">
+												{$hidden_csrf_token}
 											</form>
 										{/if}
 										

programming_language: HTML
filename: page_psw_input.tpl
change_type: ModificationType.MODIFY
diff: @@ -9,5 +9,6 @@
 				<input type="submit" name="send" class="btn btn-success btn-block" value="{$button_send}">
 			</div>
 		</div>
+		{$hidden_csrf_token}
 	</form>
 </fieldset>
\ No newline at end of file

programming_language: PHP
filename: password.tpl
change_type: ModificationType.MODIFY
diff: @@ -18,6 +18,6 @@
 		
 				<input class="btn btn-success" type="submit" name="ask_for_psw" value="{$button_send}">
 			</div>
-	
+		{$hidden_csrf_token}
 	</fieldset>
 </form>
\ No newline at end of file

programming_language: HTML
filename: products-display.tpl
change_type: ModificationType.MODIFY
diff: @@ -74,7 +74,7 @@
                             <hr>
                             <button class="btn btn-outline-success btn-lg" name="add_to_cart" value="{$product_id}">{$btn_add_to_cart}</button>
                         </div>
-                        <input type="hidden" name="csrf_token" value="{$csrf_token}">
+                        {$hidden_csrf_token}
 
                     </form>
                 </div>
@@ -273,6 +273,7 @@
                 <input type="hidden" name="csrf_token" value="{$csrf_token}">
             </div>
         </div>
+            {$hidden_csrf_token}
         </form>
     {/if}
 

programming_language: HTML
filename: products-list.tpl
change_type: ModificationType.MODIFY
diff: @@ -92,7 +92,7 @@
                         {if $value.show_shopping_cart == true}
                             <form action="{$form_action}" method="POST" class="pt-1">
                                 <button class="btn btn-outline-success w-100" name="add_to_cart" value="{$value.product_id}">{$btn_add_to_cart}</button>
-                                <input type="hidden" name="csrf_token" value="{$csrf_token}">
+                                {$hidden_csrf_token}
                             </form>
                         {/if}
                     </div>

programming_language: HTML
filename: profile_main.tpl
change_type: ModificationType.MODIFY
diff: @@ -55,6 +55,7 @@
 			<input class="btn btn-primary" type="submit" name="update_address_data" value="{$lang_button_update}">
 		</div>
 	</div>
+	{$hidden_csrf_token}
 </form>
 
 <form class="form-horizontal" id="form_ba_address" action="{$form_url}" method="POST">
@@ -124,7 +125,7 @@
 		</div>
 	</div>
 
-
+	{$hidden_csrf_token}
 </form>
 
 <form class="form-horizontal" id="form_psw_data" action="{$form_url}" method="POST">
@@ -148,6 +149,7 @@
 		<input class="btn btn-primary" type="submit" name="update_psw_data" value="{$lang_button_update}">
 	</div>
 	</div>
+	{$hidden_csrf_token}
 </form>
 
 <form class="form-horizontal" id="form_email_data" action="{$form_url}" method="POST">
@@ -176,6 +178,7 @@
 		<input class="btn btn-primary" type="submit" name="update_email_data" value="{$lang_button_update}">
 	</div>
 </div>
+	{$hidden_csrf_token}
 </form>
 
 
@@ -186,7 +189,6 @@
 <!-- Avatar -->
 <form id="profileform" action="{$form_url}" method="post" enctype="multipart/form-data">
 
-
 	<div class="card mb-3">
 		<div class="card-header">{$lang_legend_avatar}</div>
 		<div class="card-body">
@@ -212,7 +214,7 @@
 
 </div>
 </div>
-
+	{$hidden_csrf_token}
 </form>
 
 
@@ -229,6 +231,7 @@
 
 <input class="btn btn-danger btn-small" type="submit" onclick="return confirm('{$msg_confirm_delete_account}')" name="delete_my_account" value="{$lang_button_delete}">
 </fieldset>
+	{$hidden_csrf_token}
 </form>
 
 </div>

programming_language: HTML
filename: registerform.tpl
change_type: ModificationType.MODIFY
diff: @@ -95,7 +95,7 @@
 		
 		
 <input class="btn btn-success mt-3 mb-3" type="submit" name="send_registerform" value="{$lang_button_send_register}">
-		
+	{$hidden_csrf_token}
 
 </form>
 {/nocache}
\ No newline at end of file

programming_language: HTML
filename: search.tpl
change_type: ModificationType.MODIFY
diff: @@ -6,6 +6,6 @@
             </div>
         </div>
         <hr class="shadow">
+        {$hidden_csrf_token}
     </form>
-</div>
-
+</div>
\ No newline at end of file

programming_language: HTML
filename: searchbox.tpl
change_type: ModificationType.DELETE
diff: @@ -1,10 +0,0 @@
-<div class="search_toggle">
-    <form action="{$search_uri}" method="POST" class="">
-        <div class="row">
-            <div class="col-md-12">
-                <input class="searchbox form-control" type="text" name="s" value="{$search_string}">
-            </div>
-        </div>
-        <hr class="shadow">
-    </form>
-</div>
\ No newline at end of file

programming_language: unknown
filename: shopping_cart_form.tpl
change_type: ModificationType.MODIFY
diff: @@ -24,6 +24,7 @@
         <textarea class="form-control" id="requestcomment" name="buyer_comment">{$buyer_comment}</textarea>
     </div>
     <button type="submit" class="btn btn-success" name="send_request" value="send">{$lang_btn_send_order_request}</button>
+    {$hidden_csrf_token}
 </form>
 
 </div>
\ No newline at end of file

programming_language: HTML
filename: shopping_cart_table.tpl
change_type: ModificationType.MODIFY
diff: @@ -38,6 +38,7 @@
                             <input type="number" name="cart_product_amount" value="{$item.amount}" class="form-control"
                                    onchange="this.form.submit()">
                             <input type="hidden" name="cart_item_key" value="{$item.cart_id}">
+                            {$hidden_csrf_token}
                         </form>
                     </div>
                 </div>
@@ -61,6 +62,7 @@
                 <form action="{$shopping_cart_uri}" method="POST">
                     <button type="submit" class="btn btn-link link-danger" name="remove_from_cart"
                             value="{$item.cart_id}"><i class="bi bi-trash"></i></button>
+                    {$hidden_csrf_token}
                 </form>
             </td>
         </tr>
@@ -88,6 +90,7 @@
                         <label class="form-check-label" for="id_{$pm.key}">{$pm.title} ({$currency} {$pm.cost})</label>
                     </div>
                 {/foreach}
+                {$hidden_csrf_token}
             </form>
         </td>
         <td class="text-end">{$currency} {$cart_payment_costs}</td>
@@ -165,6 +168,7 @@
                     </div>
                 </div>
             </div>
+            {$hidden_csrf_token}
         </form>
     {/if}
 {/if}
\ No newline at end of file

programming_language: HTML
filename: sidebar-filter.tpl
change_type: ModificationType.MODIFY
diff: @@ -55,7 +55,8 @@ example for links:
 
                 </div>
             {/foreach}
-    </div>
     <input type="hidden" name="set_custom_filters" value="send">
+    {$hidden_csrf_token}
     </form>
+    </div>
 {/if}
\ No newline at end of file

programming_language: HTML
filename: statusbox.tpl
change_type: ModificationType.MODIFY
diff: @@ -19,7 +19,7 @@
 		<form action="{$link_acp}?tn=pages&sub=edit" method="POST">
 			<div class="d-grid gap-2">
 				<button name="editpage" value="{$page_id}" class="btn btn-secondary w-100">{$lang_button_edit_page}</button>
-				<input type="hidden" name="csrf_token" value="{$smarty.session.token}">
+				{$hidden_csrf_token}
 			</div>
 		</form>
 			</div>

programming_language: HTML