CVE-2018-12457 (JavaScript, published 2018-06-15T14:29Z)
Description: value: expressCart before 1.1.6 allows remote attackers to create an admin user via a /admin/setup Referer header.
Severity: MEDIUM (CVSS v3 base score: 8.8)
Weakness: CWE-732 \u2014 Incorrect Permission Assignment for Critical Resource
The product specifies permissions for a security-critical resource in a way that allows that resource to be read or modified by unintended actors.
Repository: https://github.com/mrvautin/expressCart
Files changed:
routes/user.js
Commit message: Fix issue with ability to create admin user by setting referrer


Vulnerable code:
    let isAdmin = false;
    if(urlParts.path === '/admin/setup'){
        isAdmin = true;
    }
    let doc = {
        usersName: req.body.usersName,
        userEmail: req.body.userEmail,
        userPassword: bcrypt.hashSync(req.body.userPassword, 10),
        isAdmin: isAdmin
    };

    // check for existing user
    db.users.findOne({'userEmail': req.body.userEmail}, (err, user) => {
        if(user){
            // user already exists with that email address
            console.error(colors.red('Failed to insert user, possibly already exists: ' + err));
            req.session.message = 'A user with that email address already exists';
            req.session.messageType = 'danger';
            res.redirect('/admin/user/new');
            return;
        // email is ok to be used.
        db.users.insert(doc, (err, doc) => {
            // show the view
            if(err){
                if(doc){
                    console.error(colors.red('Failed to insert user: ' + err));
                    req.session.message = 'User exists';
                    req.session.messageType = 'danger';
                    res.redirect('/admin/user/edit/' + doc._id);
                    return;
                }
                console.error(colors.red('Failed to insert user: ' + err));
                req.session.message = 'New user creation failed';
            req.session.message = 'User account inserted';
            req.session.messageType = 'success';

            // if from setup we add user to session and redirect to login.
            // Otherwise we show users screen
            if(urlParts.path === '/admin/setup'){
                req.session.user = req.body.userEmail;
                res.redirect('/admin/login');
                return;
            }
            res.redirect('/admin/users');

Fixed code:
    // Check number of users
    db.users.count({}, (err, userCount) => {
        let isAdmin = false;
        // if no users, setup user as admin
        if(userCount === 0){
            isAdmin = true;

        let doc = {
            usersName: req.body.usersName,
            userEmail: req.body.userEmail,
            userPassword: bcrypt.hashSync(req.body.userPassword, 10),
            isAdmin: isAdmin
        };

        // check for existing user
        db.users.findOne({'userEmail': req.body.userEmail}, (err, user) => {
            if(user){
                // user already exists with that email address
                console.error(colors.red('Failed to insert user, possibly already exists: ' + err));
                req.session.message = 'A user with that email address already exists';
            // email is ok to be used.
            db.users.insert(doc, (err, doc) => {
                // show the view
                if(err){
                    if(doc){
                        console.error(colors.red('Failed to insert user: ' + err));
                        req.session.message = 'User exists';
                        req.session.messageType = 'danger';
                        res.redirect('/admin/user/edit/' + doc._id);
                        return;
                    }
                    console.error(colors.red('Failed to insert user: ' + err));
                    req.session.message = 'New user creation failed';
                    req.session.messageType = 'danger';
                    res.redirect('/admin/user/new');
                    return;
                }
                req.session.message = 'User account inserted';
                req.session.messageType = 'success';

                // if from setup we add user to session and redirect to login.
                // Otherwise we show users screen
                if(urlParts.path === '/admin/setup'){
                    req.session.user = req.body.userEmail;
                    res.redirect('/admin/login');
                    return;
                }
                res.redirect('/admin/users');
            });