When sending a PATCH request with an attribute value of the wrong type, scimitar accepts it silently and returns 200 OK. The same invalid payload sent via POST or PUT is correctly rejected with 400 InvalidValue.
Example: the active field is declared as type: boolean in the SCIM User schema. Sending "active": "yes" (a string) behaves inconsistently across methods:
| Method |
Payload |
Response |
POST /Users |
"active": "yes" |
400 — Active has the wrong type. It has to be a(n) boolean. |
PUT /Users/:id |
"active": "yes" |
400 — Active has the wrong type. It has to be a(n) boolean. |
PATCH /Users/:id |
"active": "yes" |
200 OK ← bug |
Root cause
POST and PUT both go through the private with_scim_resource helper, which constructs a Scimitar::Resources::User from the request body and calls .valid? on it before yielding to the controller block. Type errors are caught there.
PATCH (in ResourcesController#update) only calls validate_request() — which checks that the body is non-empty — and then yields the raw params hash directly:
def update(&block)
validate_request()
render(json: yield(safe_params[:id], safe_params.to_hash()))
end
No Resources::User object is ever constructed for PATCH, so .valid? is never called and schema type validation is skipped entirely. This means any attribute in a PATCH body can be set to a value of the wrong type without error.
Expected behaviour: PATCH should validate attribute types (and other schema constraints) in the same way POST and PUT do, returning 400 invalidValue when a value does not match the declared type.
I wanted to confirm this wasn't caused by any of my project's overrides so I had Claude cook up a minimal repro
When sending a
PATCHrequest with an attribute value of the wrong type, scimitar accepts it silently and returns200 OK. The same invalid payload sent viaPOSTorPUTis correctly rejected with400 InvalidValue.Example: the
activefield is declared astype: booleanin the SCIM User schema. Sending"active": "yes"(a string) behaves inconsistently across methods:POST /Users"active": "yes"400— Active has the wrong type. It has to be a(n) boolean.PUT /Users/:id"active": "yes"400— Active has the wrong type. It has to be a(n) boolean.PATCH /Users/:id"active": "yes"200 OK← bugRoot cause
POSTandPUTboth go through the privatewith_scim_resourcehelper, which constructs aScimitar::Resources::Userfrom the request body and calls.valid?on it before yielding to the controller block. Type errors are caught there.PATCH(inResourcesController#update) only callsvalidate_request()— which checks that the body is non-empty — and then yields the raw params hash directly:No
Resources::Userobject is ever constructed forPATCH, so.valid?is never called and schema type validation is skipped entirely. This means any attribute in aPATCHbody can be set to a value of the wrong type without error.Expected behaviour:
PATCHshould validate attribute types (and other schema constraints) in the same wayPOSTandPUTdo, returning400 invalidValuewhen a value does not match the declared type.I wanted to confirm this wasn't caused by any of my project's overrides so I had Claude cook up a minimal repro