CVE-2020-36621: 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 chedabob whatismyudid. Affected by this issue is the function exports.enrollment of the file routes/mobileconfig.js. The manipulation leads to cross site scripting. The attack may be launched remotely. The name of the patch is bb33d4325fba80e7ea68b79121dba025caf6f45f. It is recommended to apply a patch to fix this issue. VDB-216470 is the identifier 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: 2022-12-21T19:15Z
Repository: https://github.com/chedabob/whatismyudid
Language: JavaScript
Files changed: app.js, routes/mobileconfig.js
Commit date: 2020-09-30 23:03:58 +0100
Commit message: fix: set cookie securely, and prevent XSS in the `/enrollment` route

Diff: diff --git a/app.js b/app.js
index 1104156..9c3d506 100644
--- a/app.js
+++ b/app.js
@@ -16,11 +16,10 @@ var app = express();
 // all environments
 app.set('port', process.env.PORT || 3001);
 app.set('views', __dirname + '/views');
 app.set('view engine', 'pug');
 
-app.use(express.urlencoded({extended: true})); 
 app.use(cookieParser(process.env.COOKIE_KEY || 'f76210bc2acc4f54af5754e15b0aab05'));
 app.use(express.static(path.join(__dirname, 'public')));
 app.use(express.raw({
   'type' : 'application/pkcs7-signature'
 }))
diff --git a/routes/mobileconfig.js b/routes/mobileconfig.js
index 06aceb7..913f1c7 100644
--- a/routes/mobileconfig.js
+++ b/routes/mobileconfig.js
@@ -8,34 +8,50 @@ exports.enrollment = function(req, res){
     var url = require('url');
     var url_parts = url.parse(req.url, true);
     var query = url_parts.query;
     
     var tudid = query.udid;
-    if (tudid) // If it's in the query, store it and redirect (so the user doesn't see the UDID being sent in the URL)
+    if (tudid && extractValidUdid(tudid)) // If it's in the query, store it and redirect (so the user doesn't see the UDID being sent in the URL)
     {
-        res.cookie('newudid', query.udid, { maxAge: 10 * 60 * 1000});     // Store for 10 minutes
+        res.cookie('newudid', query.udid, 
+        { 
+            maxAge: 10 * 60 * 1000,
+            httpOnly: true,
+            secure: process.env.NODE_ENV === 'production'? true: false
+        });
         res.redirect('/enrollment');
     }
     else
     {
         var cookie = req.cookies.newudid;
-        if (cookie) {
+        if (cookie && extractValidUdid(cookie)) {
             // Found the cookie, let's render it
             res.render('udid', { udid: cookie, title: 'udid.fyi'});
         }
         else {
             // No cookie, redirect back to home page
             res.redirect('/');
         }
     }
 }
 exports.enroll = function(req, res){
-    var match = req.body.toString().match(/(0000[\d]{4}-00[A-Fa-f\d]+)|([a-fA-F\d]{40})/);
+    var udid = extractValidUdid(req.body.toString())
 
-    if (match && match.length > 0) {
-        res.redirect(301,'/enrollment?udid=' + match[0]);
+    if (udid) {
+        res.redirect(301,'/enrollment?udid=' + udid);
     }
     else {
         res.status(400)
         res.send('Did not find a valid UDID in the body')
     }
 };
+
+function extractValidUdid (udid) {
+    const match = udid.match(/(0000[\d]{4}-00[A-Fa-f\d]+)|([a-fA-F\d]{40})/);
+
+    if (match && match.length > 0) {
+        return match[0]
+    }
+    else {
+        return null
+    }
+}

Vulnerable code: app.use(express.urlencoded({extended: true})); 
    if (tudid) // If it's in the query, store it and redirect (so the user doesn't see the UDID being sent in the URL)
        res.cookie('newudid', query.udid, { maxAge: 10 * 60 * 1000});     // Store for 10 minutes
        if (cookie) {
    var match = req.body.toString().match(/(0000[\d]{4}-00[A-Fa-f\d]+)|([a-fA-F\d]{40})/);
    if (match && match.length > 0) {
        res.redirect(301,'/enrollment?udid=' + match[0]);
Fixed code:     if (tudid && extractValidUdid(tudid)) // If it's in the query, store it and redirect (so the user doesn't see the UDID being sent in the URL)
        res.cookie('newudid', query.udid, 
        { 
            maxAge: 10 * 60 * 1000,
            httpOnly: true,
            secure: process.env.NODE_ENV === 'production'? true: false
        });
        if (cookie && extractValidUdid(cookie)) {
    var udid = extractValidUdid(req.body.toString())
    if (udid) {
        res.redirect(301,'/enrollment?udid=' + udid);

function extractValidUdid (udid) {
    const match = udid.match(/(0000[\d]{4}-00[A-Fa-f\d]+)|([a-fA-F\d]{40})/);

    if (match && match.length > 0) {
        return match[0]
    }
    else {
        return null
    }
}