SCAP Workbench 1.1.0

The new SCAP Workbench is out! This is the biggest release to date. We focused on improving the typical use-case of tailoring and remote scanning. This is also the first release to have Windows and MacOS X support!

Update: Thanks to the great work of Jakub Jelen, we now have a testing release for Windows that supports remote scan! Give it a try, report any issues: SCAP Workbench 1.1.1 will be released some time soon and will have remote scanning from Windows included.

Fedora updates for F22, F21 and F20 are pending. Testing and karma would be greatly appreciated! This release brings so many fixes and does not break existing use-cases that I decided to push it to older Fedoras as well. Even though it is a major release.


sw-1.1.0_1 sw-1.1.0_2

sw-1.1.0_3 sw-1.1.0_4

What’s new?

1.1.0 is a packed major release, the number of changes is second only to the 0.8.0 C++ rewrite.

  • Windows support – including a native MSI installer
  • MacOS X support – including a native dmg image
  • Complete redesign of the main window, with rich-text rule descriptions
  • Better SCAP Security Guide integration
  • Tailoring window greatly improved – shows relationships between values and rules
  • Opens bzip2 files
  • Performance improvements when loading big SCAP files
  • Countless UX improvements
  • And a lot more, a total of 49 tickets fixed, plus fixes merged from maintenance branches

Where to report issues?

The best place to report issues is the trac bug tracker. However I also accept reports via the mailing list or even comments to this blog post.

OpenSCAP and SCAP Workbench on Windows – part 2

Go to Part 1

Remote scanning

I have made some progress with remote scanning but there still are issues that prevent convenient usage. Right now workbench on Windows can:

  • login to the remote machine
  • query oscap capabilities and parse them
  • copy input content to the remote machine (ssh+tee)
  • start the scan
  • copy remote results back to the local machine


So it seems remote scan is working fine, right? The issue is that ssh continuously asks for login over and over again. This is not such an issue if you have a private key setup but if you login with username and password this is a major pain. You have to type the password in a dozen of times, each time for one performed action. To make matters worse, setting up ssh private key in cygwin ssh isn’t straightforward at all.

The issue stems from the fact that it seems cygwin ssh does not support ControlMaster and ControlPath options. Right now I am researching alternatives but haven’t found anything suitable yet. Suggestions welcome.

Windows content tailoring

However I also have good news 🙂

NIST has released release candidate of the upcoming USGCB content for Microsoft products. At first workbench failed to open it, claiming there are referenced tests that are non-existent. Turns out openscap had some of the Windows specific OVAL enumeration strings missing and/or wrong. This has been fixed in openscap master branch.

OpenSCAP and SCAP Workbench from master branches can now open the upcoming USGCB content for Windows 7. Furthermore, workbench can customize Windows-specific content and save the result for later use.

windows-tailoring-1 windows-tailoring-2 windows-tailoring-3

I have performed profile customization of the Windows 7 USGCB profile and saved it to a tailoring file, here is how the resulting file looks like:

<?xml version="1.0" encoding="UTF-8"?>
<xccdf:Tailoring xmlns:xccdf="" id="xccdf_scap-workbench_tailoring_default">
  <xccdf:benchmark href="C:/Users/mpreisle/Desktop/USGCB-Windows/Win7-"/>
  <xccdf:version time="2015-03-02T17:28:53">1</xccdf:version>
  <xccdf:Profile id="xccdf_gov.nist_profile_united_states_government_configuration_baseline_version_2.0.5.1_customized" extends="xccdf_gov.nist_profile_united_states_government_configuration_baseline_version_2.0.5.1">
    <xccdf:title xmlns:xhtml="" xml:lang="en-US">United States Government Configuration Baseline [CUSTOMIZED]</xccdf:title>
    <xccdf:description xmlns:xhtml="" xml:lang="en-US">This profile represents guidance outlined in United States Government Configuration Baseline for desktop systems with Microsoft Windows 7 installed.</xccdf:description>
    <xccdf:select idref="xccdf_gov.nist_group_security_options_settings" selected="false"/>
    <xccdf:select idref="xccdf_gov.nist_group_system_services_settings" selected="false"/>
    <xccdf:set-value idref="xccdf_gov.nist_value_auto_admin_logon_var">1</xccdf:set-value>
    <xccdf:set-value idref="xccdf_gov.nist_value_router_discovery_var">1</xccdf:set-value>

Executables for testing

Please keep in mind that this is a preliminary release that is in no way official. It just shows what is possible right now and allows me to outline future plans. You should NOT use this in production!

You need to edit scap-workbench.bat if you want to try remote scanning. Right now workbench requires absolute path to win-ssh-askpass.exe and I am too much of a Windows scripting newbie to do it automatically 🙂 This will be fixed later. The executable is in the bin folder in the zip file.

OpenSCAP and SCAP Workbench on Windows

In the past week I merged Daniel Kopecek’s patches to the master branch and applied new patches to make openscap master build and run on Windows. After a bit of gnulib wrestling I do have a working OpenSCAP and SCAP Workbench executables that can be tested.

The following screenshots were taken on Windows 7 with openscap from master branch (69626aeaf9dbb16b99bb9f3cd43423a3d00df179) and scap-workbench from master branch (d4ac3e4c49abb660e02f436b262315bd2b85679f). Everything was compiled using the mingw32 toolchain on Fedora 21.

workbench_win_1 workbench_win_2 workbench_win_3

Executables for testing

Please keep in mind that this is a preliminary release that is in no way official. It just shows what is possible right now and allows me to outline future plans. You should NOT use this in production!


After extraction, run the scap-workbench.bat script. In the final release the bat script won’t be necessary, it just sets all the paths for now.

How to build (Fedora 21)

$ sudo dnf install mingw32-gcc mingw32-binutils mingw32-libxml2 \
  mingw32-libgcrypt mingw32-pthreads mingw32-libxslt \
  mingw32-curl mingw32-pcre \
  automake autoconf libtool
$ cd openscap
$ ./
# EDIT: Also disable oscap-docker because it needs bz2-devel
$ mingw32-configure --disable-probes --disable-python --disable-util-oscap-docker
$ make -j 4
$ sudo make install

$ sudo dnf install mingw32-qt
$ cd scap-workbench
$ mkdir build/
$ cd build/
$ mingw32-cmake ../
$ make -j 4
$ sudo make install

What works

  • Opening XCCDF files and source datastreams
  • Changing profiles
  • Opening tailoring, saving tailoring
  • Customizing profiles
  • Saving all into a directory
  • Opening user manual

What doesn’t work

  • Local scanning
  • Remote scanning
  • Saving as RPM


The high level goal is to enable remote scanning from Windows machines, that is the most immediate plan.

I am not sure about save-as-rpm. It is a great feature but getting all the necessary tools on Windows is a lot of pain.

After that I hope to add MacOS X support.

Also see the mailing list thread about this blog post on open-scap-list.

Go to Part 2

SCAP Workbench 1.1.0rc1

Before I release the final 1.1.0 I wanted to make a release candidate with COPR repos for Fedora 20 and 21. This should be less painful than compiling everything from source so I am hoping to get more feedback and testing that way.

Feedback would be greatly appreciated. I expect to have a final release out by the end of February.

ssg_integration intro_screenshot tailoring_dialog_opened

What’s new?

1.1.0 will be a packed major release, the number of changes is second only to the 0.8.0 C++ rewrite.

  • Complete redesign of the main window, with rich-text rule descriptions
  • Better SCAP Security Guide integration
  • Tailoring window greatly improved – shows relationships between values and rules
  • Opens bzip2 files
  • Performance improvements when loading big SCAP files
  • Countless UX improvements
  • And a lot more, a total of 34 tickets fixed

How to test?

If you have x86_64 Fedora 20 or 21 you can just enable my COPR repo and install scap-workbench via yum or dnf.

# dnf install dnf-plugins-core

# dnf copr enable mpreisle/scap-workbench

# dnf install scap-workbench

Please consider also installing scap-security-guide to test the new integration dialog. We may opt to make scap-workbench depend on scap-security-guide for the final release but the decision has not been made yet.

# dnf install scap-security-guide

Otherwise you have to pull from the git repository or download the 1.1.0rc1 tarball and build workbench yourself.

Where to report issues?

The best place to report issues is the trac bug tracker. However I also accept reports via the mailing list or even comments to this blog post.


Waivers in openscap HTML report

XCCDF supports waivers by the means of the cdf:override element. Support for it in the openscap API has recently been greatly enhanced by Šimon Lukašík. Therefore I have looked into adding support for waivers in the HTML report.

This blog post talks about openscap master as of commit 30f9a224bc25f2127462d30ec1e4c0d499a23511.

We decided to use the term waiver instead of override. The situation looks similar to tailoring vs customization to us. Waiver should be understood by more people without even looking at any documentation.

Rule overview now shows a small label next to waived rules. This label signifies that this particular rule has at least one waiver.


When you click on the waived rule to see the details you will be presented with description of the waiver including information on who has performed it and when. If there are more waivers they are all shown in the order they appear in the original XML file.


I know this feature has been requested by the community for a long time so I would like to gather some feedback to get it as right as possible.

Please note that the HTML reports themselves don’t allow you to interactively perform waivers, they just show them. As of now I don’t have plans to support interactive waivers but we may implement something like that in the future.

EDIT: I have implemented a prototype that allows interactive waivers using JavaScript. The waivers are not committed yet but I plan to commit them to master next week. Take a look at

Suggestions welcome!

EDIT2: Based on the feedback we decided not to include interactive waiver in the openscap reports themselves. Instead I will add HTML elements to make it easier to implement it in openscap integrations. The patch of the prototype follows and can be cleanly applied on top of 30f9a224bc25f2127462d30ec1e4c0d499a23511.

diff --git a/xsl/xccdf-report-impl.xsl b/xsl/xccdf-report-impl.xsl
index 08c50cf..f7c26f5 100644
--- a/xsl/xccdf-report-impl.xsl
+++ b/xsl/xccdf-report-impl.xsl
@@ -293,9 +293,7 @@ Authors:
 <xsl:with-param name="profile" select="$profile"/>
- <xsl:if test="$ruleresult/cdf:override">
- &#160;<span class="label label-warning">waived</span>
- </xsl:if>
+ &#160;<span class="label label-warning waiver-label"><xsl:if test="not($ruleresult/cdf:override)"><xsl:attribute name="style">display: none</xsl:attribute></xsl:if>waived</span>
 <td style="text-align: center"><xsl:value-of select="$ruleresult/@severity"/></td>
 <td class="rule-result rule-result-{$result}">
@@ -304,7 +302,7 @@ Authors:
 <xsl:with-param name="ruleresult" select="$result"/>
- <div>
+ <div class="inner">
 <abbr title="{$result_tooltip}"><xsl:value-of select="$result"/></abbr>
@@ -606,7 +604,8 @@ Authors:
 <div class="panel-body">
 <table class="table table-striped table-bordered">
- <tr><td class="col-md-3">Rule ID</td><td class="rule-id col-md-9"><xsl:value-of select="$item/@id"/></td></tr>
+ <xsl:variable name="itemid" select="$item/@id"/>
+ <tr><td class="col-md-3">Rule ID</td><td class="rule-id col-md-9"><xsl:value-of select="$itemid"/></td></tr>
 <td class="rule-result rule-result-{$result}">
 <xsl:variable name="result_tooltip">
@@ -614,9 +613,17 @@ Authors:
 <xsl:with-param name="ruleresult" select="$result"/>
- <div>
+ <div class="inner">
 <abbr title="{$result_tooltip}"><xsl:value-of select="$result"/></abbr>
+ <!-- see openscap.js for clues about the following 2 divs, they are used
+ for interactive waivers. -->
+ <div class="js-only waiver-button">
+ <xsl:if test="$result != 'pass' and $result != 'fixed' and $result != 'notselected'">
+ <button class="waive-button btn btn-warning btn-lg" type="button" onclick="return showWaiverForm($(this).closest('.rule-detail'), '{$itemid}')">Waive</button>
+ </xsl:if>
+ </div>
+ <div class="js-only waiver-form"></div>
 <tr><td>Time</td><td><xsl:value-of select="$ruleresult/@time"/></td></tr>
 <tr><td>Severity</td><td><xsl:value-of select="$ruleresult/@severity"/></td></tr>
@@ -628,8 +635,8 @@ Authors:
 <xsl:with-param name="item" select="$item"/>
- <xsl:if test="$ruleresult/cdf:override">
- <tr><td colspan="2">
+ <tr><td colspan="2" class="waivers">
+ <xsl:if test="$ruleresult/cdf:override">
 <xsl:for-each select="$ruleresult/cdf:override">
 <xsl:variable name="old-result" select="cdf:old-result/text()"/>
@@ -643,8 +650,8 @@ Authors:
- </td></tr>
- </xsl:if>
+ </xsl:if>
+ </td></tr>
 <tr><td colspan="2"><div class="description">
 <xsl:apply-templates mode="sub-testresult" select="$item/cdf:description">
diff --git a/xsl/ b/xsl/
index ec5f584..089d38a 100755
--- a/xsl/
+++ b/xsl/
@@ -10,12 +10,15 @@ cat xccdf-resources/jquery.treetable.css >> $ALL_CSS
 cat xccdf-resources/jquery.treetable.theme.css >> $ALL_CSS
 cat xccdf-resources/openscap.css >> $ALL_CSS
 csstidy $ALL_CSS --template=highest $ALL_CSS_MIN
 rm $ALL_CSS
 echo "" > $ALL_JS
 cat xccdf-resources/jquery.treetable.js >> $ALL_JS
 cat xccdf-resources/bootstrap.min.js >> $ALL_JS
 cat xccdf-resources/openscap.js >> $ALL_JS
 slimit $ALL_JS > $ALL_JS_MIN
 rm $ALL_JS
diff --git a/xsl/xccdf-resources/openscap.css b/xsl/xccdf-resources/openscap.css
index 2e0f8e4..6521c84 100644
--- a/xsl/xccdf-resources/openscap.css
+++ b/xsl/xccdf-resources/openscap.css
@@ -1,11 +1,13 @@
 tr.rule-overview-needs-attention td a { color: #d9534f }
-td.rule-result div, span.rule-result { text-align: center; font-weight: bold; color: #fff; background: #808080 }
-td.rule-result-fail div, span.rule-result-fail { background: #d9534f }
-td.rule-result-error div, span.rule-result-error { background: #d9534f }
-td.rule-result-unknown div, span.rule-result-unknown { background: #f0ad4e }
-td.rule-result-pass div, span.rule-result-pass { background: #5cb85c }
-td.rule-result-fixed div, span.rule-result-fixed { background: #5cb85c }
+td.rule-result div.inner, span.rule-result { text-align: center; font-weight: bold; color: #fff; background: #808080 }
+td.rule-result-fail div.inner, span.rule-result-fail { background: #d9534f }
+td.rule-result-error div.inner, span.rule-result-error { background: #d9534f }
+td.rule-result-unknown div.inner, span.rule-result-unknown { background: #f0ad4e }
+td.rule-result-pass div.inner, span.rule-result-pass { background: #5cb85c }
+td.rule-result-fixed div.inner, span.rule-result-fixed { background: #5cb85c }
+td.rule-result div.waiver-button { float: right }
 .js-only { display: none }
diff --git a/xsl/xccdf-resources/openscap.js b/xsl/xccdf-resources/openscap.js
index f76645b..70e87b3 100644
--- a/xsl/xccdf-resources/openscap.js
+++ b/xsl/xccdf-resources/openscap.js
@@ -9,6 +9,7 @@ function openRuleDetailsDialog(rule_result_id)
 var clone = $("#rule-detail-" + rule_result_id).clone();
 clone.attr("id", "");
+"idm_id", "rule-detail-" + rule_result_id);
 closebutton.css( { "float" : "right" } );
 closebutton.css( { "margin-top" : "-=20px" } );
@@ -108,7 +109,122 @@ function ruleSearch()
 $("#search-matches").html("No rules match your search criteria!");
-$(document).ready( function() {
+waiverCallback = function(rule_id, authority, datetime, new_result, remark)
+ //alert(rule_id);
+ //alert(datetime);
+ //alert(new_result);
+ //alert(remark);
+ return "";
+if (typeof waiverCallback === "undefined")
+ waiverCallback = null;
+if (typeof waiverDefaultAuthority === "undefined")
+ waiverDefaultAuthority = "Undefined Authority";
+function injectNewWaiver(rule_detail, rule_id, authority, datetime, new_result, remark)
+ var previous_result = rule_detail.find(".rule-result .inner abbr").html();
+ rule_detail.removeClass();
+ rule_detail.addClass("panel panel-default rule-detail rule-detail-" + new_result);
+ var waiver_div = rule_detail.find("div.waiver-button");
+ waiver_div.hide();
+ var rule_result = rule_detail.find("td.rule-result");
+ rule_result.removeClass();
+ rule_result.addClass("rule-result");
+ rule_result.addClass("rule-result-" + new_result);
+ rule_result.find(".inner").html("<abbr>" + new_result + "</abbr>");
+ var waivers_div = rule_detail.find("td.waivers");
+ var new_waiver_div = $('<div class="alert alert-warning waiver">This rule has been waived by <strong>' + authority + '</strong> at <strong>' + datetime + '</strong>.<blockquote>' + remark + '</blockquote><small>The previous result was <span class="rule-result rule-result-' + previous_result + '">&#160;' + previous_result + '&#160;</span>.</small></div>');
+ waivers_div.append(new_waiver_div);
+ if ("idm_id"))
+ {
+ rule_detail_lookup = $("#" +"idm_id"));
+ injectNewWaiver(rule_detail_lookup, rule_id, authority, datetime, new_result, remark);
+ return;
+ }
+ var idm_base = $(rule_detail).attr("id").substring(12);
+ var rule_overview_leaf = $("#rule-overview-leaf-" + idm_base);
+ rule_overview_leaf.removeClass();
+ rule_overview_leaf.addClass("rule-overview-leaf rule-overview-leaf-" + new_result);
+ rule_overview_leaf.find(".waiver-label").show();
+ var rule_result_overview = rule_overview_leaf.find(".rule-result");
+ rule_result_overview.removeClass();
+ rule_result_overview.addClass("rule-result rule-result-" + new_result);
+ rule_result_overview.find("div").html("<abbr>" + new_result + "</abbr>");
+function submitWaiverForm(rule_detail, rule_id, waiver_form)
+ var now = new Date();
+ var datetime = now.toISOString();
+ var authority = waiver_form.find(".waiver-authority").val();
+ var new_result = waiver_form.find(".waiver-new-result option:selected").val();
+ var remark = waiver_form.find(".waiver-remark").val();
+ var result = waiverCallback(rule_id, authority, datetime, new_result, remark);
+ if (result == "")
+ {
+ hideWaiverForm(rule_detail, rule_id);
+ injectNewWaiver(rule_detail, rule_id, authority, datetime, new_result, remark);
+ }
+ else
+ {
+ // TODO: Show error
+ }
+ return false;
+function showWaiverForm(rule_detail, rule_id)
+ var waiver_div = rule_detail.find("div.waiver-button");
+ waiver_div.hide();
+ var waiver_form_div = rule_detail.find("div.waiver-form");
+ var waiver_form = $('<form role="form"/>');
+ var authority = $('<div class="form-group"><label class="control-label">Authority</label><input type="text" class="waiver-authority form-control" value="' + waiverDefaultAuthority + '"/></div>');
+ waiver_form.append(authority);
+ var new_result = $('<div class="form-group"><label class="control-label">New result</label><select class="waiver-new-result form-control"><option>pass</option><option>notapplicable</option></select></div>');
+ waiver_form.append(new_result);
+ var remark = $('<div class="form-group"><label class="control-label">Remark</label><textarea class="waiver-remark form-control"/></div>');
+ waiver_form.append(remark);
+ var ok_button = $('<button type="button" class="btn btn-primary btn-sm">Confirm</button>');
+ return submitWaiverForm(rule_detail, rule_id, waiver_form);
+ });
+ waiver_form.append(ok_button);
+ var cancel_button = $('<button type="button" class="btn btn-default btn-sm">Cancel</button>');
+ return hideWaiverForm(rule_detail, rule_id);
+ });
+ waiver_form.append(cancel_button);
+ waiver_form_div.append(waiver_form);
+function hideWaiverForm(rule_detail, rule_id)
+ var waiver_div = rule_detail.find("div.waiver-button");
+ var waiver_form_div = rule_detail.find("div.waiver-form");
+ waiver_form_div.empty();
+ return false;

Don’t forget to run after applying the patch!