dotCMS / dotCMS/core

[DEFECT] Users API v1 — Missing validation and leaked internals in error responses

Open
#34,549 0 comments 0 reactions 1 assignee View on GitHub

@hassandotcms is already working on this.

Since Feb 9, 2026.

OKR : Customer Support Team : Modernization
Dominant language
Java
Stars
970
Forks
486
Avg merge
3d 33m
Merged PRs (30d)
170

Description

Problem Statement

The /api/v1/users REST API has 3 validation/error-handling defects found during systematic endpoint testing. These affect API consumers (frontend, integrations) who receive unhelpful or leaked internal error messages instead of proper validation responses.

Impact:

  • Security concern: A NullPointerException stack trace is leaked to API clients, exposing internal implementation details.
  • Developer experience: Two endpoints return raw userId strings as error messages instead of descriptive explanations, making it difficult for API consumers to understand what went wrong.
Defect 1 (High) — PUT /api/v1/users/current returns 500 NPE when currentPassword is missing

When calling PUT /api/v1/users/current without the currentPassword field, the server returns HTTP 500 with:

{"message":"Cannot invoke \"String.toCharArray()\" because \"passwordFromUser\" is null"}

Expected: HTTP 400 with a message like "currentPassword is required" or a validation error referencing the currentPassword field.

Defect 2 (Medium) — POST /api/v1/users leaks Jackson internals on malformed JSON

When sending invalid JSON (e.g. not-json) to POST /api/v1/users, the response exposes Jackson deserialization internals:

{"message":"Unrecognized token 'not'... at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 5]"}

Expected: HTTP 400 with a user-friendly message like "Invalid JSON in request body".

Defect 3 (Low) — PATCH /api/v1/users/activate|deactivate/{userId} returns raw userId as error message

When calling activate or deactivate with a non-existent userId, the error response message is just the raw userId string:

{"message":"nonexistent-user-12345"}

Expected: A descriptive message like "User nonexistent-user-12345 does not exist" (consistent with GET /api/v1/users/{userId} and DELETE /api/v1/users/{userId} which already return "User X does not exist").

Steps to Reproduce

Defect 1 — NPE on missing currentPassword:

curl -s -w '\n%{http_code}' http://localhost:8080/api/v1/users/current   -X PUT -H "Authorization: Basic $(echo -n 'admin@dotcms.com:admin' | base64)"   -H "Content-Type: application/json"   -d '{"userId":"dotcms.org.1","givenName":"Test","surname":"Test"}'
# Returns: HTTP 500 with NPE message

Defect 2 — Jackson internals leaked on malformed JSON:

curl -s -w '\n%{http_code}' http://localhost:8080/api/v1/users   -X POST -H "Authorization: Basic $(echo -n 'admin@dotcms.com:admin' | base64)"   -H "Content-Type: application/json"   -d 'not-json'
# Returns: HTTP 400 with Jackson internal error

Defect 3 — Raw userId as error message:

curl -s -w '\n%{http_code}' http://localhost:8080/api/v1/users/deactivate/nonexistent-id   -X PATCH -H "Authorization: Basic $(echo -n 'admin@dotcms.com:admin' | base64)"
# Returns: HTTP 400 with message "nonexistent-id"

Acceptance Criteria

  • PUT /api/v1/users/current without currentPassword returns HTTP 400 with a validation message (not 500 NPE)
  • PUT /api/v1/users/current without currentPassword does not leak Java internals (NPE) in the response
  • POST /api/v1/users with malformed JSON returns a user-friendly error message without Jackson internal references (StreamReadFeature, INCLUDE_SOURCE_IN_LOCATION)
  • PATCH /api/v1/users/activate/{userId} with non-existent user returns a descriptive message (e.g. "User X does not exist"), not just the raw userId
  • PATCH /api/v1/users/deactivate/{userId} with non-existent user returns a descriptive message, not just the raw userId

dotCMS Version

Latest from main branch (trunk Docker image)

Severity

Medium - Some functionality impacted

Links

  • NA

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.