GROOVY-12277: Encode source-derived text emitted into generated HTML - #2814
Open
paulk-asert wants to merge 1 commit into
Open
GROOVY-12277: Encode source-derived text emitted into generated HTML#2814paulk-asert wants to merge 1 commit into
paulk-asert wants to merge 1 commit into
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #2814 +/- ##
==================================================
- Coverage 70.1794% 70.1763% -0.0031%
- Complexity 35853 35886 +33
==================================================
Files 1563 1564 +1
Lines 132546 132606 +60
Branches 24385 24399 +14
==================================================
+ Hits 93020 93058 +38
- Misses 31113 31137 +24
+ Partials 8413 8411 -2
🚀 New features to boost your workflow:
|
This comment has been minimized.
This comment has been minimized.
Contributor
There was a problem hiding this comment.
Pull request overview
This PR hardens GroovyDoc HTML generation by encoding source-derived/doc-comment-derived strings before inserting them into HTML attributes or element text, preventing markup/attribute injection in generated documentation.
Changes:
- Encode
{@link}-derived URL/label when GroovyDoc constructs anchors (attribute vs. text contexts). - Encode annotation name/description when rendering declaration headings in the class template.
- Add regression tests covering the above injection vectors.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/GroovyDocToolTest.java | Adds regression tests for encoding of link and annotation text in generated HTML. |
| subprojects/groovy-groovydoc/src/main/resources/org/codehaus/groovy/tools/groovydoc/gstringTemplates/classLevel/classDocName.html | Encodes annotation name/description when emitting declaration text. |
| subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/tools/groovydoc/SimpleGroovyClassDoc.java | Encodes link targets/labels for href, title, and anchor text when constructing HTML. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Two places where groovydoc builds HTML around text taken from the source it
is documenting, without encoding it for the context it lands in.
A {@link} or @see reference is split into a target and a label, both of
which are then concatenated into an anchor the tool constructs: the target
into href, the label into the element text, and for a resolved class the
short name into title as well. None was encoded, so a reference could close
the attribute and open a tag of its own. Encode each for its context, the
attributes through encodeAttribute and the text through encodeAngleBrackets.
An annotation's name and description are emitted into the class declaration
and every member heading. description() carries the annotation's arguments
as they were written, so an annotation holding a string literal put that
literal into the page verbatim. Encode both, leaving the linkable() call
alone since that one does produce markup.
This is groovydoc's own construction rather than the raw HTML a doc comment
body may contain by javadoc parity, so the passthrough that covers a comment
body does not extend to it. For the annotation case the text is not from a
comment at all: it is source code, and reaches the page without any doc
comment being written.
Not changed: the @default tag GroovydocJavaVisitor appends for an annotation
member's default value. It is added to the raw comment text and no template
renders it as a declaration, and constantValueExpression() is only tested
for nullity, so that value does not reach a declaration block.
paulk-asert
force-pushed
the
groovy12277
branch
from
August 19, 2026 10:04
295d92a to
0686a9f
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two places where groovydoc builds HTML around text taken from the source it is documenting, without encoding it for the context it lands in.
A {@link} or @see reference is split into a target and a label, both of which are then concatenated into an anchor the tool constructs: the target into href, the label into the element text, and for a resolved class the short name into title as well. None was encoded, so a reference could close the attribute and open a tag of its own. Encode each for its context, the attributes through encodeAttribute and the text through encodeAngleBrackets.
An annotation's name and description are emitted into the class declaration and every member heading. description() carries the annotation's arguments as they were written, so an annotation holding a string literal put that literal into the page verbatim. Encode both, leaving the linkable() call alone since that one does produce markup.
This is groovydoc's own construction rather than the raw HTML a doc comment body may contain by javadoc parity, so the passthrough that covers a comment body does not extend to it. For the annotation case the text is not from a comment at all: it is source code, and reaches the page without any doc comment being written.
Not changed: the @default tag GroovydocJavaVisitor appends for an annotation member's default value. It is added to the raw comment text and no template renders it as a declaration, and constantValueExpression() is only tested for nullity, so that value does not reach a declaration block.