diff --git a/CHANGELOG.md b/CHANGELOG.md
index fde6b8fb755fc8f8818bd1d7afd8474c18873ebf..28fdb59c94469b05ada76e904b72e56b92413f64 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ### Added (for new features, dependecies etc.)
 
+* `ext_sss_markdown` module for pretty display of server-side scripting stdout.
+  See module docstring for more information.
 * `ext_trigger_crawler_form` module which generates a form for triggering the
   crawler. See module docstring for more info.
 * Support for deeply nested selectors in SELECT queries.
diff --git a/build.properties.d/00_default.properties b/build.properties.d/00_default.properties
index da4c8d0035970069b6762206477ae3b250b521c7..23b1e9ff929b030750f6cab0014f22cd0d6b7cf4 100644
--- a/build.properties.d/00_default.properties
+++ b/build.properties.d/00_default.properties
@@ -39,10 +39,11 @@
 # overridden in the makefile in any case.
 
 ##############################################################################
-# Modules enabled by default
+# Modules enabled/disabled by default
 ##############################################################################
 BUILD_MODULE_EXT_PREVIEW=ENABLED
 BUILD_MODULE_EXT_RESOLVE_REFERENCES=ENABLED
+BUILD_MODULE_EXT_SSS_MARKDOWN=DISABLED
 BUILD_MODULE_EXT_TRIGGER_CRAWLER_FORM=DISABLED
 
 ##############################################################################
diff --git a/src/core/js/ext_sss_markdown.js b/src/core/js/ext_sss_markdown.js
new file mode 100644
index 0000000000000000000000000000000000000000..21c7d3261faeb7052dbe8aa0b9fba29d88ed56d9
--- /dev/null
+++ b/src/core/js/ext_sss_markdown.js
@@ -0,0 +1,55 @@
+/**
+ * @module ext_sss_markdown
+ * @version 0.1
+ *
+ * Transforms the STDOUT of server-side scripting responses from plain text to
+ * HTML. The STDOUT is interpreted as Markdown.
+ *
+ * Module has to be enabled via setting the build property
+ * `BUILD_MODULE_EXT_SSS_MARKDOWN=ENABLED`.
+ */
+var ext_sss_markdown = function() {
+
+    var logger = log.getLogger("ext_sss_markdown");
+
+    var init = function() {
+        logger.trace("enter init");
+        const stdout_container = $("#caosdb-stdout");
+        if (stdout_container.length == 0) {
+            // nothing to do
+            return;
+        }
+
+        // get text content of the STDOUT container
+        const text = stdout_container[0].textContent;
+        logger.debug("transform", text);
+        // interpret as markdown.
+        const html = markdown.textToHtml(text);
+
+        // a little styling
+        stdout_container.css({padding: 10});
+
+        // replace plain markdown text with formatted html
+        stdout_container.empty();
+        stdout_container.append(html);
+
+        // hide error output container if the STDERR was empty.
+        var errortext = $("#caosdb-stderr").text();
+        if (errortext.length == 0) {
+            $("#caosdb-container-stderr").hide();
+        }
+    }
+
+    return {
+        init: init,
+        logger: logger,
+    };
+
+}();
+
+
+$(document).ready(function() {
+    if ("${BUILD_MODULE_EXT_SSS_MARKDOWN}" == "ENABLED") {
+        caosdb_modules.register(ext_sss_markdown);
+    }
+});
diff --git a/src/core/xsl/main.xsl b/src/core/xsl/main.xsl
index 52e5b4249fa85479efc69bd7d8c63de80fbb2631..d4ec6cda7bd9fee3f3e65bee6564de71fc7e49d4 100644
--- a/src/core/xsl/main.xsl
+++ b/src/core/xsl/main.xsl
@@ -240,6 +240,11 @@
         <xsl:value-of select="concat($basepath,'webinterface/${BUILD_NUMBER}/js/ext_revisions.js')"/>
       </xsl:attribute>
     </xsl:element>
+    <xsl:element name="script">
+      <xsl:attribute name="src">
+        <xsl:value-of select="concat($basepath,'webinterface/${BUILD_NUMBER}/js/ext_sss_markdown.js')"/>
+      </xsl:attribute>
+    </xsl:element>
     <xsl:element name="script">
       <xsl:attribute name="src">
         <xsl:value-of select="concat($basepath,'webinterface/${BUILD_NUMBER}/js/ext_trigger_crawler_form.js')"/>
diff --git a/test/core/index.html b/test/core/index.html
index ab65f0d9546c671ad55485a187154d7a165f3e5c..50d8cbef8003d6fb9ab383f94405bcfa07270774 100644
--- a/test/core/index.html
+++ b/test/core/index.html
@@ -67,6 +67,7 @@
   <script src="js/ext_bottom_line.js"></script>
   <script src="js/ext_revisions.js"></script>
   <script src="js/autocomplete.js"></script>
+  <script src="js/ext_sss_markdown.js"></script>
   <script src="js/ext_trigger_crawler_form.js"></script>
   <!--EXTENSIONS-->
   <script src="js/modules/webcaosdb.js.js"></script>
@@ -86,6 +87,7 @@
   <script src="js/modules/ext_bottom_line.js.js"></script>
   <script src="js/modules/ext_revisions.js.js"></script>
   <script src="js/modules/autocomplete.js.js"></script>
+  <script src="js/modules/ext_sss_markdown.js.js"></script>
   <script src="js/modules/ext_trigger_crawler_form.js.js"></script>
 </body>
 </html>
diff --git a/test/core/js/modules/ext_sss_markdown.js.js b/test/core/js/modules/ext_sss_markdown.js.js
new file mode 100644
index 0000000000000000000000000000000000000000..07199e869f56c7042a78dba6938de55e4a36e727
--- /dev/null
+++ b/test/core/js/modules/ext_sss_markdown.js.js
@@ -0,0 +1,77 @@
+/*
+ * ** header v3.0
+ * This file is a part of the CaosDB Project.
+ *
+ * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * ** end header
+ */
+
+
+/* MODULE ext_sss_markdown */
+QUnit.module("ext_sss_markdown", {
+    before: function (assert) {
+        markdown.init();
+        ext_sss_markdown.logger.setLevel("trace");
+
+        const qunit_obj = this;
+        const done = assert.async();
+
+        // load test case
+        $.ajax({
+            cache: true,
+            dataType: 'xml',
+            url: "xml/test_sss_output.xml",
+        }).done(function(data, textStatus, jdXHR) {
+            // append the test case to the QUnit module object.
+            qunit_obj.testCase1 = data;
+        }).always(function() {
+            done();
+        });
+    },
+    after: function (assert) {
+        // clean up
+        $("#caosdb-stdout").remove();
+    }
+});
+
+
+QUnit.test("availability", function(assert) {
+    assert.ok(ext_sss_markdown, "available");
+});
+
+QUnit.test("test case 1", function(assert) {
+    // setup
+    const testCase1 = this.testCase1;
+    const plainStdout = testCase1.evaluate("/Response/script/stdout", testCase1, null, XPathResult.STRING_TYPE, null).stringValue;
+
+    const stdout = $('<div id="caosdb-stdout"/>').text(plainStdout);
+    $("body").append(stdout);
+
+    assert.equal($("#caosdb-stdout").length, 1);
+    assert.equal($("#caosdb-stdout div.alert").length, 0, "no bootstrap alert");
+    assert.equal($("#caosdb-stdout p").length, 0, "no html paragraphs");
+    assert.equal($("#caosdb-stdout").text(), plainStdout, "only plain text");
+
+    ext_sss_markdown.init();
+
+    assert.equal($("#caosdb-stdout p").length, 3, "3 html paragraphs transformed");
+    assert.equal($("#caosdb-stdout code").length, 1, "html code tag transformed");
+    assert.equal($("#caosdb-stdout div.alert").text(),
+        "this is a bootstrap alert", "bootstrap alert transformed");
+
+});
diff --git a/test/core/xml/test_sss_output.xml b/test/core/xml/test_sss_output.xml
new file mode 100644
index 0000000000000000000000000000000000000000..6fad9d3edcc3436b32c0efc2a015fe5ce60a29df
--- /dev/null
+++ b/test/core/xml/test_sss_output.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?xml-stylesheet type="text/xsl" href="../webcaosdb.xsl"?>
+<Response>
+    <script code="0">
+        <stdout>here are new lines and stuff
+
+&lt;code>this is a code environment&lt;/code>
+
+
+&lt;div class=&quot;alert alert-info&quot;>this is a bootstrap alert&lt;/div>
+
+last line ---</stdout>
+    </script>
+</Response>