Unwrap AOP proxies in configprops endpoint serialization#50273
Open
zxuhan wants to merge 2 commits intospring-projects:mainfrom
Open
Unwrap AOP proxies in configprops endpoint serialization#50273zxuhan wants to merge 2 commits intospring-projects:mainfrom
zxuhan wants to merge 2 commits intospring-projects:mainfrom
Conversation
The configprops endpoint serialized AOP proxies directly, leaking the Advised interface getters (targetSource, exposeProxy, preFiltered) into the response. With BufferingApplicationStartup configured, the targetSource walk reached the entire startup-event buffer. Unwrap to the proxy's target before handing it to the serializer so only the user-defined configuration properties are exposed. See spring-projectsgh-50231 Signed-off-by: zxuhan7 <zxuhan7@gmail.com>
wilkinsona
requested changes
May 1, 2026
Member
wilkinsona
left a comment
There was a problem hiding this comment.
Thanks for the PR, @zxuhan. I've left a few comments for your consideration.
| } | ||
|
|
||
| private @Nullable Object unwrapAopProxy(@Nullable Object bean) { | ||
| if (bean instanceof Advised advised) { |
Member
There was a problem hiding this comment.
A bean could have been proxied multiple times so a while loop would be better here.
| } | ||
| } | ||
| catch (Exception ex) { | ||
| // Fall through and serialize the proxy |
Member
There was a problem hiding this comment.
I think we should exclude the bean from the result rather than serializing the proxy.
| private Map<String, @Nullable Object> safeSerialize(@Nullable Object bean, String prefix) { | ||
| try { | ||
| return new HashMap<>(this.serializer.serialize(bean)); | ||
| return new HashMap<>(this.serializer.serialize(unwrapAopProxy(bean))); |
Member
There was a problem hiding this comment.
I think the unwrapping call would be better done earlier. If it returns null (no target, getting the target fails, etc), we should skip the bean entirely.
- Move proxy unwrap out of safeSerialize and into describeBean - Loop on Advised so chains of proxies are unwrapped - Skip the bean when the target cannot be obtained instead of serializing the proxy See spring-projectsgh-50231 Signed-off-by: zxuhan7 <zxuhan7@gmail.com>
Contributor
Author
|
Thanks for the review, @wilkinsona. Pushed 41a538f:
Added two tests covering nested proxies and an unresolvable |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The
configpropsactuator endpoint serializes each@ConfigurationPropertiesbean using its bean-factory instance. When that instance is an AOP proxy
(commonly a CGLIB scoped proxy created by
@RefreshScope, but the sameapplies to any AOP proxy), the serializer also picks up the
Advisedinterface getters that the proxy exposes (
targetSource,exposeProxy,preFiltered).With
BufferingApplicationStartupconfigured, thetargetSourcewalk reachesbeanFactory.applicationStartup.bufferedTimeline.events[…], inflating theresponse by ~200 KB per refresh-scoped bean.
This change unwraps AOP proxies via
Advised.getTargetSource().getTarget()in
safeSerializebefore delegating to the serializer, so only the user-definedconfiguration properties are exposed. The unwrap is wrapped in a try/catch so
that any failure to obtain the target falls back to the existing behaviour.
A test has been added that creates a
ProxyFactory-based CGLIB proxy around a@ConfigurationPropertiesbean and verifies that the resulting descriptorcontains only the user properties, not
targetSource/exposeProxy/preFiltered.See gh-50231