diff --git a/core/bug_api.php b/core/bug_api.php
index e43bc05..eaf24a6 100644
--- a/core/bug_api.php
+++ b/core/bug_api.php
@@ -1075,13 +1075,16 @@ function bug_copy( $p_bug_id, $p_target_project_id = null, $p_copy_custom_fields
 
 /**
  * Moves an issue from a project to another.
+ *
  * @todo Validate with sub-project / category inheritance scenarios.
- * @todo Fix #11687: Bugs with attachments that are moved will lose attachments.
  * @param int p_bug_id The bug to be moved.
  * @param int p_target_project_id The target project to move the bug to.
  * @access public
  */
 function bug_move( $p_bug_id, $p_target_project_id ) {
+	// Attempt to move disk based attachments to new project file directory.
+	file_move_bug_attachments( $p_bug_id, $p_target_project_id );
+
 	// Move the issue to the new project.
 	bug_set_field( $p_bug_id, 'project_id', $p_target_project_id );
 
diff --git a/core/file_api.php b/core/file_api.php
index 1fc416f..10fd088 100644
--- a/core/file_api.php
+++ b/core/file_api.php
@@ -909,3 +909,72 @@ function file_get_content_type_override( $p_filename ) {
 
 	return $g_file_download_content_type_overrides[$t_extension];
 }
+
+/**
+ * Move any attachments as needed when a bug is moved from project to project.
+ *
+ * @param int $p_bug_id ID of bug containing attachments to be moved
+ * @param int $p_project_id_to destination project ID for the bug
+ * @return null
+ */
+function file_move_bug_attachments( $p_bug_id, $p_project_id_to ) {
+	$t_project_id_from = bug_get_field( $p_bug_id, 'project_id' );
+	if ( $t_project_id_from == $p_project_id_to ) {
+		return;
+	}
+
+	$t_method = config_get( 'file_upload_method' );
+	if ( $t_method != DISK ) {
+		return;
+	}
+
+	if ( !file_bug_has_attachments( $p_bug_id ) ) {
+		return;
+	}
+
+	$t_path_from = project_get_field( $t_project_id_from, 'file_path' );
+	if ( is_blank( $t_path_from ) ) {
+		$t_path_from = config_get( 'absolute_path_default_upload_folder', null, null, $t_project_id_from );
+	}
+	file_ensure_valid_upload_path( $t_path_from );
+	$t_path_to = project_get_field( $p_project_id_to, 'file_path' );
+	if ( is_blank( $t_path_to ) ) {
+		$t_path_to = config_get( 'absolute_path_default_upload_folder', null, null, $p_project_id_to );
+	}
+	file_ensure_valid_upload_path( $t_path_to );
+	if ( $t_path_from == $t_path_to ) {
+		return;
+	}
+
+	# Initialize the update query to update a single row
+	$t_bug_file_table = db_get_table( 'mantis_bug_file_table' );
+	$c_bug_id = db_prepare_int( $p_bug_id );
+	$query_disk_attachment_update = "UPDATE $t_bug_file_table
+	                                 SET folder=" . db_param() . "
+	                                 WHERE bug_id=" . db_param() . "
+	                                 AND id =" . db_param();
+
+	$t_attachment_rows = bug_get_attachments( $p_bug_id );
+	$t_attachments_count = count( $t_attachment_rows );
+	for ( $i = 0; $i < $t_attachments_count; $i++ ) {
+		$t_row = $t_attachment_rows[$i];
+		$t_basename = basename( $t_row['diskfile'] );
+
+		$t_disk_file_name_from = file_path_combine( $t_path_from, $t_basename );
+		$t_disk_file_name_to = file_path_combine( $t_path_to, $t_basename );
+
+		if ( !file_exists( $t_disk_file_name_to ) ) {
+			chmod( $t_disk_file_name_from, 0775 );
+			if ( !rename( $t_disk_file_name_from, $t_disk_file_name_to ) ) {
+				if ( !copy( $t_disk_file_name_from, $t_disk_file_name_to ) ) {
+					trigger_error( FILE_MOVE_FAILED, ERROR );
+				}
+				file_delete_local( $t_disk_file_name_from );
+			}
+			chmod( $t_disk_file_name_to, config_get( 'attachments_file_permissions' ) );
+			db_query_bound( $query_disk_attachment_update, Array( db_prepare_string( $t_path_to ), $c_bug_id, db_prepare_int( $t_row['id'] ) ) );
+		} else {
+			trigger_error( ERROR_FILE_DUPLICATE, ERROR );
+		}
+	}
+}
