Error Bodies That Repeat Your Input Back
API error messages that echo requester input are a cheap reconnaissance channel. The fix: specific code, static detail, regression tests.
TL;DR
KotaPortal's admin API was reflecting user input back in error messages across five spots in two services, confirming injection viability per OWASP guidance. The fix keeps specific error codes but makes human-readable details fully static, never echoing request data. Each endpoint gets a regression test that sends a random probe and fails if the probe appears in the response.
During a routine security review of the KotaPortal admin API, a write request falling outside the authorized access scope was rejected with a standard `FORBIDDEN` status. However, the response body carried the exact `bidang` value the requester had typed. An automated probe script later confirmed this behavior, receiving its own randomized probe value quoted verbatim within the error detail.
What the Investigation Found
The investigation identified five distinct spots across two services where request data was reflected. Three separate `mapError` chains were interpolating user input directly into validation messages, such as `invalid bidang:
The Fix Pattern and the Boundary
The resolution requires keeping the machine-readable error code specific while making the human-readable detail entirely static. Messages must read `invalid bidang` without appending the value, or `this data belongs to another bidang`. Standard codes like `FORBIDDEN`, `INVALID_INPUT`, and `CONFLICT` remain intact. Client-side field validation can still inform users that their input is incorrect before submission. The API must never repeat the input back, primarily because the API serves diverse clients that may not be the benign, controlled form in the official frontend.
Regression Tests as the Proof
To guarantee the fix holds, each corrected endpoint receives a dedicated regression test. The checkable artifact is straightforward: send a unique, randomized probe payload, expect the standard error code, and grep the response body for the probe string. The test passes only on zero hits. Enforcing a code-level convention where error details must be static strings or table-driven lookups, never format strings constructed over request data, is significantly cheaper than manually reviewing every error message before each release. The OWASP warning exists precisely to justify this strict convention.
Sources