CVE-2020-7778 (JavaScript, published 2020-11-26T11:15Z)
Description: value: This affects the package systeminformation before 4.30.2. The attacker can overwrite the properties and functions of an object, which can lead to executing OS commands.
Severity: HIGH (CVSS v3 base score: 7.3)
Weakness: CWE-78 \u2014 Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')
The product constructs all or part of an OS command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended OS command when it is sent to a downstream component.
Repository: https://github.com/sebhildebrandt/systeminformation
Files changed:
CHANGELOG.md
docs/history.html
docs/index.html
lib/internet.js
lib/network.js
lib/processes.js
lib/util.js
Commit message: security update (prototype pollution prevention)


Vulnerable code:
      <div class="version">Current Version: <span id="version">4.30.0</span></div>

      let urlSanitized = util.sanitizeShellString(url).toLowerCase();
      urlSanitized = urlSanitized.replace(/ /g, '');
      urlSanitized = urlSanitized.replace(/\$/g, '');
      urlSanitized = urlSanitized.replace(/\(/g, '');
      urlSanitized = urlSanitized.replace(/\)/g, '');
      urlSanitized = urlSanitized.replace(/{/g, '');
      urlSanitized = urlSanitized.replace(/}/g, '');
      if (urlSanitized) {
  const hostSanitized = util.sanitizeShellString(host);
      const ifaceSanitized = util.sanitizeShellString(iface);
      const procSanitized = util.sanitizeShellString(proc);
  let result = str || '';
  result = result.replace(/>/g, '');
  result = result.replace(/</g, '');
  result = result.replace(/\*/g, '');
  result = result.replace(/\?/g, '');
  result = result.replace(/\[/g, '');
  result = result.replace(/\]/g, '');
  result = result.replace(/\|/g, '');
  result = result.replace(/\`/g, '');
  result = result.replace(/\$/g, '');
  result = result.replace(/;/g, '');
  result = result.replace(/&/g, '');
  result = result.replace(/\)/g, '');
  result = result.replace(/\(/g, '');
  result = result.replace(/\$/g, '');
  result = result.replace(/#/g, '');
  result = result.replace(/\\/g, '');
  result = result.replace(/\t/g, '');
  result = result.replace(/\n/g, '');
  result = result.replace(/\"/g, '');

Fixed code:
| 4.30.2         | 2020-11-25     | security update (prototype pollution prevention) |
| 4.30.1         | 2020-11-12     | updated docs |
                  <tr>
                    <th scope="row">4.30.2</th>
                    <td>2020-11-25</td>
                    <td>security update (prototype pollution prevention)</td>
                  </tr>
                  <tr>
                    <th scope="row">4.30.1</th>
                    <td>2020-11-12</td>
                    <td>updated docs</td>
                  </tr>
      <div class="version">Current Version: <span id="version">4.30.2</span></div>
      let urlSanitized = '';
      const s = util.sanitizeShellString(url);
      for (i = 0; i <= 2000; i++) {
        if (!(s[i] === undefined ||
          s[i] === ' ' ||
          s[i] === '{' ||
          s[i] === '}')) {
          const sl = s[i].toLowerCase();
          if (sl[0] && !sl[1]) {
            urlSanitized = urlSanitized + sl[i];
          }
        }
      }
      if (urlSanitized && !util.isPrototypePolluted()) {
  const hostSanitized = util.isPrototypePolluted() ? '8.8.8.8' : util.sanitizeShellString(host);
      const ifaceSanitized = util.isPrototypePolluted() ? '---' : util.sanitizeShellString(iface);
        if (util.isPrototypePolluted() && srvString !== '*') {
          srvString = '------';
        }
      const procSanitized = util.isPrototypePolluted() ? '' : util.sanitizeShellString(proc);
  const s = str || '';
  let result = '';
  for (i = 0; i <= 2000; i++) {
    if (!(s[i] === undefined ||
      s[i] === '>' ||
      s[i] === '<' ||
      s[i] === '*' ||
      s[i] === '?' ||
      s[i] === '[' ||
      s[i] === ']' ||
      s[i] === '|' ||
      s[i] === '˚' ||
      s[i] === '$' ||
      s[i] === ';' ||
      s[i] === '&' ||
      s[i] === '(' ||
      s[i] === ')' ||
      s[i] === ']' ||
      s[i] === '#' ||
      s[i] === '\\' ||
      s[i] === '\t' ||
      s[i] === '\n' ||
      s[i] === '"')) {
      result = result + s[i];
    }
  }
function isPrototypePolluted() {
  s = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
  let notPolluted = true;
  let st = '';
  notPolluted = notPolluted || !(s.length === 62)
  const ms = Date.now();
  if (typeof ms === 'number' && ms > 1600000000000) {
    const l = ms % 100 + 15;
    let c = 0;
    for (i = 0; i < l; i++) {
      const r = Math.random() * 61.99999999 + 1;
      const rs = parseInt(Math.floor(r).toString(), 10)
      const rs2 = parseInt(r.toString().split('.')[0], 10);
      const q = Math.random() * 61.99999999 + 1;
      const qs = parseInt(Math.floor(q).toString(), 10)
      const qs2 = parseInt(q.toString().split('.')[0], 10);
      notPolluted = notPolluted && !(r === q);
      notPolluted = notPolluted && rs === rs2 && qs === qs2;
      st += s[rs - 1];
    }
    notPolluted = notPolluted && st.length === l;
    // string manipulation
    let p = Math.random() * l * 0.9999999999;
    let stm = st.substr(0, p) + ' ' + st.substr(p, 2000);
    let sto = stm.replace(/ /g, '');
    notPolluted = notPolluted && st === sto;
    p = Math.random() * l * 0.9999999999;
    stm = st.substr(0, p) + '{' + st.substr(p, 2000);
    sto = stm.replace(/{/g, '');
    notPolluted = notPolluted && st === sto;
    p = Math.random() * l * 0.9999999999;
    stm = st.substr(0, p) + '*' + st.substr(p, 2000);
    sto = stm.replace(/\*/g, '');
    notPolluted = notPolluted && st === sto;
    p = Math.random() * l * 0.9999999999;
    stm = st.substr(0, p) + '$' + st.substr(p, 2000);
    sto = stm.replace(/\$/g, '');
    notPolluted = notPolluted && st === sto;

    // lower
    const stl = st.toLowerCase();
    notPolluted = notPolluted && (stl.length === l) && stl[l - 1] && !(stl[l])
    for (i = 0; i < l; i++) {
      const s1 = st[i];
      const s2 = stl[i];
      const s1l = s1.toLowerCase();
      notPolluted = notPolluted && s1l[0] === s2 && s1l[0] && !(s1l[1]);
    }
  }
  return !notPolluted;
}

exports.isPrototypePolluted = isPrototypePolluted;