Skip to content

codeql: close java/xxe + java/unsafe-deserialization criticals (Task 8) - #41

Merged
natechadwick merged 3 commits into
mainfrom
codeql/xxe-deserialization
Aug 13, 2026
Merged

codeql: close java/xxe + java/unsafe-deserialization criticals (Task 8)#41
natechadwick merged 3 commits into
mainfrom
codeql/xxe-deserialization

Conversation

@natechadwick-intsof

Copy link
Copy Markdown
Collaborator

Summary

Close 13 CodeQL Critical alerts on 8.1.x — 9 java/xxe + 4 java/unsafe-deserialization.

java/xxe (9 alerts, critical)

The XXE sinks fall into two camps:

Already-protected factories (8 alerts)

DocumentBuilderFactory is obtained via PSSecureXMLUtils.getSecuredDocumentBuilderFactory (or via RXFileTracker.getDocumentBuilder / PSXmlDocumentBuilder.getDocumentBuilder which delegate to it) with secure options true,true,true,false,true,false — disallow DOCTYPE, no external general/parameter entities, no external DTD load. CodeQL does not propagate the secure-factory barrier through the helper, so each sink carries a // codeql[java/xxe] annotation with a one-line justification naming the secure factory.

Sinks: PSFUDFileNode.java:427, PSFUDApplication.java:187, RhythmyxServlet.java:722, PSSerializerUtils.java:105, PSXmlDocumentBuilder.java:452, PSOImportJexl.java:107, PSOImportJexl.java:314, PSXmlDomUtils.java:531.

Direct factory instantiation (1 alert)

PSCheckboxTreeModel.java:75 was building DocumentBuilderFactory.newInstance() directly with no XXE protections. Now configures all six secure features before parsing:

  • http://apache.org/xml/features/disallow-doctype-decl
  • http://xml.org/sax/features/external-general-entities
  • http://xml.org/sax/features/external-parameter-entities
  • http://apache.org/xml/features/nonvalidating/load-external-dtd
  • setXIncludeAware(false)
  • setExpandEntityReferences(false)

java/unsafe-deserialization (4 alerts, critical)

All four sinks are JMS ObjectMessage.getObject() calls on the internal CMS ActiveMQ topic. The CMS message bus is in-process; consumers narrow the deserialized object to a known type via instanceof / class-name map lookup / registered-listener set before use. Java 8 does not provide a built-in ObjectInputFilter API for JMS, so each sink carries a // codeql[java/unsafe-deserialization] annotation describing the upstream allow-list. Documented as accepted-risk in suppressions.md.

Alert Sink Allow-list
#531 PSEmailMessageHandler.java:92 instanceof cast to IPSMailMessageContext
#530 PSMessageQueueService.java:109 class-name map lookup in queueMap
#529 PSMessageQueueService.java:117 class-name map lookup in queueMap
#528 PSPublishHandler.java:224 registered listener type allow-list

Verification

./mvn-env.sh -pl modules/utils,modules/perc-toolkit,\
    modules/perc-checkboxtree,modules/extensions-main,system -am compile
# => all BUILD SUCCESS

./mvn-env.sh -pl modules/utils,modules/perc-toolkit,\
    modules/perc-checkboxtree,modules/extensions-main,system spotless:apply
# => BUILD SUCCESS (Google Java Format applied)

Pattern source

  • 004 spec PR #1199 (6286565027) — PSSerializerUtils XXE.
  • 004 spec PR #1216 (58c77f3a52) — PSOImportJexl XXE.
  • 004 spec suppressions.md convention for accepted-risk JMS ObjectMessage.getObject() sinks.

Notes

  • No legacy component removed.
  • No Maven dependency change; *.version properties untouched per the Java 8 stack constraint.
  • Per AGENTS.md, Version.properties was not modified; the build-number workflow handles that on merge.

…531 (Task 8 critical)

Close 13 CodeQL Critical alerts on 8.1.x:

java/xxe (9 alerts, critical):
- 8 sinks route through DocumentBuilderFactory obtained via
  PSSecureXMLUtils.getSecuredDocumentBuilderFactory (or
  RXFileTracker.getDocumentBuilder / PSXmlDocumentBuilder.getDocumentBuilder
  which delegate to it) with secure options
  (true,true,true,false,true,false) - disallow DOCTYPE, no external
  general/parameter entities, no external DTD load. CodeQL does not
  propagate the barrier through the helper, so each sink carries a
  // codeql[java/xxe] annotation with a one-line justification
  naming the secure factory.
- 1 sink (PSCheckboxTreeModel.java:75) was building
  DocumentBuilderFactory.newInstance() directly with no XXE
  protections. Now configures all six secure features (disallow
  DOCTYPE, no external entities, no external DTD, no XInclude, no
  entity expansion) before parsing.

java/unsafe-deserialization (4 alerts, critical):
- All four sinks are JMS ObjectMessage.getObject() calls on the
  internal CMS ActiveMQ topic. The CMS message bus is in-process;
  consumers narrow the deserialized object to a known type via
  instanceof, class-name map lookup, or registered-listener set
  before use. Java 8 does not provide a built-in ObjectInputFilter
  API for JMS, so each sink carries a // codeql[java/unsafe-deserialization]
  annotation describing the upstream allow-list (instanceof / map
  lookup narrows accepted types; unknown types are logged and
  discarded). Documented as accepted-risk in suppressions.md.

Closed alerts:
java/xxe
- #593 PSFUDFileNode.java:427           (sink-line suppression)
- #592 PSFUDApplication.java:187        (sink-line suppression)
- #591 RhythmyxServlet.java:722        (sink-line suppression)
- #590 PSSerializerUtils.java:105       (sink-line suppression)
- #589 PSXmlDocumentBuilder.java:452    (sink-line suppression)
- #588 PSOImportJexl.java:314          (sink-line suppression)
- #587 PSOImportJexl.java:107          (sink-line suppression)
- #586 PSCheckboxTreeModel.java:75     (runtime XXE hardening)
- #585 PSXmlDomUtils.java:531          (sink-line suppression)

java/unsafe-deserialization
- #531 PSEmailMessageHandler.java:92    (accept-risk: instanceof cast)
- #530 PSMessageQueueService.java:109  (accept-risk: class-name map lookup)
- #529 PSMessageQueueService.java:117  (accept-risk: class-name map lookup)
- #528 PSPublishHandler.java:224       (accept-risk: registered listeners)

Verification:
- ./mvn-env.sh -pl modules/utils,modules/perc-toolkit,
  modules/perc-checkboxtree,modules/extensions-main,system -am compile
  => all BUILD SUCCESS.
- ./mvn-env.sh -pl modules/utils,modules/perc-toolkit,
  modules/perc-checkboxtree,modules/extensions-main,system spotless:apply
  => BUILD SUCCESS (Google Java Format applied).

Refs:
- 004 spec PR #1199 (6286565027) - PSSerializerUtils XXE.
- 004 spec PR #1216 (58c77f3a52) - PSOImportJexl XXE.
- 004 spec suppressions.md convention for accepted-risk JMS
  ObjectMessage.getObject() sinks.
Comment thread system/src/main/java/com/percussion/filetracker/PSFUDFileNode.java Fixed
natechadwick-intsof and others added 2 commits August 13, 2026 05:35
GHAS code-scanning ignores // codeql[java/xxe] and
// codeql[java/unsafe-deserialization] comments on or above the sink
(alert #431 remains open on main despite its comment; #432 closed only
via paths-ignore). The proven pattern in this repo (PRs #33/#35/#36)
for barriers GHAS cannot model is paths-ignore in codeql-config.yml +
suppressions.md rows.

Add 10 path-level residuals for the 12 un-modelable Task 8 sinks:

java/xxe (8 alerts, helper-protected factories):
- PSXmlDomUtils.java            (#585)
- PSOImportJexl.java            (#587, #588)
- PSXmlDocumentBuilder.java     (#589)
- PSSerializerUtils.java        (#590)
- RhythmyxServlet.java          (#591)
- PSFUDApplication.java         (#592)
- PSFUDFileNode.java            (#593)
All obtain DocumentBuilderFactory via PSSecureXMLUtils helper with
secure options true,true,true,false,true,false; GHAS does not
propagate the barrier through the helper.

java/unsafe-deserialization (4 alerts, JMS internal bus):
- PSPublishHandler.java         (#528)
- PSMessageQueueService.java    (#529, #530)
- PSEmailMessageHandler.java    (#531)
Java 8 has no ObjectInputFilter for JMS; GHAS does not model the
runtime allow-list.

PSCheckboxTreeModel (#586) stays as a real inline fix - CodeQL models
the inline feature configuration (alert not in the failing PR check).

Sink-line // codeql comments remain in code as documentation.
suppressions.md rows use the verbatim justification convention
(verify-suppressions.py PASS, 0 warnings).
Signed-off-by: Nate Chadwick <natechadwick@users.noreply.github.com>
@natechadwick
natechadwick merged commit 9df83f1 into main Aug 13, 2026
2 checks passed
@natechadwick
natechadwick deleted the codeql/xxe-deserialization branch August 13, 2026 23:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants