You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: src/content/blog/semgrep-vs-codeql-vs-opentaint.mdx
+46-6Lines changed: 46 additions & 6 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -267,7 +267,33 @@ public MessageContent(String text) {
267
267
}
268
268
```
269
269
270
-
All three tools detect this first constructor-based example. The next variant extends the field chain further:
270
+
All three tools detect this first constructor-based example. Each version also has a secure variant that reads `secureText` instead of `text` — the `MessageContent` constructor escapes the value with `HtmlUtils.htmlEscape` before storing it:
271
+
272
+
```java
273
+
// Profile.java
274
+
public class MessageContent {
275
+
public String text;
276
+
public String secureText;
277
+
278
+
public MessageContent(String text) {
279
+
this.text = "<h1>Notification: " + text + "</h1>";
@RequestParam(defaultValue = "New Message") String content) {
291
+
Profile.MessageTemplate template = new Profile.MessageTemplate(content);
292
+
return template.body.content.secureText;
293
+
}
294
+
```
295
+
296
+
The next variant extends the field chain further:
271
297
272
298
```java
273
299
// NotificationController.java
@@ -281,13 +307,27 @@ public String generateNotification(
281
307
}
282
308
```
283
309
284
-
Here the tools diverge. Semgrep Code and OpenTaint track the deeper field chain. CodeQL does not report the vulnerability — its taint-tracking model does not propagate through field stores and loads on heap objects beyond a limited depth, so the six-deep accessor chain exceeds what its default `java/xss` query tracks.
310
+
And its secure counterpart:
311
+
312
+
```java
313
+
// NotificationController.java — secure version
314
+
@GetMapping("/notifications/secureGenerate")
315
+
@ResponseBody
316
+
public String generateSecureNotification(
317
+
@RequestParam(defaultValue = "New Message") String content) {
318
+
Profile.UserProfile profile = new Profile.UserProfile(content);
Here the tools diverge. Semgrep Code and OpenTaint track the deeper field chain. CodeQL does not report the vulnerability — its taint-tracking model does not propagate through field stores and loads on heap objects beyond a limited depth, so the six-deep accessor chain exceeds what its default `java/xss` query tracks. On the secure variants, Semgrep Code produces false positives — it flags the sanitized `secureText` field as vulnerable, unable to distinguish it from the tainted `text` field on the same object.
285
325
286
326
Results:
287
327
288
-
- ✅ **Semgrep Code**: Detects both simple and complex versions.
328
+
- ⚠️ **Semgrep Code**: Detects both simple and complex vulnerable versions but produces false positives on secure variants.
289
329
- ⚠️ **CodeQL**: Handles the simple version but misses the complex one.
290
-
- ✅ **OpenTaint**: Correctly handles both versions, including secure variants.
330
+
- ✅ **OpenTaint**: Correctly handles both versions, filtering out secure variants.
291
331
292
332
### Pointer analysis — builder pattern with virtual dispatch
293
333
@@ -394,7 +434,7 @@ This comparison has deliberate constraints worth naming.
@@ -408,7 +448,7 @@ This comparison has deliberate constraints worth naming.
408
448
Each tool plateaus at a different depth of analysis:
409
449
410
450
- **Semgrep CE** handles syntax matching and local taint tracking but stops at function boundaries.
411
-
- **Semgrep Code** extends through inter-procedural analysis and field sensitivity but does not follow builder patterns or virtual dispatch.
451
+
- **Semgrep Code** extends through inter-procedural analysis and field sensitivity but produces false positives on secure field variants and does not follow builder patterns or virtual dispatch.
412
452
- **CodeQL** covers most cases but its analysis limits surface at deep field chains and virtual calls.
413
453
- **OpenTaint** tracks data through all five cases — including builder state, constructor chains, and interface dispatch — using the same pattern rules throughout.
0 commit comments