Skip to content

[12.x] Add option to hide detailed validation errors in JSON responses#59125

Draft
MElkmeshi wants to merge 1 commit intolaravel:12.xfrom
MElkmeshi:hide-validation-errors-opt-in
Draft

[12.x] Add option to hide detailed validation errors in JSON responses#59125
MElkmeshi wants to merge 1 commit intolaravel:12.xfrom
MElkmeshi:hide-validation-errors-opt-in

Conversation

@MElkmeshi
Copy link
Contributor

Summary

This is more of a discussion than a ready-to-merge PR. I'd love to hear maintainers' thoughts on this.

The Problem

Laravel's default JSON validation error response exposes exact field names and validation rules. This makes API enumeration trivial for attackers — just send an empty {} body to any endpoint:

curl -X POST https://example.com/api/v1/register \
  -H 'Content-Type: application/json' \
  -d '{}'

Response:

{
    "message": "The customer id field is required.",
    "errors": {
        "customer_id": ["The customer id field is required."],
        "device_id": ["The device id field is required."],
        "password": ["The password field is required."]
    }
}

Without any authentication or prior knowledge, an attacker now knows the exact schema. I've seen this on production banking APIs.

The Proposal

Add a HIDE_VALIDATION_ERRORS env variable (opt-in, defaults to false). When enabled, JSON validation responses become:

{
    "message": "The given data was invalid."
}

No field names, no per-field errors, no enumeration.

Usage

HIDE_VALIDATION_ERRORS=true

What Changed

  • config/app.php — new hide_validation_errors config key reading from env
  • Handler::invalidJson() — respects the config to omit detailed errors
  • Added test covering both behaviors

Discussion Points

  • Is this the right approach, or should this be a method on the exception handler instead?
  • Should it be tied to APP_DEBUG (hide errors when debug is false)?
  • Is this something the framework should handle, or is it better left to individual apps?
  • Would a different config key name be preferred?

I understand this is opinionated — just wanted to start the conversation around making this easier out of the box.

Test Plan

  • Existing tests pass
  • New test covers both default (errors shown) and opt-in (errors hidden) behavior

Adds a HIDE_VALIDATION_ERRORS env option that, when enabled, omits
field names and per-field error messages from JSON validation responses.
This prevents API field enumeration via empty request bodies.
@github-actions
Copy link

github-actions bot commented Mar 7, 2026

Thanks for submitting a PR!

Note that draft PRs are not reviewed. If you would like a review, please mark your pull request as ready for review in the GitHub user interface.

Pull requests that are abandoned in draft may be closed due to inactivity.

@MElkmeshi MElkmeshi marked this pull request as ready for review March 7, 2026 16:25
@shaedrich
Copy link
Contributor

shaedrich commented Mar 7, 2026

The Proposal

Add a HIDE_VALIDATION_ERRORS env variable (opt-in, defaults to false). When enabled, JSON validation responses become:

{
    "message": "The given data was invalid."
}

Why then a message at all and not simply 422, 400, or even 500 as some already do for their production systems?

Usage

HIDE_VALIDATION_ERRORS=true

On the other hand, this could be a gradual setting:

  • Level 1: Show everything
  • Level 2: Hide the keys and only show the messages (messages should contain a human-readable field name, not its actual identifier)
  • Level 3: Contain an abbreviated list of errors (maybe, they can be somehow grouped (like in a wizard, e.g. "please complete your address data" or "your payment data is incomplete"))
  • Level 4: 422 + generic validation error message
  • Level 5: Only 500 with no (particular) body (equivalent to APP_DEBUG=false)

The Problem

Laravel's default JSON validation error response exposes exact field names and validation rules. This makes API enumeration trivial for attackers — just send an empty {} body to any endpoint:

You would usually have an API key or a CSRF token or the like, so simply sending {} would not expose the validation keys, because 422 isn't the error, that would be triggered. If there are indeed unauthenticated endpoints, maybe, they should be targeted specifically.

@MElkmeshi MElkmeshi marked this pull request as draft March 8, 2026 18: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.

2 participants