Static Code Analysis¶
Version: 3.1
When you set up the build for a WSO2 product, wire in the static analysis tooling described below. Tool-by-tool tutorials, install steps, and configuration references live in the tools' own documentation, linked below. This page covers what to run, the thresholds to gate on, and the WSO2-specific patterns worth encoding as custom rules.
Static analysis complements Dynamic Analysis with OWASP ZAP and Dependency Vulnerability Analysis.
FindBugs is defunct
Earlier versions of this document referenced FindBugs and FindBugs-IDEA. FindBugs has been unmaintained since 2015 and is formally archived; the project moved to SpotBugs in 2017, and Find Security Bugs now runs on SpotBugs. Use SpotBugs + Find Security Bugs for new work; migrate any legacy build that still references FindBugs.
What every product build should run¶
Wire all four into the PR builder:
- OWASP-Top-10-focused SAST: SpotBugs + Find Security Bugs (Java);
gosec(Go). - General-purpose static analyzer: SpotBugs core (Java);
staticcheck(Go). - Semantic-rules engine for codebase-specific patterns, either Semgrep or GitHub CodeQL. These catch what generic tools cannot: usage of internal WSO2 helpers, secrets in source, and anti-patterns from past audits.
- Vulnerable-dependency scanner: covered in Dependency Vulnerability Analysis.
Findings above the agreed severity threshold fail the PR build. Suppressions go in an audited allow-list with a documented rationale; blanket suppressions are rejected at review.
Tool references¶
- SpotBugs: project site · Maven plugin · SpotBugs-IDEA IntelliJ plugin (the legacy
FindBugs-IDEAis unmaintained; uninstall and replace). - Find Security Bugs (SpotBugs plugin, ~120 security rules): project site.
gosec: github.com/securego/gosec.staticcheck: staticcheck.dev.- Semgrep: semgrep.dev.
- CodeQL: codeql.github.com.
reviewdog(surface SAST findings as inline PR comments): github.com/reviewdog/reviewdog.
Thresholds and CI integration¶
When wiring these into your product's CI:
- Pin the Maven SpotBugs plugin in the parent POM with
<effort>Max</effort>,<threshold>Low</threshold>, and<failOnError>true</failOnError>. New code should be quiet at this setting. Pin both the SpotBugs and Find Security Bugs plugin versions; check their sites for current releases. gosecin CI:gosec -severity high -confidence medium -exclude-dir=vendor ./..., which fails on any high-severity finding.- SARIF output from each tool uploaded to the GitHub Security tab. Semgrep and CodeQL produce SARIF natively;
gosecsupports it directly; SpotBugs XML can be converted via a reviewdog adapter orspotbugs-sarif. - SAST runs as a parallel step alongside build/test in the PR builder.
reviewdogsurfaces findings as inline PR comments rather than a single "build failed" line. - Track findings over time. A SAST tool producing 1000 findings on first run with no follow-up is doing nothing. Either fix or formally accept each.
Suppressions¶
Narrow, with rationale, in the tool-native suppression format:
<!-- spotbugs-exclude.xml -->
<FindBugsFilter>
<Match>
<Bug pattern="EI_EXPOSE_REP"/>
<Class name="org.wso2.example.legacy.LegacyDTO"/>
<!-- Reason: public mutable internal array is the existing contract;
rewrite tracked in WSO2-XXXX. -->
</Match>
</FindBugsFilter>
Annotation-based suppression (@SuppressFBWarnings) is acceptable on a single method or field; both forms must include a rationale comment.
WSO2-specific Semgrep rules to author¶
These are anti-patterns from the WSO2 Secure Coding Guide that generic SAST tools do not catch. They are high-value to encode as Semgrep (or CodeQL) rules in a shared WSO2 ruleset:
Java:
Cipher.getInstance("RSA")or"AES"without explicit mode and padding.MessageDigest.getInstance("MD5")and"SHA-1"for security purposes.NoopHostnameVerifier.INSTANCEorAllowAllHostnameVerifier.ObjectInputStreamconstruction withoutObjectInputFilter.Runtime.getRuntime().exec(<single String arg>)outside test code.- Missing
PrivilegedCarbonContext.endTenantFlow()afterstartTenantFlow(). - Direct
Cipher.getInstancecalls outside the centralCryptoUtilfacade.
Go:
tls.Config{InsecureSkipVerify: true}outside_test.go.aes.NewCiphercalled from anywhere outside the project's central crypto helper package.==comparison of MAC / HMAC byte slices (must behmac.Equal).text/templateused to render HTML (must behtml/template).panic(in handlers / services (panic is reserved for init failures).json.UnmarshalwithoutDisallowUnknownFieldson inbound request bodies.os/execinvocations ofsh -cwith interpolated input.
Each rule lives in the shared WSO2 Semgrep ruleset with a short description, the canonical example, and a link to the Secure Coding Guide entry that motivated it.