Fortify SCA for Scala

Fortify SCA (Static Code Analyzer), by Micro Focus, finds security issues in source code. For an overview, visit microfocus.com.

Fortify supports many programming languages. This page provides technical documentation about its support for Scala in particular.

Scala support in Fortify is the product of a collaboration between Micro Focus and Lightbend.

Supported language features

All of Scala is supported by the translator.

Supported security vulnerabilities

A full list is available on the Micro Focus site.

Sample project

The play-webgoat repository contains an example web app that uses the Play framework. The fortify branch is configured for use with Fortify SCA. Here is a list of the vulnerabilities Fortify finds there.

Requirements

This release supports translating and scanning Scala source code on the following platforms:

  • Linux
  • MacOS
  • Windows

The following Java Virtual Machine versions are supported:

  • Java 8

The following Scala versions are supported:

  • Scala 2.13.0 or newer
  • Scala 2.12.3 or newer
  • except 2.12.9; please use 2.12.8 or 2.12.10 instead
  • Scala 2.11.6 or newer

The latest patch releases are recommended (2.13.1, 2.12.10, and 2.11.12 as of September 2019).

To translate Scala code for Fortify to scan, you must be a current Lightbend subscriber.

To actually scan translated code for vulnerabilities, you must either:

  • be a licensed Fortify SCA user. Fortify SCA version 19.1 or newer is recommended for best results; 17.20 or newer is required
  • or, use Fortify on Demand (see below for details)

Fortify 19.1’s own system requirements are documented here.

License installation

The license file for using the Scala translator is a standard Lightbend Enterprise Suite license. Lightbend subscribers can obtain their license by visiting https://www.lightbend.com/account/license.

The license contents should look like:

===== LIGHTBEND ENTERPRISE SUITE LICENSE =====

DO NOT TAMPER WITH THIS FILE - ...

All current Lightbend subscribers should have the fortify grant in the grants: line of the license. You may need to retrieve a new license if the old one was created before mid-July 2017. (Note that Lightbend Enterprise Suite trial licenses do not have this grant.)

Copy and paste the text from that web page into a file in the correct platform-dependent location. On MacOS and Linux platforms the default location is ~/.lightbend/license and on the Windows platform it is %homePath%\.lightbend\license.

Be sure the license file has OS-appropriate line endings. For example, on Windows a license file with Unix line endings may not work.

You can ask the compiler plugin to look in a different location by specifying -P:fortify:license=..., substituting any full path you like for ....

Getting and using the translator (via sbt)

Prerequisite: install the sbt build tool (link).

Translating Scala source code for Fortify is done by a Scala compiler plugin.

You can have sbt resolve the compile plugin if you either

  • set up authentication for Lightbend’s commercial-releases repository
  • or, mirror the compiler plugin to an internal repository used at your organization. This is usually done in larger organizations.

To authenticate to the commercial-releases repo, create a ~/.lightbend/commercial.credentials file (on MacOS or Linux platforms), or a %homePath%\.lightbend\commercial.credentials file (on Windows) that looks like:

realm=Bintray
host=dl.bintray.com
user=********-****-****-****-************@lightbend
password=****************************************

but substitute user and password values that you retrieve from https://portal.lightbend.com/ReactivePlatform/Credentials .

And in your project’s build definition, add:

credentials += Credentials(
  Path.userHome / ".lightbend" / "commercial.credentials")
resolvers += "lightbend-commercial-releases" at
  "https://repo.lightbend.com/commercial-releases/"

If the compiler plugin has already been mirrored to an internal repository at your organization, you can skip the preceding steps.

Then, add the following to your top-level build.sbt:

addCompilerPlugin(
  "com.lightbend" % "scala-fortify" % "1.0.16"
    classifier "assembly"
    cross CrossVersion.patch)
scalacOptions += s"-P:fortify:build=myproject"

Substituting any build id you like for myproject. Specifying the build id causes translated files to be written to the usual location used by SCA:

  • $HOME/.fortify/sca19.1/build/myproject (Linux, MacOS)
  • %LOCALAPPDATA%\Fortify\sca19.1\build\myproject (Windows)

If you prefer to specify the output directory directly, use -P:fortify:out=... instead, filling in a filesystem path for ....

You may also want to add:

scalacOptions += "-Ystop-before:jvm"

to make compilation stop before any actual JVM classfiles are generated. (You can omit this if you want to let compilation finish.)

These changes to your build will cause the compiler plugin to run and translated files (with an .nst extension) to be generated whenever your code is compiled (e.g., with the compile task).

For the scan step, supplying the same build id again (with -b) will allow the scanner to find the translated files. For example:

sourceanalyzer -b myproject -f myproject.fpr -scan

Multi-project builds

If your build has subprojects, then you’ll need to adapt the above addCompilerPlugin(...) and scalacOptions += ... settings accordingly. (By default, the settings will apply only to your root project.)

The best way to do this depends on how your build is set up and whether you want to enable Fortify SCA on every subproject, or only some of them.

If you want to enable Fortify SCA in every subproject and you don’t mind all of the translated files getting mixed together in the top-level target directory, then simply add in ThisBuild to the settings. The sbt documentation on build-level settings for details on how this works.

To enable Fortify on a particular subproject, and to keep that subproject’s translated files in their own target directory, add the addCompilerPlugin and scalacOptions to those subprojects only.

If you want to do this across multiple subprojects without copy-and-paste, you can store the addCompilerPlugin and scalacOptions settings in a variable, and then add that variable in each subproject. This technique is shown in the sbt documentation on common settings. The resulting build definition will look something like this:

lazy val fortifySettings = Seq(
  addCompilerPlugin(...),
  scalacOptions += ...)
lazy val project1 = project ... (
  .settings(fortifySettings,
    // other settings
  )
lazy val project2 = project ... (
  .settings(fortifySettings,
    // other settings
  )

Getting and using the translator (with Maven)

Here is a sample pom.xml file showing how to use the translator in a Maven build.

It is assumed that your Lightbend credentials, retrieved from https://portal.lightbend.com/ReactivePlatform/Credentials, are in ~/.m2/settings.xml as:

...
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
                          https://maven.apache.org/xsd/settings-1.0.0.xsd">
    <servers>
        <server>
            <id>lightbend-commercial</id>
            <username>LIGHTBEND_USERNAME</username>
            <password>LIGHTBEND_PASSWORD</password>
        </server>
    </servers>
</settings>

The following example pom.xml adds the scala-maven-plugin and Fortify SCA configuration to the build file:

    <build>
        <plugins>
            <!-- Maven Build Plugins -->
            ...
            <plugin>
                <groupId>net.alchim31.maven</groupId>
                <artifactId>scala-maven-plugin</artifactId>
                <version>4.3.0</version>
                <executions>
                    <execution>
                        <goals>
                            <-- Compilation of main sources, test code is irrelevant -->
                            <goal>compile</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <scalaVersion>${scala.binary.version}</scalaVersion>
                    <args>
                        <!-- Configure the absolute path to the jar file -->
                        <arg>-Xplugin:/<PATH>/scala-fortify_2.13.1-1.0.16-assembly.jar</arg>
                        <arg>-Xplugin-require:fortify</arg>
                        <arg>-P:fortify:build=<PROJECT_NAME></arg>
                        <arg>-P:fortify:scaversion=19.1</arg>
                    </args>
                </configuration>
            </plugin>

        </plugins>
    </build>

As the build progresses, you should notice that the plugin is invoked during the Maven compile goal:

...
[INFO] Compiling 365 Scala sources to /<PROJECT_ROOT>/target/classes ...
scala-fortify 1.0.16, licensed to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx (expires: 2020-09-10T00:00Z[UTC])
scala-fortify: writing translated files to /<USER_HOME>/.fortify/sca19.1/build/<PROJECT_NAME>
...

Getting and using the translator (with Gradle)

Here is a sample build.gradle file showing how to use the translator in a Gradle build.

It is assumed that your Lightbend credentials, retrieved from https://portal.lightbend.com/ReactivePlatform/Credentials, are in ~/.gradle/gradle.properties as:

lightbendUser=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx@lightbend
lightbendPassword=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Sample build.gradle:

apply plugin: 'scala'

repositories {
    mavenCentral()
    maven {
        credentials {
            username lightbendUser
            password lightbendPassword
        }
        url = 'https://repo.lightbend.com/commercial-releases/'
    }
}

ext {
    scalaBinaryVersion = '2.12'
    scalaVersion = '2.12.10'
    fortifyPluginVersion = '1.0.16'
}

configurations {
    lightbendFortifyPlugin
}

dependencies {
    compile("org.scala-lang:scala-library:$scalaVersion") // specify Scala version
    lightbendFortifyPlugin group: 'com.lightbend', name: "scala-fortify_$scalaVersion", version: fortifyPluginVersion, classifier: "assembly"
}

tasks.withType(ScalaCompile) {
  scalaCompileOptions.additionalParameters = [
    "-Xplugin:" + configurations.lightbendFortifyPlugin.asPath,
    "-Xplugin-require:fortify",
    "-P:fortify:build=myproject"
  ]
}

When using with Play Framework

Gradle also has support for Play Framework and you mix both Fortify and Play configuration in your project, for example:

plugins {
    id 'play'
    id 'scala'
}

ext {
    playVersion = '2.6.12'
    scalaVersion = '2.12.10'
    scalaBinaryVersion = '2.12'
    fortifyPluginVersion = '1.0.16'
}

model {
    components {
        play {
            platform play: playVersion, scala: scalaBinaryVersion, java: '1.8'
            injectedRoutesGenerator = true

            sources {
                twirlTemplates {
                    defaultImports = TwirlImports.SCALA
                }
            }
        }
    }
}

configurations {
    lightbendFortifyPlugin
}

dependencies {
    // Example of play dependencies
    play "com.typesafe.play:play-guice_$scalaBinaryVersion:$playVersion"
    play "com.typesafe.play:play-ahc-ws_$scalaBinaryVersion:$playVersion"
    play "com.typesafe.play:play-logback_$scalaBinaryVersion:$playVersion"
    play "com.typesafe.play:filters-helpers_$scalaBinaryVersion:$playVersion"

    lightbendFortifyPlugin group: 'com.lightbend', name: "scala-fortify_$scalaVersion", version: fortifyPluginVersion, classifier: "assembly"
}

repositories {
    jcenter()
    maven {
        name "lightbend-maven-releases"
        url "https://repo.lightbend.com/lightbend/maven-release"
    }
    ivy {
        name "lightbend-ivy-release"
        url "https://repo.lightbend.com/lightbend/ivy-releases"
        layout "ivy"
    }

    // Fortify repository
    maven {
        credentials {
            username lightbendUser
            password lightbendPassword
        }
        url = 'https://repo.lightbend.com/commercial-releases'
    }
}

tasks.withType(PlatformScalaCompile) {
    scalaCompileOptions.additionalParameters = [
            "-Xplugin:" + configurations.lightbendFortifyPlugin.asPath,
            "-Xplugin-require:fortify",
            "-P:fortify:build=myproject"
    ]
}

You can also see a sample application here.

Getting and using the translator (manually)

Prerequisite: install the Scala compiler (link).

In the following instructions, substitute the actual full Scala 2.13.x or 2.12.x or 2.11.x version you are using; we use 2.13.1 as the example version.

Using the username and password that you retrieve from https://portal.lightbend.com/ReactivePlatform/Credentials , you can download the compiler plugin JAR from:

https://repo.lightbend.com/commercial-releases/com/lightbend/scala-fortify_2.13.1/1.0.16/scala-fortify_2.13.1-1.0.16-assembly.jar

Then, supposing you have scala-fortify_2.13.1-assembly.jar in your current working directory, you can do e.g.:

scalac -Xplugin:scala-fortify_2.13.1-assembly.jar \
  -Xplugin-require:fortify \
  -Ystop-before:jvm \
  -P:fortify:build=myproject \
  *.scala

Substituting your own build id for myproject. (Or, use the -P:fortify:out=... to specify the output directory directly.)

When build id support is enabled, it is currently assumed that you are running a version of Fortify SCA in the 19.1 series, so that translated files are written to ~/.fortify/sca19.1 (Linux, MacOS) or %LOCALAPPDATA%\Fortify\sca19.1 (Windows). If you are using some other version of Fortify SCA, for example some version in the 17.2 series, add e.g.:

-P:fortify:scaversion=17.2

Including -Ystop-before:jvm, as shown above, makes compilation stop before any actual JVM classfiles are generated. You can also omit it if you want to let compilation finish.

For the scan step, supplying the build id again will allow the scanner to find the translated files. For example:

sourceanalyzer -b myproject -f myproject.fpr -scan

Using the translator (other build tools)

If you are using a build tool other than sbt, then:

  • Obtain the compiler plugin JAR using the instructions in the previous section
  • Use whatever your build tool’s mechanism is for customizing the options passed to scalac, and pass the additional options shown in the previous section.

Fortify on Demand

Micro Focus Fortify on Demand supports Scala.

To submit something to Fortify on Demand, you need to generate a Mobile Build Session (.mbs) file. After translating your Scala code with -P:fortify:build=... enabled, you run sourceanalyzer -b <build-id> -export-build-session <file.mbs> to generate a session file suitable for upload.

Please see the Fortify on Demand documentation for more information on preparing Scala applications. To access the documentation, log in to Fortify on Demand, select Documentation from the account menu, and run a search for “Preparing Scala Application Files”.

Known issues

To report an issue, please open a support ticket with either Lightbend or Micro Focus.

  • Newer Java versions than Java 8 (such as Java 11) may work but are not currently officially supported. (issue 222, issue 223)
  • Mixed Scala and Java codebases require separately translating the Scala and Java sources. Depending on the dependency structure of the code, not all issues involving both languages may be found. (issue 180)
  • Scala 2.12.9 is not supported; please use 2.12.8 or 2.12.10 instead (issue 340)
  • Some pattern matches may produce spurious “Dead Code : Expression is Always false” reports. (issue 221)
  • Use of do ... while may produce spurious “null dereference” reports. (issue 208)
  • When method calls are nested, all issues are reported as occurring on the line of code containing the outermost call. (issue 204)
  • Not all characters are supported in build ids; - and _ work but other special characters may not. (issue 174)
  • On Scala 2.11, the -Ydelambdafy flag is not supported and results in “unknown code Function” errors. Disable this flag when using the compiler plugin. (issue 215)

Release notes

1.0.16 (September 12, 2019)

  • enabling the plugin no longer requires explicitly declaring transitive dependencies (issue 279)
  • generated NST files are smaller now (as much as 95% smaller!) (issue 339)
  • more vulnerabilities are found in a variety of situations (issues 328, 337, 338)
  • Scala 2.13 support was improved; for best 2.13 support, also update Fortify to latest security rules (issues 329, 331, 335)
  • Scala 2.12.9 is not supported; please use 2.12.8 or 2.12.10 instead (issue 340)

available for Scala versions: 2.13.{0-1}, 2.12.{3-8,10}, 2.11.{6-8,11-12}

1.0.15 (June 21, 2019)

  • recommended version of Fortify SCA is now 19.1.0 (formerly 18.20); by default, files are now written to an sca19.1 directory (formerly sca18.2) (issue 315)
  • add full support for Scala 2.13 (issue 156)
  • when the plugin starts, it now prints the absolute path to the directory name where translated files are written, to aid with configuration and troubleshooting (issue 320)
  • character literals containing a backslash escape sequence are now handled correctly (issue 325)

available for Scala versions: 2.13.0, 2.12.{3-8}, 2.11.{6-8,11-12}

1.0.13 (December 2, 2018)

  • recommended version of Fortify SCA is now 18.20 (formerly 18.10); by default, files are now written to an sca18.2 directory (formerly sca18.1) (issue 310)

available for Scala versions: 2.11.{6-8,11-12}, 2.12.{3-8}

1.0.12 (October 2, 2018)

  • improved tracking of data flow through trait methods (issue 297)
  • improved tracking of data flow across multiple source files (issue 302)
  • improved accuracy of line number information in reported vulnerabilities (issue 301)

available for Scala versions: 2.11.{6-8,11-12}, 2.12.{3-8}

1.0.10 (June 12, 2018)

  • support class literals with type parameters (issue 294)

1.0.9 (April 30, 2018)

  • recommended version of Fortify SCA is now 18.10 (formerly 17.20).
  • by default, files are now written to an sca18.1 directory (formerly sca17.2)
  • vulnerabilities involving Twirl templates are now reported as occurring in the original .html file, not the generated .scala file (issue 159)

1.0.7 (March 14, 2018)

  • plugin is now published Maven-style, not Ivy-style; as a result, build configuration instructions have changed (issue 277)
  • emit fewer “Value Never Read” false positives (issue 258 (partial fix))

1.0.5 (February 7, 2018)

  • handle source files with any character encoding (issue 267)
  • Scala 2.11.6 and 2.11.7 are now supported (issue 217)

1.0.2 (January 11, 2018)

  • the location of the Lightbend license file is now configurable with -P:fortify:license=... (issue 263)

1.0.1 (December 20, 2017)

  • enabling the plugin no longer interferes with Scaladoc generation (issue 260)

1.0.0 (December 6, 2017)

  • first general release