CVE-2009-10002: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79)
value: A vulnerability, which was classified as problematic, has been found in dpup fittr-flickr. This issue affects some unknown processing of the file fittr-flickr/features/easy-exif.js of the component EXIF Preview Handler. The manipulation leads to cross site scripting. The attack may be initiated remotely. The identifier of the patch is 08875dd8a2e5d0d16568bb0d67cb4328062fccde. It is recommended to apply a patch to fix this issue. The identifier VDB-218297 was assigned to this vulnerability.
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: 6.1
Published: 2023-01-13T18:15Z
Repository: https://github.com/dpup/fittr-flickr
Language: JavaScript
Files changed: fittr-flickr/api_relay.html, fittr-flickr/features/easy-exif.js, fittr-flickr/utils/dom.js
Commit date: 2009-11-04 02:45:57 +0000
Commit message: A couple of potential security fixes.  Stop using innerHTML when building the EXIF preview, in theory someone could add malicious EXIF data and XSS.  Also, use JSON.parse instead of eval() to protect against MITM attacks.
Diff: diff --git a/fittr-flickr/api_relay.html b/fittr-flickr/api_relay.html
index 534f831..c9c6780 100644
--- a/fittr-flickr/api_relay.html
+++ b/fittr-flickr/api_relay.html
@@ -52,11 +52,11 @@ function makeRequest(port, type, params) {
   xhr.onreadystatechange = function() {
     if (xhr.readyState == 4) {
       var status = xhr.status;
       var response, err = '';
       try {
-        response = eval('(' + xhr.responseText + ')');
+        response = JSON.parse(xhr.responseText);
       } catch (e) {
         status = -1;
         err = e.message;
       }
       var responseObject = {
diff --git a/fittr-flickr/features/easy-exif.js b/fittr-flickr/features/easy-exif.js
index fd03920..931577c 100644
--- a/fittr-flickr/features/easy-exif.js
+++ b/fittr-flickr/features/easy-exif.js
@@ -63,28 +63,39 @@ var exif = (function() {
       el.id = 'fittr-exif-dislay';
       el.innerHTML = '<i>Loading</i>';
       link.parentNode.parentNode.insertBefore(el, link.parentNode.nextSibling);
 
       api.makeApiRequest(api.RequestType.GET_EXIF, {photo_id: page.getPhotoId()}, function(data) {
+        el.innerHTML = '';
         if (data.status == 200 && data.content.stat == 'ok') {
-          var html = '<table class="fittr-exif-table">';
+          var table = createEl('table', 'fittr-exif-table');
           var seen = {};
           for (var i = 0; i < data.content.photo.exif.length; i++) {
             var item = data.content.photo.exif[i];
             if (item.tag in EXIF_TAG_WHITELIST && !(item.tag in seen)) {
               seen[item.tag] = 1;
               var value = item.clean ? item.clean._content : item.raw._content;
-              html += '<tr><td>' + item.label + '</td><td>' + value + '</td></tr>';
+              var tr = createEl('tr');
+              var td1 = createEl('td');
+              td1.appendChild(createText(item.label));
+              tr.appendChild(td1);
+              var td2 = createEl('td');
+              td2.appendChild(createText(value));
+              tr.appendChild(td2);
+              table.appendChild(tr);
             }
           }
-          html += '</table>';
-          el.innerHTML = html;
-        } else if (data.status == 200 && data.content.stat == 'fail') {
-          el.innerHTML = '<i>Error loading EXIF : ' + data.content.message + '</i>';
+          el.appendChild(table);
         } else {
-          el.innerHTML = '<i>Error loading EXIF.</i>';
-        }
+          var error = createEl('i');
+          if (data.status == 200 && data.content.stat == 'fail') {
+            error.appendChild(createText('Error loading EXIF : ' + data.content.message));
+          } else {
+            error.appendChild(createText('Error loading EXIF, status: ' + data.status));
+          }
+          el.appendChild(error);
+        }  
         el.style.height = el.scrollHeight + 'px';
       });
     }
     return el;
   }
diff --git a/fittr-flickr/utils/dom.js b/fittr-flickr/utils/dom.js
index 61fba1d..d292f58 100644
--- a/fittr-flickr/utils/dom.js
+++ b/fittr-flickr/utils/dom.js
@@ -20,12 +20,14 @@
 
 function createText(txt) {
   return document.createTextNode(txt); 
 }
 
-function createEl(el) {
-  return document.createElement(el); 
+function createEl(el, opt_className) {
+  var el = document.createElement(el); 
+  if (opt_className) el.className = opt_className;
+  return el;
 }
 
 function getEl(id) {
   return document.getElementById(id);
 }

Vulnerable code:         response = eval('(' + xhr.responseText + ')');
          var html = '<table class="fittr-exif-table">';
              html += '<tr><td>' + item.label + '</td><td>' + value + '</td></tr>';
          html += '</table>';
          el.innerHTML = html;
        } else if (data.status == 200 && data.content.stat == 'fail') {
          el.innerHTML = '<i>Error loading EXIF : ' + data.content.message + '</i>';
          el.innerHTML = '<i>Error loading EXIF.</i>';
        }
function createEl(el) {
  return document.createElement(el); 
Fixed code:         response = JSON.parse(xhr.responseText);
        el.innerHTML = '';
          var table = createEl('table', 'fittr-exif-table');
              var tr = createEl('tr');
              var td1 = createEl('td');
              td1.appendChild(createText(item.label));
              tr.appendChild(td1);
              var td2 = createEl('td');
              td2.appendChild(createText(value));
              tr.appendChild(td2);
              table.appendChild(tr);
          el.appendChild(table);
          var error = createEl('i');
          if (data.status == 200 && data.content.stat == 'fail') {
            error.appendChild(createText('Error loading EXIF : ' + data.content.message));
          } else {
            error.appendChild(createText('Error loading EXIF, status: ' + data.status));
          }
          el.appendChild(error);
        }  
function createEl(el, opt_className) {
  var el = document.createElement(el); 
  if (opt_className) el.className = opt_className;
  return el;