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 projects

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.

Similarly, akka-http-webgoat repository contains an example web service that uses Akka-Http. 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
  • Java 11
  • Java 17

The following Scala versions are supported:

  • Scala 2.13.0 or newer
  • Scala 2.12.6 or newer
  • except 2.12.9; please use 2.12.8 or 2.12.10+ instead
  • Scala 2.11.8 or newer

The latest patch releases are recommended (2.13.6, 2.12.15, and 2.11.12, as of September 2021).

To translate Scala code for Fortify to scan, you use the Lightbend compiler plugin, using a license file supplied by Micro Focus.

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

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

Fortify 21.1’s own system requirements are documented here.

License installation

The license that you obtain from Micro Focus should look like:

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

DO NOT TAMPER WITH THIS FILE - ...

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. The plugin is available from Maven Central.

sbt will retrieve and use the plugin if you add the following to your top-level build.sbt:

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

You can substitute 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/sca21.1/build/myproject (Linux, MacOS)
  • %LOCALAPPDATA%\Fortify\sca21.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)

Translating Scala source code for Fortify is done by a Scala compiler plugin. The plugin is available from Maven Central.

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

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>
                    <args>
                        <arg>-P:fortify:build=<PROJECT_NAME></arg>
                        <arg>-P:fortify:scaversion=21.1</arg>
                    </args>
                    <compilerPlugins>
                        <compilerPlugin>
                            <groupId>com.lightbend</groupId>
                            <artifactId>scala-fortify_2.13.6</artifactId>
                            <version>1.0.21</version>
                        </compilerPlugin>
                    </compilerPlugins>
                </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.21, licensed to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx (expires: 2020-09-10T00:00Z[UTC])
scala-fortify: writing translated files to /<USER_HOME>/.fortify/sca21.1/build/<PROJECT_NAME>
...

Getting and using the translator (with Gradle)

Translating Scala source code for Fortify is done by a Scala compiler plugin. The plugin is available from Maven Central.

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

Sample build.gradle:

apply plugin: 'scala'

repositories {
    mavenCentral()
    mavenLocal()
}

ext {
    scalaBinaryVersion = '2.13'
    scalaVersion = '2.13.6'
    fortifyPluginVersion = '1.0.21'
}

configurations {
    lightbendFortifyPlugin
}

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

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.8.8'
    scalaVersion = '2.13.6'
    scalaBinaryVersion = '2.13'
    fortifyPluginVersion = '1.0.21'
}

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
}

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"
    }
}

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

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.6 as the example version.

You can download the compiler plugin JAR from Maven Central from the following URL:

https://repo1.maven.org/maven2/com/lightbend/scala-fortify_2.13.6/1.0.21/scala-fortify_2.13.6-1.0.21.jar

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

scalac -Xplugin:scala-fortify_2.13.6-1.0.21.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 21.1 series, so that translated files are written to ~/.fortify/sca21.1 (Linux, MacOS) or %LOCALAPPDATA%\Fortify\sca21.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 help menu near the top right corner (or follow this link), and search for “Preparing Scala Application Files” (or follow this link – the exact URL may be subject to change).

Known issues

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

  • 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.21 (August 10, 2021)

  • the translator is now available from Maven Central; it no longer requires special credentials to resolve and download (issue 373)
  • the translator is no longer published with the “assembly” classifier; users of previous versions will need to update their dependencies to omit classifier "assembly" (issue 373)

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

1.0.20 (July 22, 2021)

  • recommended version of Fortify SCA is now 21.1.1 (formerly 20.2); by default, files are now written to an sca21.1 directory (issue 370)
  • Java 17 is now officially supported (issue 346)

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

1.0.19 (March 25, 2021)

  • improved handling of == and != operators, resulting in fewer “null dereference” false positives, fewer “dead code” false positives (issues 356, 357, 358)

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

1.0.18 (November 21, 2020)

  • recommended version of Fortify SCA is now 20.2 (formerly 20.1); by default, files are now written to an sca20.2 directory (formerly sca20.1) (issue 350)

available for Scala versions: 2.13.{0-5}, 2.12.{6-8,11-13}, 2.11.{8,11-12}

1.0.17 (August 5, 2020)

  • recommended version of Fortify SCA is now 20.1 (formerly 19.2); by default, files are now written to an sca20.1 directory (formerly sca19.1) (issue 350)

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

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)
  • Java 11 is now officially supported (issue 223)

available for Scala versions: 2.13.{0-3}, 2.12.{3-8,11-12}, 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