Skip to content

Fix: return proper HTTP 400/404 for invalid id in rules include endpoint#35337

Open
mbiuki wants to merge 8 commits intomainfrom
fix/rules-include-endpoint-error-handling-34888
Open

Fix: return proper HTTP 400/404 for invalid id in rules include endpoint#35337
mbiuki wants to merge 8 commits intomainfrom
fix/rules-include-endpoint-error-handling-34888

Conversation

@mbiuki
Copy link
Copy Markdown
Contributor

@mbiuki mbiuki commented Apr 15, 2026

Summary

Fixes #34888

The /api/portlet/rules/include endpoint was responding with a JasperException error page (HTTP 200 with error HTML body) whenever the id parameter was missing, malformed, or didn't match any contentlet.

  • include.jsp: validates the id parameter before touching the API:
    • Missing or empty id → throws WebApplicationException(400) with a clear message
    • findContentletByIdentifierAnyLanguage throws (e.g. invalid UUID format) → 400
    • Contentlet not found (null / empty identifier) → 404
    • Also encodes id and hideRulePushOptions with Xss.encodeForJavaScript() before embedding in the script block (XSS fix)
  • BaseRestPortlet.getJspResponse(): re-throws WebApplicationException before the generic catch(Exception) handler, so the correct HTTP status propagates to the JAX-RS layer instead of being swallowed as error HTML.

Test plan

  • GET /api/portlet/rules/include (no id param) → 400 Bad Request
  • GET /api/portlet/rules/include?id= (empty) → 400 Bad Request
  • GET /api/portlet/rules/include?id=not-a-valid-uuid400 Bad Request
  • GET /api/portlet/rules/include?id=00000000-0000-0000-0000-000000000000 (valid format, no match) → 404 Not Found
  • GET /api/portlet/rules/include?id=<valid-contentlet-id>200 OK with the rules iframe page

🤖 Generated with Claude Code

mbiuki and others added 5 commits April 14, 2026 16:12
…ool (fixes #24120)

Integrates the OWASP Java Encoder (1.3.1) into dotCMS core as the
standard context-aware output encoding library for XSS prevention.

Changes:
- bom/application/pom.xml, dotCMS/pom.xml: add org.owasp.encoder:encoder:1.3.1
- Xss.java: replace StringEscapeUtils.escapeHtml() with Encode.forHtml();
  replace UtilMethods.encodeURL() with Encode.forUriComponent(); add new
  context-specific helpers: encodeForHTML, encodeForHTMLAttribute,
  encodeForJavaScript, encodeForCSS
- VelocityRequestWrapper.java: replace htmlifyString() with Xss.encodeForHTML()
  in getParameter() for standards-compliant output encoding
- XssWebAPI.java: expose all OWASP encoder contexts to Velocity templates via
  $xsstool — encodeForHTML, encodeForHTMLAttribute, encodeForJavaScript,
  encodeForURL, encodeForCSS; legacy strip/escape methods kept and deprecated

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…4120)

Covers all 5 encoding contexts (HTML, HTML attribute, JavaScript, URL, CSS),
null-safety, legacy methods, and XSS detection helpers. 22 tests, all passing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add $encode Velocity viewtool (OwaspEncoderTool) exposing full OWASP
  Java Encoder API: forHtml, forHtmlContent, forHtmlAttribute,
  forHtmlUnquotedAttribute, forCssString, forCssUrl, forUriComponent,
  forJavaScript, forJavaScriptAttribute, forJavaScriptBlock,
  forJavaScriptSource, forXml*, forCDATA, plus URL safety helpers
  (validateUrl, urlHasXSS, cleanUrl). Registered as $encode in toolbox.xml.
- Wrap VelocityRequestWrapper XSS encoding in
  USE_OWASP_ENCODING_FOR_XSS_PARAMS config flag (default true) so it
  can be reverted to legacy htmlifyString if needed.

Closes #24120

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Covers every encoding context exposed by the viewtool:
forHtml, forHtmlContent, forHtmlAttribute, forHtmlUnquotedAttribute,
forCssString, forCssUrl, forUriComponent, forJavaScript and its
block/attribute/source variants, forXml family, forCDATA, forJava,
plus validateUrl / urlHasXSS / cleanUrl URL-safety helpers.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fixes #34888

Previously /api/portlet/rules/include responded with a JasperException
(HTTP 200 with an error page body) when the id parameter was missing,
invalid, or did not match an existing contentlet.

Changes:
- include.jsp: validate id before calling the API; throw
  WebApplicationException(400) for missing/empty or format-invalid id,
  and WebApplicationException(404) when no contentlet is found.
- BaseRestPortlet.getJspResponse(): re-throw WebApplicationException
  instead of swallowing it in the generic catch block, so the correct
  HTTP status propagates back to the caller.
- include.jsp: encode id and hideRulePushOptions with
  Xss.encodeForJavaScript() before embedding them in the script block.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
mbiuki and others added 3 commits April 16, 2026 04:14
…agation

4 tests verifying:
- WebApplicationException(400) from a JSP dispatch propagates out of
  getJspResponse() with its HTTP status intact.
- WebApplicationException(404) same.
- Ordinary IOException is caught and converted to error-HTML (existing
  behaviour preserved).
- Ordinary RuntimeException same.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…-handling-34888' into fix/rules-include-endpoint-error-handling-34888
@mbiuki
Copy link
Copy Markdown
Contributor Author

mbiuki commented Apr 15, 2026

Test Results

./mvnw test -pl :dotcms-core -Dtest=BaseRestPortletTest

Running com.dotcms.rest.BaseRestPortletTest
Tests run: 4, Failures: 0, Errors: 0, Skipped: 0
BUILD SUCCESS

Tests added — BaseRestPortletTest (4 tests)

Test Verifies
getJspResponse_propagates400WhenJspThrowsWebApplicationException WebApplicationException(400) from a JSP dispatch propagates out of getJspResponse() with HTTP status intact
getJspResponse_propagates404WhenJspThrowsWebApplicationException Same for WebApplicationException(404)
getJspResponse_returnsErrorHtmlForGenericException Ordinary IOException is still caught and converted to error-HTML (existing behaviour preserved)
getJspResponse_returnsErrorHtmlForRuntimeException Ordinary RuntimeException same

Note: the JSP validation logic (include.jsp) requires a running servlet container and is covered by the manual test plan in the PR description.

@semgrep-code-dotcms-test
Copy link
Copy Markdown

Semgrep found 1 ssc-1289c362-ab31-4c96-bd5e-5e444f4fb067 finding:

Risk: Affected versions of vite are vulnerable to Exposure of Sensitive Information to an Unauthorized Actor / Missing Authentication for Critical Function. This occurs because the Vite Dev Server WebSocket improperly exposes the fetchModule method, allowing unauthenticated remote attackers to bypass filesystem restrictions and read arbitrary files from the host machine

Manual Review Advice: A vulnerability from this advisory is reachable if you enable vite dev server using --host flag and websocket is not disabled

Fix: Upgrade this library to at least version 7.3.2 at core/core-web/yarn.lock:22638.

Reference(s): GHSA-p9ff-h696-f583, CVE-2026-39363

If this is a critical or high severity finding, please also link this issue in the #security channel in Slack.

Semgrep found 1 ssc-81d0f8fa-e5f9-414f-a539-fa38f9590a35 finding:

Risk: Affected versions of vite are vulnerable to Improper Access Control / Incorrect Behavior Order. Vite's dev server can bypass server.fs.deny protections: if the server is exposed to the network and a denied file is within an allowed directory, an attacker can retrieve sensitive files such as .env or certificate files by requesting them with query parameters like ?raw, ?import&raw, or ?import&url&inline.

Manual Review Advice: A vulnerability from this advisory is reachable if you enable vite dev server using --host flag and have sensitive data in deny list

Fix: Upgrade this library to at least version 7.3.2 at core/core-web/yarn.lock:22638.

Reference(s): GHSA-v2wj-q39q-566r, CVE-2026-39364

If this is a critical or high severity finding, please also link this issue in the #security channel in Slack.

Semgrep found 2 ssc-4759c514-b537-20ef-d52f-ebb0a5c388fa findings:

Risk: Affected versions of axios are vulnerable to Improper Neutralization of CRLF Sequences in HTTP Headers ('HTTP Request/Response Splitting') / Inconsistent Interpretation of HTTP Requests ('HTTP Request/Response Smuggling') / Server-Side Request Forgery (SSRF). Axios can be used as a gadget for header injection: if another dependency enables prototype pollution, polluted properties can be merged into Axios request headers and written without CRLF sanitization, allowing request smuggling/SSRF that can reach internal services such as AWS IMDSv2 and potentially lead to credential theft or broader compromise.

Fix: Upgrade this library to at least version 1.15.0 at core/core-web/yarn.lock:10238.

Reference(s): GHSA-fvcv-3m26-pcqx, CVE-2026-40175

If this is a critical or high severity finding, please also link this issue in the #security channel in Slack.

Semgrep found 2 ssc-5ea2c631-7cef-a4e0-e641-d179af079827 findings:

Risk: Affected versions of axios are vulnerable to Server-Side Request Forgery (SSRF) / Unintended Proxy or Intermediary ('Confused Deputy'). Axios does not normalize hostnames before applying NO_PROXY, so requests to loopback or internal hosts such as localhost. or [::1] can be sent through a configured proxy instead of bypassing it. If an attacker can influence request URLs, they may force local/internal Axios traffic through an attacker-controlled proxy, undermining SSRF protections and exposing sensitive responses.

Manual Review Advice: A vulnerability from this advisory is reachable if you have NO_PROXY configured in your environment

Fix: Upgrade this library to at least version 1.15.0 at core/core-web/yarn.lock:10238.

Reference(s): GHSA-3p68-rc4w-qgx5, CVE-2025-62718

If this is a critical or high severity finding, please also link this issue in the #security channel in Slack.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area : Backend PR changes Java/Maven backend code

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

Rules include endpoint improve Error Message : return proper HTTP error (400/404) for invalid id instead of server error

1 participant