CVE-2022-46165: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79)
value: Syncthing is an open source, continuous file synchronization program. In versions prior to 1.23.5 a compromised instance with shared folders could sync malicious files which contain arbitrary HTML and JavaScript in the name. If the owner of another device looks over the shared folder settings and moves the mouse over the latest sync, a script could be executed to change settings for shared folders or add devices automatically. Additionally adding a new device with a malicious name could embed HTML or JavaScript inside parts of the page. As a result the webUI may be subject to a stored cross site scripting attack. This issue has been addressed in version 1.23.5. Users are advised to upgrade. Users unable to upgrade should avoid sharing folders with untrusted users.
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-06-06T18:15Z
Repository: https://github.com/syncthing/syncthing
Language: HTML
Files changed: gui/default/assets/css/overrides.css, gui/default/index.html, gui/default/syncthing/core/aboutModalView.html, gui/default/syncthing/core/editShareTemplate.html, gui/default/syncthing/core/syncthingController.js, gui/default/syncthing/device/editDeviceModalView.html, gui/default/syncthing/device/globalChangesModalView.html, gui/default/syncthing/folder/editFolderModalView.html, gui/default/syncthing/transfer/localChangedFilesModalView.html, gui/default/syncthing/transfer/remoteNeededFilesModalView.html
Commit date: 2023-06-06 09:06:51 +0200
Commit message: gui: Avoid code generating HTML (#8923)


Diff: diff --git a/gui/default/assets/css/overrides.css b/gui/default/assets/css/overrides.css
index 06f705629..8b0e9fb45 100644
--- a/gui/default/assets/css/overrides.css
+++ b/gui/default/assets/css/overrides.css
@@ -183,11 +183,11 @@ td input[type="checkbox"] {
 .remote-devices-panel {
     display: inline-block;
 }
 
 /* Wrap long file paths to prevent text overflow. See issue #6268. */
-.file-path {
+.word-break-all {
     word-break: break-all;
 }
 
 .folder-advanced {
     padding: 1rem;
diff --git a/gui/default/index.html b/gui/default/index.html
index ac84df04c..cf4d60314 100644
--- a/gui/default/index.html
+++ b/gui/default/index.html
@@ -286,11 +286,11 @@
               </h3>
             </div>
             <div class="panel-body">
               <p ng-repeat="err in errorList()">
                 <small>{{err.when | date:"yyyy-MM-dd HH:mm:ss"}}:</small>
-                <span ng-bind-html="friendlyDevices(err.message) | linky: '_blank'"></span>
+                <span ng-bind="friendlyDevices(err.message)"></span>
               </p>
             </div>
             <div class="panel-footer">
               <button type="button" class="btn btn-sm btn-default pull-right" ng-click="clearErrors()">
                 <span class="fas fa-check"></span>&nbsp;<span translate>OK</span>
@@ -551,12 +551,18 @@
                           </span>
                         </td>
                       </tr>
                       <tr>
                         <th><span class="fas fa-fw fa-share-alt"></span>&nbsp;<span translate>Shared With</span></th>
-                        <td class="text-right">
-                          <span tooltip data-original-title="{{sharesFolder(folder)}} {{folderHasUnacceptedDevices(folder) ? '<br/>(<sup>1</sup>' + ('The remote device has not accepted sharing this folder.' | translate) + ')' : ''}} {{folderHasPausedDevices(folder) ? '<br/>(<sup>2</sup>' + ('The remote device has paused this folder.' | translate) + ')' : ''}}" ng-bind-html="sharesFolder(folder)"></span>
+                        <td class="text-right no-overflow-ellipse word-break-all">
+                          <span ng-repeat="device in folder.devices">
+                            <span ng-if="device.deviceID != myID" ng-switch="completion[device.deviceID][folder.id].remoteState">
+                              <span ng-switch-when="notSharing" data-original-title="{{'The remote device has not accepted sharing this folder.' | translate}}" tooltip>{{deviceName(devices[device.deviceID])}}<sup>1</sup><span ng-if="!$last">,</span></span>
+                              <span ng-switch-when="paused" data-original-title="{{'The remote device has paused this folder.' | translate}}" tooltip>{{deviceName(devices[device.deviceID])}}<sup>2</sup><span ng-if="!$last">,</span></span>
+                              <span ng-switch-default>{{deviceName(devices[device.deviceID])}}<span ng-if="!$last">,</span></span>
+                            </span>
+                          </span>
                         </td>
                       </tr>
                       <tr ng-if="folderStats[folder.id].lastScan">
                         <th><span class="far fa-fw fa-clock"></span>&nbsp;<span translate>Last Scan</span></th>
                         <td translate ng-if="folderStats[folder.id].lastScanDays >= 365" class="text-right">Never</td>
@@ -881,12 +887,18 @@
                         <th><span class="fas fa-fw fa-tag"></span>&nbsp;<span translate>Version</span></th>
                         <td class="text-right">{{connections[deviceCfg.deviceID].clientVersion}}</td>
                       </tr>
                       <tr ng-if="deviceFolders(deviceCfg).length > 0">
                         <th><span class="fas fa-fw fa-folder"></span>&nbsp;<span translate>Folders</span></th>
-                        <td class="text-right">
-                          <span tooltip data-original-title="{{sharedFolders(deviceCfg)}} {{deviceHasUnacceptedFolders(deviceCfg) ? '<br/>(<sup>1</sup>' + ('The remote device has not accepted sharing this folder.' | translate) + ')' : '' }} {{deviceHasPausedFolders(deviceCfg) ? '<br/>(<sup>2</sup>' + ('The remote device has paused this folder.' | translate) + ')' : '' }}" ng-bind-html="sharedFolders(deviceCfg)"></span>
+                        <td class="text-right no-overflow-ellipse word-break-all">
+                          <span ng-repeat="folderID in deviceFolders(deviceCfg)">
+                            <span ng-switch="completion[deviceCfg.deviceID][folderID].remoteState">
+                              <span ng-switch-when="notSharing" data-original-title="{{'The remote device has not accepted sharing this folder.' | translate}}" tooltip>{{folderLabel(folderID)}}<sup>1</sup><span ng-if="!$last">,</span></span>
+                              <span ng-switch-when="paused" data-original-title="{{'The remote device has paused this folder.' | translate}}" tooltip>{{folderLabel(folderID)}}<sup>2</sup><span ng-if="!$last">,</span></span>
+                              <span ng-switch-default>{{folderLabel(folderID)}}<span ng-if="!$last">,</span></span>
+                            </span>
+                          </span>
                         </td>
                       </tr>
                       <tr ng-if="deviceCfg.remoteGUIPort > 0">
                         <th><span class="fas fa-fw fa-desktop"></span>&nbsp;<span translate>Remote GUI</span></th>
                         <td class="text-right" ng-attr-title="Port {{deviceCfg.remoteGUIPort}}">
diff --git a/gui/default/syncthing/core/aboutModalView.html b/gui/default/syncthing/core/aboutModalView.html
index 46932f74f..b81a9291f 100644
--- a/gui/default/syncthing/core/aboutModalView.html
+++ b/gui/default/syncthing/core/aboutModalView.html
@@ -84,41 +84,41 @@ Jakob Borg, Audrius Butkevicius, Jesse Lucas, Simon Frei, Alexander Graf, Alexan
         <table class="table table-striped table-auto">
           <caption><label translate>Internally used paths:</label></caption>
           <tbody>
             <tr>
               <th translate>User Home</th>
-              <td><code class="file-path">{{ about.paths['baseDir-userHome'] }}</code></td>
+              <td><code class="word-break-all">{{ about.paths['baseDir-userHome'] }}</code></td>
             </tr>
             <tr>
               <th><strong translate>Configuration Directory</strong></th>
-              <td><code class="file-path"><strong>{{ about.paths['baseDir-config'] }}</strong></code></td>
+              <td><code class="word-break-all"><strong>{{ about.paths['baseDir-config'] }}</strong></code></td>
             </tr>
             <tr>
               <th translate>Configuration File</th>
-              <td><code class="file-path">{{ about.paths['config'] }}</code></td>
+              <td><code class="word-break-all">{{ about.paths['config'] }}</code></td>
             </tr>
             <tr>
               <th translate>Device Certificate</th>
-              <td><code class="file-path">{{ about.paths['certFile'] }}</code>
-                <br /><code class="file-path">{{ about.paths['keyFile'] }}</code></td>
+              <td><code class="word-break-all">{{ about.paths['certFile'] }}</code>
+                <br /><code class="word-break-all">{{ about.paths['keyFile'] }}</code></td>
             </tr>
             <tr>
               <th translate>GUI / API HTTPS Certificate</th>
-              <td><code class="file-path">{{ about.paths['httpsCertFile'] }}</code>
-                <br /><code class="file-path">{{ about.paths['httpsKeyFile'] }}</code></td>
+              <td><code class="word-break-all">{{ about.paths['httpsCertFile'] }}</code>
+                <br /><code class="word-break-all">{{ about.paths['httpsKeyFile'] }}</code></td>
             </tr>
             <tr>
               <th translate>Database Location</th>
-              <td><code class="file-path">{{ about.paths['database'] }}</code></td>
+              <td><code class="word-break-all">{{ about.paths['database'] }}</code></td>
             </tr>
             <tr>
               <th translate>Log File</th>
-              <td><code class="file-path">{{ about.paths['logFile'] }}</code></td>
+              <td><code class="word-break-all">{{ about.paths['logFile'] }}</code></td>
             </tr>
             <tr>
               <th translate>GUI Override Directory</th>
-              <td><code class="file-path">{{ about.paths['guiAssets'] }}</code></td>
+              <td><code class="word-break-all">{{ about.paths['guiAssets'] }}</code></td>
             </tr>
           </tbody>
         </table>
       </div>
 
diff --git a/gui/default/syncthing/core/editShareTemplate.html b/gui/default/syncthing/core/editShareTemplate.html
index c03bba16e..701451dde 100644
--- a/gui/default/syncthing/core/editShareTemplate.html
+++ b/gui/default/syncthing/core/editShareTemplate.html
@@ -1,9 +1,15 @@
 <div class="col-md-6 checkbox">
   <label for="sharedwith-{{id}}">
     <input id="sharedwith-{{id}}" ng-model="selected[id]" type="checkbox" />
-    <span tooltip data-original-title="{{id}}" ng-bind-html="label"></span>
+    <span tooltip data-original-title="{{id}}">
+      <span ng-switch="remoteState">
+        <span ng-switch-when="notSharing">{{label}}<sup>1</sup></span>
+        <span ng-switch-when="paused">{{label}}<sup>2</sup></span>
+        <span ng-switch-default>{{label}}</span>
+      </span>
+    </span>
   </label>
 </div>
 <div class="col-md-6">
   <div class="input-group">
     <span class="input-group-addon" ng-switch="folderType !== 'receiveencrypted' && !encryptionPasswords[id]">
diff --git a/gui/default/syncthing/core/syncthingController.js b/gui/default/syncthing/core/syncthingController.js
index 9be6a988b..20c3ec384 100755
--- a/gui/default/syncthing/core/syncthingController.js
+++ b/gui/default/syncthing/core/syncthingController.js
@@ -2450,34 +2450,10 @@ angular.module('syncthing.core')
         $scope.dismissPendingFolder = function (folderID, deviceID) {
             $http.delete(urlbase + '/cluster/pending/folders?folder=' + encodeURIComponent(folderID)
                          + '&device=' + encodeURIComponent(deviceID));
         };
 
-        $scope.deviceNameMarkRemoteState = function (deviceID, folderID) {
-            var name = $scope.deviceName($scope.devices[deviceID]);
-            // Add footnote if sharing was not accepted on the remote device
-            if (deviceID in $scope.completion && folderID in $scope.completion[deviceID]) {
-                if ($scope.completion[deviceID][folderID].remoteState == 'notSharing') {
-                    name += '<sup>1</sup>';
-                } else if ($scope.completion[deviceID][folderID].remoteState == 'paused') {
-                    name += '<sup>2</sup>';
-                }
-            }
-            return name;
-        };
-
-        $scope.sharesFolder = function (folderCfg) {
-            var names = [];
-            folderCfg.devices.forEach(function (device) {
-                if (device.deviceID !== $scope.myID) {
-                    names.push($scope.deviceNameMarkRemoteState(device.deviceID, folderCfg.id));
-                }
-            });
-            names.sort();
-            return names.join(", ");
-        };
-
         $scope.folderHasUnacceptedDevices = function (folderCfg) {
             for (var deviceID in $scope.completion) {
                 if (deviceID in $scope.devices
                     && folderCfg.id in $scope.completion[deviceID]
                     && $scope.completion[deviceID][folderCfg.id].remoteState == 'notSharing') {
@@ -2517,31 +2493,10 @@ angular.module('syncthing.core')
             }
             var label = $scope.folders[folderID].label;
             return label && label.length > 0 ? label : folderID;
         };
 
-        $scope.folderLabelMarkRemoteState = function (folderID, deviceID) {
-            var label = $scope.folderLabel(folderID);
-            // Add footnote if sharing was not accepted on the remote device
-            if (deviceID in $scope.completion && folderID in $scope.completion[deviceID]) {
-                if ($scope.completion[deviceID][folderID].remoteState == 'notSharing') {
-                    label += '<sup>1</sup>';
-                } else if ($scope.completion[deviceID][folderID].remoteState == 'paused') {
-                    label += '<sup>2</sup>';
-                }
-            }
-            return label;
-        };
-
-        $scope.sharedFolders = function (deviceCfg) {
-            var labels = [];
-            $scope.deviceFolders(deviceCfg).forEach(function (folderID) {
-                labels.push($scope.folderLabelMarkRemoteState(folderID, deviceCfg.deviceID));
-            });
-            return labels.join(', ');
-        };
-
         $scope.deviceHasUnacceptedFolders = function (deviceCfg) {
             if (!(deviceCfg.deviceID in $scope.completion)) {
                 return false;
             }
             for (var folderID in $scope.completion[deviceCfg.deviceID]) {
@@ -3427,10 +3382,11 @@ angular.module('syncthing.core')
                 selected: '=',
                 encryptionPasswords: '=',
                 id: '@',
                 label: '@',
                 folderType: '@',
+                remoteState: '@',
                 untrusted: '=',
             },
             link: function (scope, elem, attrs) {
                 var plain = false;
                 scope.togglePasswordVisibility = function() {
diff --git a/gui/default/syncthing/device/editDeviceModalView.html b/gui/default/syncthing/device/editDeviceModalView.html
index 11005313f..e74e1692c 100644
--- a/gui/default/syncthing/device/editDeviceModalView.html
+++ b/gui/default/syncthing/device/editDeviceModalView.html
@@ -90,11 +90,11 @@
                 <span translate>Deselect folders to stop sharing with this device.</span>&emsp;
                 <small><a href="#" ng-click="selectAllSharedFolders(true)" translate>Select All</a>&emsp;
                   <a href="#" ng-click="selectAllSharedFolders(false)" translate>Deselect All</a></small>
               </p>
               <div class="form-group" ng-repeat="folder in currentSharing.shared">
-                <share-template selected="currentSharing.selected" encryption-passwords="currentSharing.encryptionPasswords" id="{{folder.id}}" label="{{folderLabelMarkRemoteState(folder.id, currentDevice.deviceID)}}" folder-type="{{folder.type}}" untrusted="currentDevice.untrusted" />
+                <share-template selected="currentSharing.selected" encryption-passwords="currentSharing.encryptionPasswords" id="{{folder.id}}" label="{{folderLabel(folder.id)}}" folder-type="{{folder.type}}" untrusted="currentDevice.untrusted" remote-state="{{completion[currentDevice.deviceID][folder.id].remoteState}}" />
               </div>
               <p class="help-block" ng-if="deviceHasUnacceptedFolders(currentDevice)">
                 <sup>1</sup> <span translate>The remote device has not accepted sharing this folder.</span>
               </p>
               <p class="help-block" ng-if="deviceHasPausedFolders(currentDevice)">
diff --git a/gui/default/syncthing/device/globalChangesModalView.html b/gui/default/syncthing/device/globalChangesModalView.html
index d1dfb8e6d..77799eba1 100644
--- a/gui/default/syncthing/device/globalChangesModalView.html
+++ b/gui/default/syncthing/device/globalChangesModalView.html
@@ -26,11 +26,11 @@
               <span ng-switch-when="file" translate>file</span>
               <span ng-switch-when="folder" translate>folder</span>
               <span ng-switch-default>{{changeEvent.data.type}}</span>
             </td>
             <td class="no-overflow-ellipse">{{folderLabel(changeEvent.data.folder)}}</td>
-            <td class="file-path no-overflow-ellipse">{{changeEvent.data.path}}</td>
+            <td class="word-break-all no-overflow-ellipse">{{changeEvent.data.path}}</td>
             <td class="no-overflow-ellipse">{{changeEvent.time | date:"yyyy-MM-dd HH:mm:ss"}}</td>
           </tr>
         </tbody>
       </table>
     </div>
diff --git a/gui/default/syncthing/folder/editFolderModalView.html b/gui/default/syncthing/folder/editFolderModalView.html
index 6564479d0..deff5f7f9 100644
--- a/gui/default/syncthing/folder/editFolderModalView.html
+++ b/gui/default/syncthing/folder/editFolderModalView.html
@@ -54,11 +54,11 @@
               <span translate>Deselect devices to stop sharing this folder with.</span>&emsp;
               <small><a href="#" ng-click="selectAllSharedDevices(true)" translate>Select All</a>&emsp;
                 <a href="#" ng-click="selectAllSharedDevices(false)" translate>Deselect All</a></small>
             </p>
             <div class="form-group" ng-repeat="device in currentSharing.shared">
-              <share-template selected="currentSharing.selected" encryption-passwords="currentSharing.encryptionPasswords" id="{{device.deviceID}}" label="{{deviceNameMarkRemoteState(device.deviceID, currentFolder.id)}}" folder-type="{{currentFolder.type}}" untrusted="device.untrusted || pendingIsRemoteEncrypted(currentFolder.id, device.deviceID)" />
+              <share-template selected="currentSharing.selected" encryption-passwords="currentSharing.encryptionPasswords" id="{{device.deviceID}}" label="{{deviceName(device)}}" folder-type="{{currentFolder.type}}" untrusted="device.untrusted || pendingIsRemoteEncrypted(currentFolder.id, device.deviceID)" remote-state="{{completion[device.deviceID][currentFolder.id].remoteState}}" />
             </div>
             <p class="help-block" ng-if="folderHasUnacceptedDevices(currentFolder)">
               <sup>1</sup> <span translate>The remote device has not accepted sharing this folder.</span>
             </p>
             <p class="help-block" ng-if="folderHasPausedDevices(currentFolder)">
diff --git a/gui/default/syncthing/transfer/localChangedFilesModalView.html b/gui/default/syncthing/transfer/localChangedFilesModalView.html
index 2ca483163..b2a81ba20 100644
--- a/gui/default/syncthing/transfer/localChangedFilesModalView.html
+++ b/gui/default/syncthing/transfer/localChangedFilesModalView.html
@@ -13,11 +13,11 @@
           <th translate>Path</th>
           <th translate>Size</th>
         </tr>
       </thead>
       <tr dir-paginate="file in localChanged.files | itemsPerPage: localChanged.perpage" current-page="localChanged.page" total-items="model[localChangedFolder].receiveOnlyTotalItems" pagination-id="localChanged">
-        <td class="file-path">{{file.name}}</td>
+        <td class="word-break-all">{{file.name}}</td>
         <td><span ng-hide="file.type == 'DIRECTORY'">{{file.size | binary}}B</span></td>
       </tr>
     </table>
     <dir-pagination-controls on-page-change="refreshLocalChanged(newPageNumber, localChanged.perpage)" pagination-id="localChanged"></dir-pagination-controls>
     <ul class="pagination pull-right">
diff --git a/gui/default/syncthing/transfer/remoteNeededFilesModalView.html b/gui/default/syncthing/transfer/remoteNeededFilesModalView.html
index 0ad2a8b14..f2dfbd07e 100644
--- a/gui/default/syncthing/transfer/remoteNeededFilesModalView.html
+++ b/gui/default/syncthing/transfer/remoteNeededFilesModalView.html
@@ -20,11 +20,11 @@
                   <th><span tooltip data-original-title="{{'Time the item was last modified' | translate}}" translate>Mod. Time</span></th>
                   <th><span tooltip data-original-title="{{'Device that last modified the item' | translate}}" translate>Mod. Device</span></th>
                 </tr>
               </thead>
               <tr dir-paginate="file in remoteNeed[folder].files | itemsPerPage: remoteNeed[folder].perpage" current-page="remoteNeed[folder].page" total-items="completion[remoteNeedDevice.deviceID][folder].needItems" pagination-id="'remoteNeed-' + folder">
-                <td class="file-path">{{file.name}}</td>
+                <td class="word-break-all">{{file.name}}</td>
                 <td><span ng-hide="file.type == 'DIRECTORY'">{{file.size | binary}}B</span></td>
                 <td>{{file.modified | date:"yyyy-MM-dd HH:mm:ss"}}</td>
                 <td ng-if="file.modifiedBy">{{friendlyNameFromShort(file.modifiedBy)}}</td>
                 <td ng-if="!file.modifiedBy"><span translate>Unknown</span></td>
               </tr>

Vulnerable code: .file-path {
                <span ng-bind-html="friendlyDevices(err.message) | linky: '_blank'"></span>
                        <td class="text-right">
                          <span tooltip data-original-title="{{sharesFolder(folder)}} {{folderHasUnacceptedDevices(folder) ? '<br/>(<sup>1</sup>' + ('The remote device has not accepted sharing this folder.' | translate) + ')' : ''}} {{folderHasPausedDevices(folder) ? '<br/>(<sup>2</sup>' + ('The remote device has paused this folder.' | translate) + ')' : ''}}" ng-bind-html="sharesFolder(folder)"></span>
                        <td class="text-right">
                          <span tooltip data-original-title="{{sharedFolders(deviceCfg)}} {{deviceHasUnacceptedFolders(deviceCfg) ? '<br/>(<sup>1</sup>' + ('The remote device has not accepted sharing this folder.' | translate) + ')' : '' }} {{deviceHasPausedFolders(deviceCfg) ? '<br/>(<sup>2</sup>' + ('The remote device has paused this folder.' | translate) + ')' : '' }}" ng-bind-html="sharedFolders(deviceCfg)"></span>
              <td><code class="file-path">{{ about.paths['baseDir-userHome'] }}</code></td>
              <td><code class="file-path"><strong>{{ about.paths['baseDir-config'] }}</strong></code></td>
              <td><code class="file-path">{{ about.paths['config'] }}</code></td>
              <td><code class="file-path">{{ about.paths['certFile'] }}</code>
                <br /><code class="file-path">{{ about.paths['keyFile'] }}</code></td>
              <td><code class="file-path">{{ about.paths['httpsCertFile'] }}</code>
                <br /><code class="file-path">{{ about.paths['httpsKeyFile'] }}</code></td>
              <td><code class="file-path">{{ about.paths['database'] }}</code></td>
              <td><code class="file-path">{{ about.paths['logFile'] }}</code></td>
              <td><code class="file-path">{{ about.paths['guiAssets'] }}</code></td>
    <span tooltip data-original-title="{{id}}" ng-bind-html="label"></span>
        $scope.deviceNameMarkRemoteState = function (deviceID, folderID) {
            var name = $scope.deviceName($scope.devices[deviceID]);
            // Add footnote if sharing was not accepted on the remote device
            if (deviceID in $scope.completion && folderID in $scope.completion[deviceID]) {
                if ($scope.completion[deviceID][folderID].remoteState == 'notSharing') {
                    name += '<sup>1</sup>';
                } else if ($scope.completion[deviceID][folderID].remoteState == 'paused') {
                    name += '<sup>2</sup>';
                }
            }
            return name;
        };

        $scope.sharesFolder = function (folderCfg) {
            var names = [];
            folderCfg.devices.forEach(function (device) {
                if (device.deviceID !== $scope.myID) {
                    names.push($scope.deviceNameMarkRemoteState(device.deviceID, folderCfg.id));
                }
            });
            names.sort();
            return names.join(", ");
        };

        $scope.folderLabelMarkRemoteState = function (folderID, deviceID) {
            var label = $scope.folderLabel(folderID);
            // Add footnote if sharing was not accepted on the remote device
            if (deviceID in $scope.completion && folderID in $scope.completion[deviceID]) {
                if ($scope.completion[deviceID][folderID].remoteState == 'notSharing') {
                    label += '<sup>1</sup>';
                } else if ($scope.completion[deviceID][folderID].remoteState == 'paused') {
                    label += '<sup>2</sup>';
                }
            }
            return label;
        };

        $scope.sharedFolders = function (deviceCfg) {
            var labels = [];
            $scope.deviceFolders(deviceCfg).forEach(function (folderID) {
                labels.push($scope.folderLabelMarkRemoteState(folderID, deviceCfg.deviceID));
            });
            return labels.join(', ');
        };

                <share-template selected="currentSharing.selected" encryption-passwords="currentSharing.encryptionPasswords" id="{{folder.id}}" label="{{folderLabelMarkRemoteState(folder.id, currentDevice.deviceID)}}" folder-type="{{folder.type}}" untrusted="currentDevice.untrusted" />
            <td class="file-path no-overflow-ellipse">{{changeEvent.data.path}}</td>
              <share-template selected="currentSharing.selected" encryption-passwords="currentSharing.encryptionPasswords" id="{{device.deviceID}}" label="{{deviceNameMarkRemoteState(device.deviceID, currentFolder.id)}}" folder-type="{{currentFolder.type}}" untrusted="device.untrusted || pendingIsRemoteEncrypted(currentFolder.id, device.deviceID)" />
        <td class="file-path">{{file.name}}</td>
                <td class="file-path">{{file.name}}</td>
Fixed code: .word-break-all {
                <span ng-bind="friendlyDevices(err.message)"></span>
                        <td class="text-right no-overflow-ellipse word-break-all">
                          <span ng-repeat="device in folder.devices">
                            <span ng-if="device.deviceID != myID" ng-switch="completion[device.deviceID][folder.id].remoteState">
                              <span ng-switch-when="notSharing" data-original-title="{{'The remote device has not accepted sharing this folder.' | translate}}" tooltip>{{deviceName(devices[device.deviceID])}}<sup>1</sup><span ng-if="!$last">,</span></span>
                              <span ng-switch-when="paused" data-original-title="{{'The remote device has paused this folder.' | translate}}" tooltip>{{deviceName(devices[device.deviceID])}}<sup>2</sup><span ng-if="!$last">,</span></span>
                              <span ng-switch-default>{{deviceName(devices[device.deviceID])}}<span ng-if="!$last">,</span></span>
                            </span>
                          </span>
                        <td class="text-right no-overflow-ellipse word-break-all">
                          <span ng-repeat="folderID in deviceFolders(deviceCfg)">
                            <span ng-switch="completion[deviceCfg.deviceID][folderID].remoteState">
                              <span ng-switch-when="notSharing" data-original-title="{{'The remote device has not accepted sharing this folder.' | translate}}" tooltip>{{folderLabel(folderID)}}<sup>1</sup><span ng-if="!$last">,</span></span>
                              <span ng-switch-when="paused" data-original-title="{{'The remote device has paused this folder.' | translate}}" tooltip>{{folderLabel(folderID)}}<sup>2</sup><span ng-if="!$last">,</span></span>
                              <span ng-switch-default>{{folderLabel(folderID)}}<span ng-if="!$last">,</span></span>
                            </span>
                          </span>
              <td><code class="word-break-all">{{ about.paths['baseDir-userHome'] }}</code></td>
              <td><code class="word-break-all"><strong>{{ about.paths['baseDir-config'] }}</strong></code></td>
              <td><code class="word-break-all">{{ about.paths['config'] }}</code></td>
              <td><code class="word-break-all">{{ about.paths['certFile'] }}</code>
                <br /><code class="word-break-all">{{ about.paths['keyFile'] }}</code></td>
              <td><code class="word-break-all">{{ about.paths['httpsCertFile'] }}</code>
                <br /><code class="word-break-all">{{ about.paths['httpsKeyFile'] }}</code></td>
              <td><code class="word-break-all">{{ about.paths['database'] }}</code></td>
              <td><code class="word-break-all">{{ about.paths['logFile'] }}</code></td>
              <td><code class="word-break-all">{{ about.paths['guiAssets'] }}</code></td>
    <span tooltip data-original-title="{{id}}">
      <span ng-switch="remoteState">
        <span ng-switch-when="notSharing">{{label}}<sup>1</sup></span>
        <span ng-switch-when="paused">{{label}}<sup>2</sup></span>
        <span ng-switch-default>{{label}}</span>
      </span>
    </span>
                remoteState: '@',
                <share-template selected="currentSharing.selected" encryption-passwords="currentSharing.encryptionPasswords" id="{{folder.id}}" label="{{folderLabel(folder.id)}}" folder-type="{{folder.type}}" untrusted="currentDevice.untrusted" remote-state="{{completion[currentDevice.deviceID][folder.id].remoteState}}" />
            <td class="word-break-all no-overflow-ellipse">{{changeEvent.data.path}}</td>
              <share-template selected="currentSharing.selected" encryption-passwords="currentSharing.encryptionPasswords" id="{{device.deviceID}}" label="{{deviceName(device)}}" folder-type="{{currentFolder.type}}" untrusted="device.untrusted || pendingIsRemoteEncrypted(currentFolder.id, device.deviceID)" remote-state="{{completion[device.deviceID][currentFolder.id].remoteState}}" />
        <td class="word-break-all">{{file.name}}</td>
                <td class="word-break-all">{{file.name}}</td>