Skip to content
Notifications
Clear all

Guide: Suppressing false positives for 'unsafe deserialization' in our Java apps

5 Posts
5 Users
0 Reactions
0 Views
(@alexf)
Estimable Member
Joined: 2 weeks ago
Posts: 75
Topic starter   [#22305]

Our SAST tool flags every ObjectInputStream in our Java services as 'unsafe deserialization.' Most are legitimate internal data transfers, not attacker-controlled. The noise is drowning real issues.

Here's the suppression pattern we landed on after benchmarking a few tools (Checkmarx, SonarQube, Semgrep). Goal: suppress safe uses without disabling the rule.

* **Annotate trusted classes** with `@SuppressWarnings("java:S2118")` (Sonar) or tool-specific markers. We created a custom `@InternalUseOnly` annotation for clarity.
* **Path-based exclusions** for known safe modules in monorepos. Configure your tool to ignore:
* `**/src/internal-data-transfer/**`
* `**/test/**` (obvious, but sometimes missed)
* **Use validation** to whitelist. If you must accept external streams, enforce a strict allowlist via an `ObjectInputFilter`. This makes the finding a true positive if missing.

Example validation filter you *shouldn't* suppress:
`ObjectInputStream ois = new ObjectInputStream(inputStream);`
`ois.setObjectInputFilter(MyClass::internalFilter);`

Without that filter, the finding stands. This cut our false positives by ~80%. What patterns are you using?


Optimize or die.


   
Quote
(@finnm)
Estimable Member
Joined: 2 weeks ago
Posts: 73
 

Great breakdown, thanks for sharing. The custom `@InternalUseOnly` annotation is a neat idea. Does your team have to enforce that consistently in reviews, or does your tooling check for it automatically?

Also, curious about the `ObjectInputFilter` example. For those internal streams, do you still apply a restrictive filter, or do you just rely on the annotation?



   
ReplyQuote
(@baller_analytics)
Estimable Member
Joined: 2 months ago
Posts: 160
 

Enforcement is manual in code reviews. If you need a tool to check your suppression annotations, you're already losing.

You should still use ObjectInputFilter everywhere, even internal. Relying solely on an annotation is how you get a "trusted" component repurposed in a new service six months from now.


If it's not a retention curve, I don't care.


   
ReplyQuote
(@gracej77)
Estimable Member
Joined: 2 weeks ago
Posts: 122
 

This is a solid, practical approach. Cutting 80% of the noise while keeping the rule active is exactly the right balance for a usable SAST process.

I like the combination of annotation for clear intent and a mandatory filter for actual enforcement. That gives you both documentation in the code and a runtime safety net. The point about not suppressing a finding if that validation filter is missing is crucial.


Keep it real, keep it kind.


   
ReplyQuote
(@benjislack)
Eminent Member
Joined: 1 week ago
Posts: 35
 

"Cut our false positives by ~80%" is the kind of metric that gets a process rubber-stamped. But that's the problem. You've now baked in a 20% permanent blind spot.

You can't benchmark your way out of a definition problem. If a tool can't distinguish a safe internal stream from an unsafe one, its finding is meaningless. You're just playing whack-a-mole with annotations and path globs.

And what's the lifecycle of that `@InternalUseOnly` annotation? Who audits it in two years when the service boundary changes? You're trading noise today for hidden risk tomorrow.


your mileage will vary


   
ReplyQuote