[DEFECT] Users API v1 — Missing validation and leaked internals in error responses
@hassandotcms is already working on this.
Since Feb 9, 2026.
- 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
NullPointerExceptionstack 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/currentwithoutcurrentPasswordreturns HTTP 400 with a validation message (not 500 NPE) -
PUT /api/v1/users/currentwithoutcurrentPassworddoes not leak Java internals (NPE) in the response -
POST /api/v1/userswith 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
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.