diff --git a/commands/report.js b/commands/report.js
index d1dae3f..b17b1e6 100644
--- a/commands/report.js
+++ b/commands/report.js
@@ -14,6 +14,7 @@ const {
 } = require('../lib/report/util')
 const longReport = require('../lib/report/long')
 const shortReport = require('../lib/report/short')
+const htmlReport = require('../lib/report/html')
 const { helpHeader } = require('../lib/help')
 const {
   COLORS,
@@ -30,7 +31,8 @@ module.exports.optionsList = optionsList
 
 async function report (argv, _dir) {
   const {
-    long
+    long,
+    html
   } = argv
   let { dir = _dir } = argv
   if (!dir) dir = process.cwd()
@@ -162,6 +164,7 @@ async function report (argv, _dir) {
 
   if (!long) shortReport(pkgScores, whitelisted, dir, argv)
   if (long) longReport(pkgScores, whitelisted, dir, argv)
+  if (html) htmlReport(pkgScores, whitelisted, dir, html, argv)
   if (hasFailures) process.exitCode = 1
 }
 
diff --git a/lib/report/html-template.js b/lib/report/html-template.js
new file mode 100644
index 0000000..77e3f3b
--- /dev/null
+++ b/lib/report/html-template.js
@@ -0,0 +1,256 @@
+'use strict'
+
+const {
+  filterVulns,
+  SEVERITY_RMAP
+} = require('./util')
+
+module.exports = renderHTML
+
+function renderHTML (title, summary, report, reportLength, whitelist, whitelistLength, formattedFilterOptions) {
+  const { riskCount, securityCount, insecureModules, complianceCount } = summary
+
+  let alternate = false
+  let whitelistInfo = ''
+  for (const pkg of whitelist) {
+    whitelistInfo += segment(pkg)
+  }
+
+  alternate = false
+  let pkgInfo = ''
+  for (const pkg of report) {
+    pkgInfo += segment(pkg)
+  }
+
+  function segment (pkg) {
+    const { name, version, maxSeverity, failures, license } = pkg
+    const pkgVulns = filterVulns(failures).map((v, i) => v !== 0
+      ? `<p class="${['light1', 'yellow', 'orange', 'red'][i]}">
+          ${v}&nbsp;${['Low', 'Medium', 'High', 'Critical'][i]}
+        </p>`
+      : ''
+    )
+    const pkgLicense = license && license.data && license.data.spdx ? license.data.spdx : 'UNKNOWN'
+    const pkgLicensePass = license && license.pass === true
+    const pkgSeverity = `
+    <p>
+      <span class="${['light1', 'white', 'yellow', 'orange', 'red'][maxSeverity]}">
+        ${['', '|&nbsp;', '|&nbsp;|&nbsp;', '|&nbsp;|&nbsp;|&nbsp;', '|&nbsp;|&nbsp;|&nbsp;|'][maxSeverity]}</span
+      >${['|&nbsp;|&nbsp;|&nbsp;|', '|&nbsp;|&nbsp;|', '|&nbsp;|', '|', ''][maxSeverity]}&nbsp;&nbsp;${SEVERITY_RMAP[maxSeverity]}
+    </p>`
+
+    alternate = !alternate
+    return `
+    <tr class="module-element" ${alternate ? 'style="background:#2e3535"' : ''}>
+      <td>
+        <p><span class="white">${name}</span>@${version}</p>
+      </td>
+      <td>
+        <p>${pkgSeverity}</p>
+      <td>
+        <p>
+          <span class="${pkgLicensePass ? 'green">✓' : 'red">X'}</span>&nbsp;${pkgLicense}
+        </p>
+      </td>
+      <td>
+        <p>
+    ${pkgVulns.join('').length === 0
+    ? '<span class="green">✓</span>&nbsp;0'
+    : pkgVulns.reverse().join(' ')}
+        </p>
+      </td>
+    </tr>
+    `
+  }
+
+  const template = `
+  <!DOCTYPE html>
+  <html lang="en">
+    <meta charset="utf-8">
+    <head>
+      <title>NCM Report > ${title}</title>
+      <link href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:200,400&display=swap" rel="stylesheet">
+      <style>
+        body {
+          padding: 2%;
+          color: #89a19d;
+          font-family: 'Source Sans Pro', Helvetica;
+          font-weight: 400;
+        }
+        a {
+          color: #5ac878;
+          text-decoration: none;
+        }
+        p {
+          margin: 0;
+        }
+        td {
+          padding-top: 3px;
+          padding-bottom: 3px;
+          padding-left: 10px;
+          padding-right: 10px;
+        }
+        th {
+          text-align: left;
+        }
+        table {
+          width: 100%;
+        }
+        .title {
+          font-size: 28pt;
+          color:#e1e7e6;
+        }
+        .subtitle {
+          font-size: 20pt;
+          color: #e1e7e6;
+        }
+        .module-element {
+          margin: 4px;
+        }
+        .bottom-20 {
+          margin-bottom: 20px;
+        }
+        .left-20 {
+          margin-left: 20px;
+        }
+        .white {
+          color: #e1e7e6;
+        }
+        .light1 {
+          color: #89a19d;
+        }
+        .yellow {
+          color: #ffb726;
+        }
+        .orange {
+          color: #ff8b40;
+        }
+        .red {
+          color: #ff6040;
+        }
+        .green {
+          color: #5ac878;
+        }
+      </style>
+    </head>
+    <body style="background: #202525">
+
+      <div id="ns-branding" class="bottom-20">
+        <svg xmlns="http://www.w3.org/2000/svg" height="50" width="auto" viewBox="0 0 100 100">
+          <path d="M89.243 20.864L55.642 1.5a11.21 11.21 0 0 0-11.2 0L10.778 20.937a11.208 11.208 0 0 0-5.6 9.7l-.032 38.781a11.2 11.2 0 0 0 5.611 9.718L44.359 98.5a11.208 11.208 0 0 0 11.2 0l33.663-19.437a11.206 11.206 0 0 0 5.6-9.7l.028-38.784a11.2 11.2 0 0 0-5.607-9.715zM46.36 4.823a7.338 7.338 0 0 1 1.723-.718v16.552a1.917 1.917 0 0 0 3.834 0V4.079a7.369 7.369 0 0 1 1.81.741l33.6 19.366a7.322 7.322 0 0 1 1.522 1.169L68.486 37.113a22.518 22.518 0 0 0-36.983.014L11.186 25.418a7.329 7.329 0 0 1 1.51-1.16zM68.713 50a18.74 18.74 0 0 1-16.8 18.616V51.107l15.149-8.746A18.579 18.579 0 0 1 68.713 50zm-35.785-7.626l15.155 8.734v17.508a18.679 18.679 0 0 1-15.155-26.242zM50 47.786l-15.149-8.729a18.651 18.651 0 0 1 30.288-.012zM12.672 75.813a7.284 7.284 0 0 1-1.522-1.168l13.117-7.574a1.918 1.918 0 0 0-1.918-3.321L9.232 71.323a7.316 7.316 0 0 1-.251-1.9l.029-38.786a7.274 7.274 0 0 1 .254-1.9l20.318 11.71a22.53 22.53 0 0 0 18.5 32.015v22.945a1.9 1.9 0 0 0 .083.53 7.351 7.351 0 0 1-1.892-.757zm40.969 19.364a7.362 7.362 0 0 1-1.8.741 1.919 1.919 0 0 0 .077-.511V72.461A22.533 22.533 0 0 0 70.411 40.43l20.357-11.754a7.329 7.329 0 0 1 .251 1.9l-.028 38.784a7.33 7.33 0 0 1-.264 1.937L77.651 63.75a1.918 1.918 0 0 0-1.918 3.321l13.053 7.536a7.3 7.3 0 0 1-1.481 1.135z" fill="#89a19d"></path>
+        </svg>
+        <svg height="30" width="auto" viewBox="0 0 346.17 33.7" style="display:inline-block;fill:#fff;">
+          <path d="M24.54,33.07a1.88,1.88,0,0,1-1.47-.71L3.75,7.9V31.2A1.88,1.88,0,1,1,0,31.2V2.5A1.88,1.88,0,0,1,3.35,1.34L22.67,25.8V2.5a1.88,1.88,0,0,1,3.75,0V31.2a1.88,1.88,0,0,1-1.87,1.88Z"></path><path d="M48.92,33.7c-8.81,0-16-7.56-16-16.85S40.11,0,48.92,0s16,7.56,16,16.85S57.72,33.7,48.92,33.7Zm0-29.95c-6.74,0-12.22,5.88-12.22,13.1s5.48,13.1,12.22,13.1,12.22-5.88,12.22-13.1S55.66,3.75,48.92,3.75Z"></path><path d="M177.24,33.7c-8.81,0-16-7.56-16-16.85S168.43,0,177.24,0s16,7.56,16,16.85S186,33.7,177.24,33.7Zm0-29.95C170.5,3.75,165,9.63,165,16.85s5.48,13.1,12.22,13.1,12.22-5.88,12.22-13.1S184,3.75,177.24,3.75Z"></path><path d="M234.8,33.07a1.88,1.88,0,0,1-1.87-1.88V2.5A1.88,1.88,0,0,1,234.8.62h13.31c5.67,0,9.78,3.79,9.78,9s-4.11,9-9.78,9H236.67V31.2A1.88,1.88,0,0,1,234.8,33.07Zm1.88-18.18h11.43c3.55,0,6-2.16,6-5.26s-2.48-5.26-6-5.26H236.67Z"></path><path d="M212.47,33.7A13.51,13.51,0,0,1,199.16,20V2.5a1.88,1.88,0,0,1,3.75,0V20A9.57,9.57,0,1,0,222,20V2.5a1.88,1.88,0,0,1,3.75,0V20A13.51,13.51,0,0,1,212.47,33.7Z"></path><path d="M152.72,6.59l-.18-.12c-.12-.08-.31-.21-.51-.33a18.63,18.63,0,0,0-1.91-1A14.31,14.31,0,0,0,147,4a13,13,0,0,0-4.25-.17,8.14,8.14,0,0,0-4.29,1.67A4.4,4.4,0,0,0,136.9,9.7a3.81,3.81,0,0,0,.3,1,3.68,3.68,0,0,0,.61,1A6.93,6.93,0,0,0,140,13.22a17.68,17.68,0,0,0,3,1c.54.14,1.09.26,1.64.37s1.15.23,1.82.41a22.48,22.48,0,0,1,3.7,1.25,13.74,13.74,0,0,1,3.49,2.14,8.41,8.41,0,0,1,2.52,3.66c.11.36.2.74.28,1.11s.09.75.1,1.12v.89l0,.17,0,.1-.06.42,0,.21-.07.29a8.86,8.86,0,0,1-5.21,6,15.75,15.75,0,0,1-6.39,1.31,12.44,12.44,0,0,1-1.47-.07,14.11,14.11,0,0,1-1.46-.22,17.07,17.07,0,0,1-2.49-.72,20.61,20.61,0,0,1-3.68-1.84,21.46,21.46,0,0,1-2.13-1.54c-.47-.39-.72-.62-.72-.62l0,0a1.69,1.69,0,0,1,2.26-2.5s.2.17.61.47a19.79,19.79,0,0,0,1.86,1.2,17.77,17.77,0,0,0,3.1,1.43,13.37,13.37,0,0,0,2,.54c.35.06.71.12,1,.14a10.25,10.25,0,0,0,1.15,0,12.07,12.07,0,0,0,4.86-1,6.41,6.41,0,0,0,2-1.38,3.17,3.17,0,0,0,.38-.45,2.58,2.58,0,0,0,.31-.48,4.25,4.25,0,0,0-1.06-5.41,14,14,0,0,0-5.61-2.57c-.48-.14-1.17-.26-1.67-.38s-1.23-.26-1.84-.42a21.32,21.32,0,0,1-3.68-1.27A10.58,10.58,0,0,1,135,14.17,7.53,7.53,0,0,1,133.17,10a3.77,3.77,0,0,1,0-.48l0-.42v-.6l0-.53c0-.35.11-.7.18-1s.19-.68.32-1A8.25,8.25,0,0,1,136,2.67a11.8,11.8,0,0,1,6.3-2.54,15.79,15.79,0,0,1,5.47.29,16.09,16.09,0,0,1,3.94,1.48A17.75,17.75,0,0,1,154,3.31l.71.53a1.69,1.69,0,0,1-2,2.75Z"></path><path d="M79.8,33.07H73.15a1.88,1.88,0,0,1-1.87-1.88V2.5A1.88,1.88,0,0,1,73.15.62H79.8c12.62,0,18.27,8.15,18.27,16.22C98.07,27.16,91.41,33.07,79.8,33.07ZM75,29.32H79.8c12,0,14.52-6.78,14.52-12.47,0-7.58-5.7-12.47-14.52-12.47H75Z"></path><path d="M125.54,33.07H106.37a1.88,1.88,0,0,1-1.87-1.88V2.5A1.88,1.88,0,0,1,106.37.62h19.17a1.87,1.87,0,1,1,0,3.75H108.24V29.32h17.29a1.88,1.88,0,0,1,0,3.75Z"></path><path d="M120.39,18.66h-14a1.88,1.88,0,0,1,0-3.75h14a1.87,1.87,0,0,1,0,3.75Z"></path><path d="M319.58,33.07H300.41a1.88,1.88,0,0,1-1.87-1.88V2.5A1.88,1.88,0,0,1,300.41.62h19.17a1.87,1.87,0,1,1,0,3.75H302.29V29.32h17.29a1.88,1.88,0,0,1,0,3.75Z"></path><path d="M314.44,18.66H300.8a1.88,1.88,0,0,1,0-3.75h13.63a1.88,1.88,0,0,1,0,3.75Z"></path><path d="M256.16,33.07a1.87,1.87,0,0,1-1.53-.79L244.5,17.93a1.88,1.88,0,0,1,3.06-2.16l10.13,14.35a1.88,1.88,0,0,1-1.53,3Z"></path><path d="M291.05,28.93l-.58.55a17.13,17.13,0,0,1-2,1.54,16.17,16.17,0,0,1-8.36,2.66h-.78l-.63,0a10.23,10.23,0,0,1-1.39-.13,16.51,16.51,0,0,1-3.05-.7,16.71,16.71,0,0,1-5.73-3.27,16.91,16.91,0,0,1-5.82-12.72l0-.91c0-.28,0-.53.05-.84.1-.63.17-1.3.31-1.9a16.8,16.8,0,0,1,1.18-3.45,17,17,0,0,1,4.24-5.62A16.71,16.71,0,0,1,274.28.86,17.45,17.45,0,0,1,280.12,0a16.27,16.27,0,0,1,8.38,2.66,17.06,17.06,0,0,1,2,1.52l.63.6a1.69,1.69,0,0,1-2.24,2.51l-.09-.07-.53-.45a14,14,0,0,0-1.61-1.11A13.58,13.58,0,0,0,280,3.76a14,14,0,0,0-4.57.66A13,13,0,0,0,271,7a13.24,13.24,0,0,0-3.3,4.37A13,13,0,0,0,266.8,14c-.11.46-.14.88-.23,1.32,0,.23,0,.53-.05.8l0,.72A13.16,13.16,0,0,0,271,26.74a12.9,12.9,0,0,0,6.71,3.06,7.27,7.27,0,0,0,1.19.11l.63,0H280A13.5,13.5,0,0,0,286.61,28a14.42,14.42,0,0,0,1.59-1.09l.59-.5h0a1.69,1.69,0,0,1,2.26,2.51Z"></path><path d="M337.88.2a8.29,8.29,0,1,0,8.29,8.29A8.3,8.3,0,0,0,337.88.2Zm0,15.12a6.83,6.83,0,1,1,6.83-6.83A6.84,6.84,0,0,1,337.88,15.32Z"></path><path d="M335.87,12.12a.61.61,0,0,1-.61-.61v-6a.61.61,0,0,1,.61-.61h2.81a2.12,2.12,0,1,1,0,4.23h-2.2v2.43A.61.61,0,0,1,335.87,12.12Zm.61-4.26h2.2a.91.91,0,1,0,0-1.79h-2.2Z"></path><path d="M340.38,12.12a.61.61,0,0,1-.5-.26l-2.13-3a.61.61,0,0,1,1-.7l2.13,3a.61.61,0,0,1-.5,1Z"></path>
+        </svg>
+      </div>
+
+      <div id="title" class="bottom-20">
+        <div class="title">
+          <p>
+            NCM&nbsp;Project&nbsp;Report
+            <span class="light1">&nbsp;>&nbsp;</span>
+            ${title}
+          </p>
+        </div>
+        <div class="left-20">
+          <p>
+            <b class="green">></b>
+            Powered by
+            <a href="https://docs.nodesource.com/ncmv2/docs">NodeSource Certified Modules v2</a>
+          </p>
+        </div>
+      </div>
+
+      <div id="summary" class="bottom-20 left-20">
+        <span class="subtitle">Summary</span>
+        <p><b class="white">${reportLength}</b> packages checked</p>
+        <br>
+        <p><span class="red"><b>${riskCount[4]}</b> Critical Risk</span></p>
+        <p><span class="orange"><b>${riskCount[3]}</b> High Risk</span></p>
+        <p><span class="yellow"><b>${riskCount[2]}</b> Medium Risk</span></p>
+        <p><span class-"light1"><b>${riskCount[1]}</b> Low Risk</span></p>
+        <br>
+        <p>         
+    ${(securityCount > 0
+    ? `<b class="red">!&nbsp;</b>
+      <b class="white">${securityCount}</b> 
+      security vulnerabilities found across 
+      <b class="white">${insecureModules}</b> modules`
+    : '<span class="green">✓</span> No security vulnerabilities found')}
+        </p>
+        <p>
+    ${(complianceCount > 0
+    ? `<b class="red">!&nbsp;</b>
+      <b class="white">${complianceCount}</b> noncompliant modules found`
+    : '<span class="green">✓</span> All modules compliant')}
+        </p>
+    ${(whitelistLength > 0
+    ? `<p>
+        <b class="orange">!&nbsp;</b>
+        <b class="white">${whitelistLength}</b> used modules whitelisted
+      </p>`
+    : '')}
+      </div>
+
+      ${(whitelistLength > 0
+    ? `
+          <div id="whitelist-list">
+            <p>
+              <span class="subtitle">
+                Whitelisted
+    ${(formattedFilterOptions.length > 9
+      ? 'Filtered'
+      : '')}
+                Modules
+              </span>
+    ${(formattedFilterOptions.length > 9
+      ? `(${formattedFilterOptions})`
+      : '')}
+
+            </p>
+            <hr>
+            <table id="whitelist-table" class="bottom-20">
+              <tr style="margin-bottom:5px;">
+                <th>Module Name</th>
+                <th>Risk</th>
+                <th>License</th>
+                <th>Security</th>
+              </tr>
+              ${whitelistInfo}
+            </table>
+          </div>
+          `
+    : '')}
+      
+      <div id="module-list">
+        <p>
+          <span class="subtitle">
+    ${(whitelistLength > 0
+    ? 'Non-Whitelisted'
+    : '')}
+    ${(formattedFilterOptions.length > 9
+    ? 'Filtered'
+    : '')}
+            Modules
+          </span>
+    ${(formattedFilterOptions.length > 9
+    ? `( ${formattedFilterOptions} )`
+    : '')}
+        </p>
+        <hr>
+        <table id="module-table" class="bottom-20">
+          <tr style="margin-bottom:5px;">
+            <th>Module Name</th>
+            <th>Risk</th>
+            <th>License</th>
+            <th>Security</th>
+          </tr>
+          ${pkgInfo}
+        </table>
+      </div>
+    </body>
+  </html>
+  `
+
+  return template
+}
diff --git a/lib/report/html.js b/lib/report/html.js
new file mode 100644
index 0000000..d5c37c6
--- /dev/null
+++ b/lib/report/html.js
@@ -0,0 +1,73 @@
+'use strict'
+
+const path = require('path')
+const { promisify } = require('util')
+const writeFile = promisify(require('fs').writeFile)
+const {
+  success,
+  formatError
+} = require('../ncm-style')
+const {
+  summaryInfo,
+  moduleSort,
+  filterReport,
+  parseFilterOptions,
+  formatFilterOptions
+} = require('./util')
+const renderTemplate = require('./html-template')
+const L = console.log
+
+module.exports = htmlReport
+
+async function htmlReport (report, whitelist, dir, output, argv) {
+  /* Output may only use the `.html` file format */
+  if (output !== true && !(/^.*\.html$/.test(path.basename(output)))) {
+    L()
+    L(formatError('Invalid file extension to write the HTML report. Please use `*.html`.'))
+    L()
+    process.exitCode = 1
+    return
+  }
+
+  const title = `${path.basename(dir) || 'NCM'}`
+  const summary = summaryInfo(report) // { riskCount, insecureModules, complianceCount, securityCount }
+  const reportLength = report.length
+  const whitelistLength = whitelist.length
+
+  const filterOptions = parseFilterOptions(argv)
+  const formattedfilterOptions = formatFilterOptions(filterOptions)
+  report = filterReport(report, filterOptions)
+  report = moduleSort(report)
+
+  whitelist = filterReport(whitelist, filterOptions)
+  whitelist = moduleSort(whitelist)
+
+  const htmlData = renderTemplate(
+    title,
+    summary,
+    report,
+    reportLength,
+    whitelist,
+    whitelistLength,
+    formattedfilterOptions
+  )
+
+  /*
+    No write location was specified.
+    Setting output location to current working directory with generated report name.
+  */
+  if (output === true) output = path.join(process.cwd(), `${title.toLowerCase()}-report-${Date.now()}.html`)
+
+  /* Write report to file */
+  try {
+    await writeFile(output, htmlData)
+    L()
+    L(success(`Wrote HTML report to: ${output}`))
+    L()
+  } catch (error) {
+    L()
+    L(formatError(`Unable to write HTML report to: ${output}`, error))
+    L()
+    process.exitCode = 1
+  }
+}
diff --git a/lib/report/short.js b/lib/report/short.js
index 243743a..e3bab76 100644
--- a/lib/report/short.js
+++ b/lib/report/short.js
@@ -3,7 +3,11 @@
 module.exports = shortReport
 
 const summary = require('./summary')
-const { moduleList, SEVERITY_RMAP } = require('./util')
+const {
+  moduleList,
+  parseFilterOptions,
+  formatFilterOptions
+} = require('./util')
 
 const {
   COLORS,
@@ -13,39 +17,7 @@ const chalk = require('chalk')
 const L = console.log
 
 function shortReport (report, whitelist, dir, argv) {
-  let filterSecurity = argv ? !!argv.security : false
-  let filterCompliance = argv ? !!argv.compliance : false
-  let filterLevel = SEVERITY_RMAP.indexOf('NONE')
-
-  if (argv.filter) {
-    const segments = argv.filter.split(',')
-      .map(s => s.trim().toLowerCase())
-
-    if (segments.includes('compliance')) {
-      filterCompliance = true
-    }
-    if (segments.includes('security')) {
-      filterSecurity = true
-    }
-    if (segments.includes('c') || segments.includes('critical')) {
-      filterLevel = SEVERITY_RMAP.indexOf('CRITICAL')
-    }
-    if (segments.includes('h') || segments.includes('high')) {
-      filterLevel = SEVERITY_RMAP.indexOf('HIGH')
-    }
-    if (segments.includes('m') || segments.includes('medium')) {
-      filterLevel = SEVERITY_RMAP.indexOf('MEDIUM')
-    }
-    if (segments.includes('l') || segments.includes('low')) {
-      filterLevel = SEVERITY_RMAP.indexOf('LOW')
-    }
-  }
-
-  const filterOptions = {
-    filterCompliance: filterCompliance,
-    filterSecurity: filterSecurity,
-    filterLevel: filterLevel
-  }
+  const filterOptions = parseFilterOptions(argv)
 
   summary(report, dir, filterOptions)
 
@@ -55,7 +27,7 @@ function shortReport (report, whitelist, dir, argv) {
     L()
   }
 
-  if (filterCompliance || filterSecurity || filterLevel > 0) {
+  if (filterOptions.filterCompliance || filterOptions.filterSecurity || filterOptions.filterLevel > 0) {
     const filterFormat = formatFilterOptions(filterOptions)
     if (whitelist.length > 0) {
       moduleList(
@@ -80,20 +52,3 @@ function shortReport (report, whitelist, dir, argv) {
     moduleList(report.slice(0, 5), 'Top 5: Highest Risk Modules')
   }
 }
-
-function formatFilterOptions (filterOptions) {
-  let str = '--filter='
-  if (filterOptions.filterCompliance) {
-    str += 'compliance,'
-  }
-  if (filterOptions.filterSecurity) {
-    str += 'security,'
-  }
-  if (filterOptions.filterLevel) {
-    str += SEVERITY_RMAP[filterOptions.filterLevel] + ','
-  }
-  if (str[str.length - 1] === ',') {
-    str = str.slice(0, str.length - 1)
-  }
-  return str
-}
diff --git a/lib/report/summary.js b/lib/report/summary.js
index 75d366b..ff59fd4 100644
--- a/lib/report/summary.js
+++ b/lib/report/summary.js
@@ -7,7 +7,7 @@ const {
   tooltip
 } = require('../ncm-style')
 const {
-  SEVERITY_RMAP
+  summaryInfo
 } = require('./util')
 const L = console.log
 const chalk = require('chalk')
@@ -19,27 +19,7 @@ function summary (report, dir, filterOptions) {
   L(chalk`${report.length} {${COLORS.light1} packages checked}`)
   L()
 
-  const riskCount = [0, 0, 0, 0, 0]
-  let insecureModules = 0
-  let complianceCount = 0
-  let securityCount = 0
-
-  for (const pkg of report) {
-    let insecure = false
-    let pkgMaxSeverity = 0
-    for (const score of pkg.scores) {
-      if (score.group === 'quality') continue
-      if (score.group === 'compliance' && !score.pass) complianceCount++
-      if (score.group === 'security' && !score.pass) {
-        securityCount++
-        insecure = true
-      }
-      const scoreIndex = SEVERITY_RMAP.indexOf(score.severity)
-      pkgMaxSeverity = scoreIndex > pkgMaxSeverity ? scoreIndex : pkgMaxSeverity
-    }
-    riskCount[pkgMaxSeverity]++
-    if (insecure) insecureModules++
-  }
+  const { riskCount, insecureModules, complianceCount, securityCount } = summaryInfo(report)
 
   L(chalk`  {${COLORS.red} ! ${riskCount[4]}} critical risk`)
   L(chalk`    {${COLORS.orange} ${riskCount[3]}} high risk`)
diff --git a/lib/report/util.js b/lib/report/util.js
index ca65523..f465e2e 100644
--- a/lib/report/util.js
+++ b/lib/report/util.js
@@ -40,7 +40,12 @@ module.exports = {
   severityTextLabel,
   shortVulnerabilityList,
   moduleList,
-  moduleSort
+  moduleSort,
+  summaryInfo,
+  filterVulns,
+  filterReport,
+  parseFilterOptions,
+  formatFilterOptions
 }
 
 function filterReport (report, options) {
@@ -121,15 +126,7 @@ function moduleList (report, title, options) {
         : chalk`{${COLORS.red} X}`
 
       /* security badge */
-      const vulns = [0, 0, 0, 0]
-      for (const { group, severity } of pkg.failures) {
-        if (group === 'security') {
-          if (severity === 'CRITICAL') vulns[3]++
-          if (severity === 'HIGH') vulns[2]++
-          if (severity === 'MEDIUM') vulns[1]++
-          if (severity === 'LOW') vulns[0]++
-        }
-      }
+      const vulns = filterVulns(pkg.failures)
       const securityBadges = [
         vulns.reduce((a, b) => a + b, 0) === 0
           ? chalk`{${COLORS.green} ✓} 0` : chalk`{${COLORS.red} X} `,
@@ -254,3 +251,98 @@ function severityTextLabel (severity) {
   const color = severity === 'NONE' ? COLORS.base : COLORS.light1
   return chalk`{${color} ${severityLabel[severity]}}`
 }
+
+function summaryInfo (report) {
+  const riskCount = [0, 0, 0, 0, 0]
+  let insecureModules = 0
+  let complianceCount = 0
+  let securityCount = 0
+
+  for (const pkg of report) {
+    let insecure = false
+    let pkgMaxSeverity = 0
+    for (const score of pkg.scores) {
+      if (score.group === 'quality') continue
+      if (score.group === 'compliance' && !score.pass) complianceCount++
+      if (score.group === 'security' && !score.pass) {
+        securityCount++
+        insecure = true
+      }
+      const scoreIndex = SEVERITY_RMAP.indexOf(score.severity)
+      pkgMaxSeverity = scoreIndex > pkgMaxSeverity ? scoreIndex : pkgMaxSeverity
+    }
+    riskCount[pkgMaxSeverity]++
+    if (insecure) insecureModules++
+  }
+
+  return { riskCount, insecureModules, complianceCount, securityCount }
+}
+
+function filterVulns (failures) {
+  const vulns = [0, 0, 0, 0]
+  for (const { group, severity } of failures) {
+    if (group === 'security') {
+      if (severity === 'CRITICAL') vulns[3]++
+      if (severity === 'HIGH') vulns[2]++
+      if (severity === 'MEDIUM') vulns[1]++
+      if (severity === 'LOW') vulns[0]++
+    }
+  }
+
+  return vulns
+}
+
+function parseFilterOptions (argv) {
+  let filterSecurity = argv ? !!argv.security : false
+  let filterCompliance = argv ? !!argv.compliance : false
+  let filterLevel = SEVERITY_RMAP.indexOf('NONE')
+
+  if (argv.filter) {
+    const segments = argv.filter.split(',')
+      .map(s => s.trim().toLowerCase())
+
+    if (segments.includes('compliance')) {
+      filterCompliance = true
+    }
+    if (segments.includes('security')) {
+      filterSecurity = true
+    }
+    if (segments.includes('c') || segments.includes('critical')) {
+      filterLevel = SEVERITY_RMAP.indexOf('CRITICAL')
+    }
+    if (segments.includes('h') || segments.includes('high')) {
+      filterLevel = SEVERITY_RMAP.indexOf('HIGH')
+    }
+    if (segments.includes('m') || segments.includes('medium')) {
+      filterLevel = SEVERITY_RMAP.indexOf('MEDIUM')
+    }
+    if (segments.includes('l') || segments.includes('low')) {
+      filterLevel = SEVERITY_RMAP.indexOf('LOW')
+    }
+  }
+
+  const filterOptions = {
+    filterCompliance: filterCompliance,
+    filterSecurity: filterSecurity,
+    filterLevel: filterLevel
+  }
+
+  return filterOptions
+}
+
+function formatFilterOptions (filterOptions) {
+  let str = '--filter='
+  if (filterOptions.filterCompliance) {
+    str += 'compliance,'
+  }
+  if (filterOptions.filterSecurity) {
+    str += 'security,'
+  }
+  if (filterOptions.filterLevel) {
+    str += SEVERITY_RMAP[filterOptions.filterLevel] + ','
+  }
+  if (str[str.length - 1] === ',') {
+    str = str.slice(0, str.length - 1)
+  }
+  return str
+}