Fortify SCA for Scala

Fortify SCA (Static Code Analyzer), by OpenText, finds security issues in source code. For an overview, visit opentext.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 OpenText and Lightbend.

Supported language features

All of Scala is supported by the translator.

Supported security vulnerabilities

A full list is available on the OpenText site.

Sample projects

The scala-fortify-sample repository contains a small command line program with a couple of vulnerabilities. It illustrates how to use the translator with the sbt build tool.

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.13, 2.12.19, and 2.11.12, as of February 2024).

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

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

  • be a licensed Fortify SCA user. Fortify SCA version 23.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 23.1’s own system requirements are documented here.

License installation

Since Fortify version 22, the license for the translator can be found in the Fortify SCA distribution from OpenText in <Fortify_SCA_Installation_Dir>/plugins/lightbend. (If you are on an older Fortify version, ask OpenText for the license.)

The license file should look like:

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

DO NOT TAMPER WITH THIS FILE - ...

Copy that file to 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.26"
    cross CrossVersion.patch)
scalacOptions += s"-P:fortify:build=myproject"

Note that addCompilerPlugin(...) is just shorthand for libraryDependencies += compilerPlugin(...). In some contexts, you may need to switch to the latter form.

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

Excluding source files

To exclude some source files from translation, add -P:fortify:exclude=... to scalacOptions, replacing ... with one or more path specifiers. Specifiers are matched against the absolute paths of the source files.

Specifiers may use glob syntax such as * and **, for example -P:fortify:exclude=**/test/*.scala. The supported glob syntax is that of Java’s PathMatcher, as documented here.

If you have multiple path specifiers, separate them with colons (Linux, MacOS) or semicolons (Windows). Example: -P:fortify:exclude=**/Foo.scala:**/Bar.scala.

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.

Enabling Fortify build-wide

If you want to enable Fortify SCA in every subproject and have all of the code scanned together, then add ThisBuild / to the settings. The sbt documentation on build-level settings explains ThisBuild.

Note that it’s normal for multiple subprojects to share the same build id, so that Fortify can follow data flows where code in one subproject calls code in another subproject.

If you want, the Fortify settings can go a separate .sbt file, for example fortify.sbt.

This approach is illustrated in the scala-fortify-sample sample repo.

Enabling Fortify only for some subprojects

In this scenario, instead of using ThisBuild, you will need to use addCompilerPlugin and alter scalacOptions in those subprojects only.

How to accomplish this may depend on the details of how your build is set up. Regardless, here are some guidelines.

It is typical to store the addCompilerPlugin and scalacOptions settings in a variable, and then add that variable in each subproject. This technique is documented 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
  )

Note that in this type of setup, we don’t know of any way to keep everything Fortify-related in a separate fortify.sbt file.

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=23.1</arg>
                    </args>
                    <compilerPlugins>
                        <compilerPlugin>
                            <groupId>com.lightbend</groupId>
                            <artifactId>scala-fortify_2.13.13</artifactId>
                            <version>1.0.26</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.26, licensed to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx (expires: 2024-09-10T00:00Z[UTC])
scala-fortify: writing translated files to /<USER_HOME>/.fortify/sca23.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.13'
    fortifyPluginVersion = '1.0.26'
}

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.13'
    scalaBinaryVersion = '2.13'
    fortifyPluginVersion = '1.0.26'
}

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(ScalaCompile) {
    scalaCompileOptions.additionalParameters = [
            "-Xplugin:" + configurations.lightbendFortifyPlugin.asPath,
            "-Xplugin-require:fortify",
            "-P:fortify:build=myproject"
    ]
}

Getting and using the translator (manually)

Prerequisite: install your specific desired version of the Scala 2 compiler. All versions, current and past, are available at 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.13 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.13/1.0.26/scala-fortify_2.13.13-1.0.26.jar

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

scalac -Xplugin:scala-fortify_2.13.13-1.0.26.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 23.1 series, so that translated files are written to ~/.fortify/sca23.1 (Linux, MacOS) or %LOCALAPPDATA%\Fortify\sca23.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

OpenText 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 contact OpenText support. (Or, if you are a Lightbend subscriber, you may contact Lightbend if you like.)

  • 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)
  • 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.26 (February 21, 2024)

  • fix some false positives by always declaring SAM types in the closure (issue 76)

available for Scala versions: 2.13.{3-13}, 2.12.{11-19}, 2.11.{11-12}

1.0.25 (September 7, 2023)

  • minor fixes

available for Scala versions: 2.13.{3-12}, 2.12.{11-18}, 2.11.{11-12}

1.0.24 (July 18, 2023)

  • recommended version of Fortify SCA is now 23.1 (formerly 22.1); by default, files are now written to an sca23.1 directory (issue 414)

available for Scala versions: 2.13.{3-11}, 2.12.{11-18}, 2.11.{11-12}

1.0.23 (July 16, 2023)

  • source files can now be excluded from translation using new option -P:fortify:exclude=... (issue 403)

available for Scala versions: 2.13.{3-11}, 2.12.{11-18}, 2.11.{11-12}

1.0.22 (June 30, 2022)

  • recommended version of Fortify SCA is now 22.1 (formerly 21.1); by default, files are now written to an sca22.1 directory (issue 392)

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

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-8}, 2.12.{6-8,11-16}, 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