FasterXML / FasterXML/jackson-databind

`@JsonFilter` with `serializeAllExcept()` does not filter `@JsonAnyGetter` entries

Open
#6,136 0 comments 0 reactions 0 assignees View on GitHub
3.3
Dominant language
Java
Stars
3.7k
Forks
1.5k
Avg merge
3d 6h
Merged PRs (30d)
28

Description

**Describe the bug**

When a POJO has both `@JsonFilter` and a `@JsonAnyGetter`, exclude-style filters (`SimpleBeanPropertyFilter.serializeAllExcept()`) are not applied to the entries the any-getter produces: every entry is written out, including ones whose key the filter explicitly excludes. Since exclude filters are typically used to suppress sensitive properties, entries slip out that the filter was configured to hide.

The cause is that `SimpleBeanPropertyFilter.serializeAsProperty()` calls `include(writer)` on the `AnyGetterWriter` itself, so the name being checked is the any-getter accessor's implied name, not the names of the entries it emits. That name is not in the exclude set, so the writer goes straight to `getAndSerialize()`, which writes all entries unfiltered. Only include-style filters (`filterOutAllExcept()`) ever reach the per-entry `getAndFilter()` path, since that call sits in the `else` branch behind `canOmitProperties()`.

There is a second variant: a `JsonNode`/`ObjectNode`-valued any-getter (supported since [databind#3604]) leaks under **both** filter styles, because `AnyGetterWriter.getAndFilter()` short-circuits `JsonNode` values to plain unfiltered entry serialization, so no filter is consulted at all.

2.18 and earlier are not affected: there the any-getter writer was kept out of the property array and `BeanSerializerBase.serializeFieldsFiltered()` called `getAndFilter()` unconditionally. Folding the any-getter into the property array as a `BeanPropertyWriter` put it behind the writer-level `include()` check.

**Version Information**

Reproduced on 3.3.0-SNAPSHOT (`3.x` head); same code is on 3.1/3.2. 2.18 is not affected.

**Reproduction**

```java
@JsonFilter("anyFilter")
static class AnyBeanWithSecret {
public String name = "bob";

private Map properties = new LinkedHashMap<>();
{
properties.put("a", "1");
properties.put("secret", "s3cr3t");
}

@JsonAnyGetter
public Map anyProperties() {
return properties;
}
}

FilterProvider prov = new SimpleFilterProvider().addFilter("anyFilter",
SimpleBeanPropertyFilter.serializeAllExcept("secret"));
String json = MAPPER.writer(prov).writeValueAsString(new AnyBeanWithSecret());
// expected: {"name":"bob","a":"1"}
// actual: {"name":"bob","a":"1","secret":"s3cr3t"}
```

The `ObjectNode` variant leaks the same way, and also with `filterOutAllExcept("name", "a")`:

```java
@JsonFilter("anyFilter")
static class ObjectNodeAnyBeanWithSecret {
public String name = "bob";

@JsonAnyGetter
public ObjectNode anyProperties() {
return JsonNodeFactory.instance.objectNode()
.put("a", "1")
.put("secret", "s3cr3t");
}
}
```

**Expected behavior**

The filter should decide inclusion per emitted entry name, the way `filterOutAllExcept()` already does for `Map`-valued any-getters, so that `serializeAllExcept("secret")` suppresses the `secret` entry regardless of filter style or any-getter value type.

Contributor guide

No contributing guide indexed for this repository

Research direction

Start at SimpleBeanPropertyFilter.serializeAsProperty(), AnyGetterWriter.getAndSerialize()/getAndFilter(), and BeanSerializerBase.serializeFieldsFiltered(), then trace the Map- and ObjectNode-valued any-getter paths. Add regression coverage for serializeAllExcept("secret") and filterOutAllExcept("name", "a"); done means both filter styles suppress secret entries for both value types.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.