Jackson Deserialization Validation

SkillDev tools

Securing Jackson JSON deserialization by validating input before processing and preventing unknown properties.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Jackson Deserialization Validation skill

What this skill tells your AI

The instructions your AI receives, as published by cxcscmu/skilllearnbench in skills/b1-one-shot-claude-haiku-4-5/fix-security-bug/jackson-deserialization-validation/SKILL.md and read by ahel’s review.

Vulnerability Pattern

When Jackson deserializes JSON with unknown properties, if not handled properly, malicious extra properties can bypass validation logic:

{
  "validProperty": "legitimate value",
  "": {
    "enabled": true,
    "other": "malicious"
  }
}

The empty key "" can be overlooked by simple property checks.

Jackson Configuration

1. Fail on Unknown Properties

@JsonIgnoreProperties(ignoreUnknown = false)
public class MyFilter {
    @JsonProperty
    private String function;

    // This will throw exception on unknown properties
}

2. Custom Deserialization

@JsonDeserialize(using = CustomDeserializer.class)
public class MyFilter {
    // Custom logic during deserialization
}

3. @JsonAnySetter for Validation

public class MyFilter {
    @JsonProperty
    private String function;

    @JsonAnySetter
    public void handleUnknown(String key, Object value) {
        if (key == null || key.isEmpty()) {
            throw new IllegalArgumentException("Empty property keys not allowed");
        }
        // Validate other unknown properties
    }
}

Validation Strategies

Strategy 1: Whitelist Allowed Keys

private static final Set<String> ALLOWED_KEYS =
    Set.of("function", "type", "name");

@JsonAnySetter
public void handleProperty(String key, Object value) {
    if (!ALLOWED_KEYS.contains(key)) {
        throw new IllegalArgumentException(
            "Unknown property: " + key);
    }
}

Strategy 2: Reject Empty/Null Keys

@JsonAnySetter
public void validateKey(String key, Object value) {
    if (key == null || key.trim().isEmpty()) {
        throw new IllegalArgumentException(
            "Property keys cannot be empty or null");
    }
}

Strategy 3: Post-Deserialization Validation

@JsonProperty
private Map<String, Object> properties;

@PostConstruct
public void validate() {
    for (String key : properties.keySet()) {
        if (key == null || key.isEmpty()) {
            throw new IllegalArgumentException(
                "Empty keys not allowed");
        }
    }
}

Implementation in Druid

Finding Vulnerable Classes

  1. Search for @JsonTypeName("javascript")
  2. Look for JavaScript filter/transform specs
  3. Check deserialization of filter objects

Key Locations

  • JavaScriptFilter.java - Main JavaScript filter class
  • Filter spec handlers in indexing-service
  • Transform spec deserialization

Fix Pattern

@JsonIgnoreProperties(ignoreUnknown = false)
public class JavaScriptFilter {
    @JsonProperty
    private String function;

    @JsonAnySetter
    public void handleUnknown(String key, Object value) {
        throw new IllegalArgumentException(
            "Unknown property '" + key +
            "' in JavaScript filter specification");
    }
}

Testing the Fix

Test Case 1: Valid Request

String json = "{\"type\":\"javascript\",\"function\":\"function(){return true;}\"}";
JavaScriptFilter filter = mapper.readValue(json, JavaScriptFilter.class);
// Should succeed

Test Case 2: Empty Key (Should Fail)

String json = "{\"type\":\"javascript\",\"function\":\"...\",\"\":{\"enabled\":true}}";
assertThrows(JsonMappingException.class, () ->
    mapper.readValue(json, JavaScriptFilter.class));
// Should throw exception

Test Case 3: Null Key (Should Fail)

String json = "{\"type\":\"javascript\",null:{\"value\":\"bad\"}}";
assertThrows(JsonMappingException.class, () ->
    mapper.readValue(json, JavaScriptFilter.class));

Druid-Specific Considerations

  1. Custom ObjectMapper: Druid may use custom ObjectMapper configuration
  2. Multiple Filter Types: Fix may need to apply to multiple filter classes
  3. Backward Compatibility: Ensure legitimate requests still work
  4. Nested Specs: Check if transformSpec or other nested objects also need fixes

Recommended Approach

  1. Use @JsonIgnoreProperties(ignoreUnknown = false) to detect unknown properties
  2. Add @JsonAnySetter to validate property names
  3. Reject any empty string keys explicitly
  4. Test both via HTTP API and direct deserialization

Signals

GitHub stars
83
Forks
5
Last commit
Jul 2026
Advanced
Catalog kind
skill
Gateway key
jackson-deserialization-validation
Source
github.com/cxcscmu/skilllearnbench