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.
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.