Add server.request.body.files_content AppSec address for Tomcat and Netty multipart#11198
Add server.request.body.files_content AppSec address for Tomcat and Netty multipart#11198
Conversation
BenchmarksStartupParameters
See matching parameters
SummaryFound 0 performance improvements and 0 performance regressions! Performance is the same for 62 metrics, 9 unstable metrics. Startup time reports for insecure-bankgantt
title insecure-bank - global startup overhead: candidate=1.62.0-SNAPSHOT~64dd1f56af, baseline=1.62.0-SNAPSHOT~9d737609c4
dateFormat X
axisFormat %s
section tracing
Agent [baseline] (1.066 s) : 0, 1066377
Total [baseline] (8.865 s) : 0, 8865071
Agent [candidate] (1.072 s) : 0, 1072403
Total [candidate] (8.86 s) : 0, 8860190
section iast
Agent [baseline] (1.256 s) : 0, 1255782
Total [baseline] (9.572 s) : 0, 9571539
Agent [candidate] (1.246 s) : 0, 1245634
Total [candidate] (9.568 s) : 0, 9568212
gantt
title insecure-bank - break down per module: candidate=1.62.0-SNAPSHOT~64dd1f56af, baseline=1.62.0-SNAPSHOT~9d737609c4
dateFormat X
axisFormat %s
section tracing
crashtracking [baseline] (1.238 ms) : 0, 1238
crashtracking [candidate] (1.234 ms) : 0, 1234
BytebuddyAgent [baseline] (637.745 ms) : 0, 637745
BytebuddyAgent [candidate] (641.129 ms) : 0, 641129
AgentMeter [baseline] (29.527 ms) : 0, 29527
AgentMeter [candidate] (29.726 ms) : 0, 29726
GlobalTracer [baseline] (249.402 ms) : 0, 249402
GlobalTracer [candidate] (251.13 ms) : 0, 251130
AppSec [baseline] (32.665 ms) : 0, 32665
AppSec [candidate] (33.078 ms) : 0, 33078
Debugger [baseline] (59.972 ms) : 0, 59972
Debugger [candidate] (60.344 ms) : 0, 60344
Remote Config [baseline] (601.885 µs) : 0, 602
Remote Config [candidate] (599.456 µs) : 0, 599
Telemetry [baseline] (9.225 ms) : 0, 9225
Telemetry [candidate] (9.152 ms) : 0, 9152
Flare Poller [baseline] (9.875 ms) : 0, 9875
Flare Poller [candidate] (9.815 ms) : 0, 9815
section iast
crashtracking [baseline] (1.251 ms) : 0, 1251
crashtracking [candidate] (1.246 ms) : 0, 1246
BytebuddyAgent [baseline] (832.646 ms) : 0, 832646
BytebuddyAgent [candidate] (825.082 ms) : 0, 825082
AgentMeter [baseline] (11.446 ms) : 0, 11446
AgentMeter [candidate] (11.288 ms) : 0, 11288
GlobalTracer [baseline] (239.249 ms) : 0, 239249
GlobalTracer [candidate] (237.924 ms) : 0, 237924
IAST [baseline] (28.276 ms) : 0, 28276
IAST [candidate] (28.388 ms) : 0, 28388
AppSec [baseline] (31.6 ms) : 0, 31600
AppSec [candidate] (31.63 ms) : 0, 31630
Debugger [baseline] (62.964 ms) : 0, 62964
Debugger [candidate] (62.221 ms) : 0, 62221
Remote Config [baseline] (545.163 µs) : 0, 545
Remote Config [candidate] (527.136 µs) : 0, 527
Telemetry [baseline] (8.013 ms) : 0, 8013
Telemetry [candidate] (7.875 ms) : 0, 7875
Flare Poller [baseline] (3.381 ms) : 0, 3381
Flare Poller [candidate] (3.321 ms) : 0, 3321
Startup time reports for petclinicgantt
title petclinic - global startup overhead: candidate=1.62.0-SNAPSHOT~64dd1f56af, baseline=1.62.0-SNAPSHOT~9d737609c4
dateFormat X
axisFormat %s
section tracing
Agent [baseline] (1.073 s) : 0, 1073302
Total [baseline] (11.17 s) : 0, 11170264
Agent [candidate] (1.078 s) : 0, 1078444
Total [candidate] (11.161 s) : 0, 11160939
section appsec
Agent [baseline] (1.267 s) : 0, 1267362
Total [baseline] (11.141 s) : 0, 11141474
Agent [candidate] (1.271 s) : 0, 1271402
Total [candidate] (11.085 s) : 0, 11084699
section iast
Agent [baseline] (1.254 s) : 0, 1254379
Total [baseline] (11.41 s) : 0, 11409643
Agent [candidate] (1.254 s) : 0, 1253557
Total [candidate] (11.387 s) : 0, 11387358
section profiling
Agent [baseline] (1.198 s) : 0, 1197747
Total [baseline] (11.002 s) : 0, 11002451
Agent [candidate] (1.189 s) : 0, 1188656
Total [candidate] (11.073 s) : 0, 11072751
gantt
title petclinic - break down per module: candidate=1.62.0-SNAPSHOT~64dd1f56af, baseline=1.62.0-SNAPSHOT~9d737609c4
dateFormat X
axisFormat %s
section tracing
crashtracking [baseline] (1.238 ms) : 0, 1238
crashtracking [candidate] (1.238 ms) : 0, 1238
BytebuddyAgent [baseline] (640.843 ms) : 0, 640843
BytebuddyAgent [candidate] (645.549 ms) : 0, 645549
AgentMeter [baseline] (29.786 ms) : 0, 29786
AgentMeter [candidate] (30.008 ms) : 0, 30008
GlobalTracer [baseline] (251.284 ms) : 0, 251284
GlobalTracer [candidate] (250.903 ms) : 0, 250903
AppSec [baseline] (32.985 ms) : 0, 32985
AppSec [candidate] (33.007 ms) : 0, 33007
Debugger [baseline] (61.312 ms) : 0, 61312
Debugger [candidate] (60.957 ms) : 0, 60957
Remote Config [baseline] (598.517 µs) : 0, 599
Remote Config [candidate] (603.524 µs) : 0, 604
Telemetry [baseline] (8.493 ms) : 0, 8493
Telemetry [candidate] (10.014 ms) : 0, 10014
Flare Poller [baseline] (10.571 ms) : 0, 10571
Flare Poller [candidate] (9.856 ms) : 0, 9856
section appsec
crashtracking [baseline] (1.228 ms) : 0, 1228
crashtracking [candidate] (1.234 ms) : 0, 1234
BytebuddyAgent [baseline] (678.036 ms) : 0, 678036
BytebuddyAgent [candidate] (681.058 ms) : 0, 681058
AgentMeter [baseline] (12.224 ms) : 0, 12224
AgentMeter [candidate] (12.233 ms) : 0, 12233
GlobalTracer [baseline] (249.726 ms) : 0, 249726
GlobalTracer [candidate] (249.971 ms) : 0, 249971
IAST [baseline] (24.615 ms) : 0, 24615
IAST [candidate] (24.817 ms) : 0, 24817
AppSec [baseline] (185.455 ms) : 0, 185455
AppSec [candidate] (185.056 ms) : 0, 185056
Debugger [baseline] (64.782 ms) : 0, 64782
Debugger [candidate] (64.562 ms) : 0, 64562
Remote Config [baseline] (567.984 µs) : 0, 568
Remote Config [candidate] (555.219 µs) : 0, 555
Telemetry [baseline] (7.861 ms) : 0, 7861
Telemetry [candidate] (7.771 ms) : 0, 7771
Flare Poller [baseline] (6.816 ms) : 0, 6816
Flare Poller [candidate] (6.807 ms) : 0, 6807
section iast
crashtracking [baseline] (1.249 ms) : 0, 1249
crashtracking [candidate] (1.242 ms) : 0, 1242
BytebuddyAgent [baseline] (831.824 ms) : 0, 831824
BytebuddyAgent [candidate] (830.865 ms) : 0, 830865
AgentMeter [baseline] (11.352 ms) : 0, 11352
AgentMeter [candidate] (11.385 ms) : 0, 11385
GlobalTracer [baseline] (238.354 ms) : 0, 238354
GlobalTracer [candidate] (239.614 ms) : 0, 239614
IAST [baseline] (26.639 ms) : 0, 26639
IAST [candidate] (27.502 ms) : 0, 27502
AppSec [baseline] (32.425 ms) : 0, 32425
AppSec [candidate] (30.812 ms) : 0, 30812
Debugger [baseline] (64.211 ms) : 0, 64211
Debugger [candidate] (63.162 ms) : 0, 63162
Remote Config [baseline] (522.486 µs) : 0, 522
Remote Config [candidate] (519.322 µs) : 0, 519
Telemetry [baseline] (7.987 ms) : 0, 7987
Telemetry [candidate] (7.934 ms) : 0, 7934
Flare Poller [baseline] (3.479 ms) : 0, 3479
Flare Poller [candidate] (3.416 ms) : 0, 3416
section profiling
crashtracking [baseline] (1.198 ms) : 0, 1198
crashtracking [candidate] (1.182 ms) : 0, 1182
BytebuddyAgent [baseline] (699.062 ms) : 0, 699062
BytebuddyAgent [candidate] (693.647 ms) : 0, 693647
AgentMeter [baseline] (8.979 ms) : 0, 8979
AgentMeter [candidate] (8.94 ms) : 0, 8940
GlobalTracer [baseline] (209.976 ms) : 0, 209976
GlobalTracer [candidate] (208.524 ms) : 0, 208524
AppSec [baseline] (33.116 ms) : 0, 33116
AppSec [candidate] (32.659 ms) : 0, 32659
Debugger [baseline] (66.374 ms) : 0, 66374
Debugger [candidate] (65.92 ms) : 0, 65920
Remote Config [baseline] (580.507 µs) : 0, 581
Remote Config [candidate] (575.61 µs) : 0, 576
Telemetry [baseline] (8.213 ms) : 0, 8213
Telemetry [candidate] (8.113 ms) : 0, 8113
Flare Poller [baseline] (3.627 ms) : 0, 3627
Flare Poller [candidate] (3.544 ms) : 0, 3544
ProfilingAgent [baseline] (94.666 ms) : 0, 94666
ProfilingAgent [candidate] (93.962 ms) : 0, 93962
Profiling [baseline] (95.215 ms) : 0, 95215
Profiling [candidate] (94.51 ms) : 0, 94510
LoadParameters
See matching parameters
SummaryFound 0 performance improvements and 0 performance regressions! Performance is the same for 20 metrics, 16 unstable metrics. Request duration reports for insecure-bankgantt
title insecure-bank - request duration [CI 0.99] : candidate=1.62.0-SNAPSHOT~64dd1f56af, baseline=1.62.0-SNAPSHOT~9d737609c4
dateFormat X
axisFormat %s
section baseline
no_agent (1.245 ms) : 1233, 1256
. : milestone, 1245,
iast (3.414 ms) : 3365, 3462
. : milestone, 3414,
iast_FULL (6.258 ms) : 6191, 6324
. : milestone, 6258,
iast_GLOBAL (3.75 ms) : 3681, 3818
. : milestone, 3750,
profiling (2.321 ms) : 2298, 2344
. : milestone, 2321,
tracing (1.953 ms) : 1934, 1971
. : milestone, 1953,
section candidate
no_agent (1.266 ms) : 1253, 1278
. : milestone, 1266,
iast (3.5 ms) : 3445, 3555
. : milestone, 3500,
iast_FULL (6.409 ms) : 6342, 6476
. : milestone, 6409,
iast_GLOBAL (3.707 ms) : 3646, 3768
. : milestone, 3707,
profiling (2.129 ms) : 2111, 2148
. : milestone, 2129,
tracing (1.868 ms) : 1853, 1883
. : milestone, 1868,
Request duration reports for petclinicgantt
title petclinic - request duration [CI 0.99] : candidate=1.62.0-SNAPSHOT~64dd1f56af, baseline=1.62.0-SNAPSHOT~9d737609c4
dateFormat X
axisFormat %s
section baseline
no_agent (18.701 ms) : 18504, 18897
. : milestone, 18701,
appsec (18.815 ms) : 18629, 19000
. : milestone, 18815,
code_origins (18.259 ms) : 18080, 18438
. : milestone, 18259,
iast (18.009 ms) : 17831, 18188
. : milestone, 18009,
profiling (18.707 ms) : 18518, 18896
. : milestone, 18707,
tracing (18.163 ms) : 17981, 18344
. : milestone, 18163,
section candidate
no_agent (19.219 ms) : 19025, 19412
. : milestone, 19219,
appsec (18.632 ms) : 18444, 18820
. : milestone, 18632,
code_origins (18.167 ms) : 17985, 18349
. : milestone, 18167,
iast (17.986 ms) : 17807, 18166
. : milestone, 17986,
profiling (18.358 ms) : 18176, 18540
. : milestone, 18358,
tracing (18.235 ms) : 18055, 18414
. : milestone, 18235,
DacapoParameters
See matching parameters
SummaryFound 0 performance improvements and 0 performance regressions! Performance is the same for 10 metrics, 2 unstable metrics. Execution time for biojavagantt
title biojava - execution time [CI 0.99] : candidate=1.62.0-SNAPSHOT~64dd1f56af, baseline=1.62.0-SNAPSHOT~9d737609c4
dateFormat X
axisFormat %s
section baseline
no_agent (14.836 s) : 14836000, 14836000
. : milestone, 14836000,
appsec (15.116 s) : 15116000, 15116000
. : milestone, 15116000,
iast (18.557 s) : 18557000, 18557000
. : milestone, 18557000,
iast_GLOBAL (17.837 s) : 17837000, 17837000
. : milestone, 17837000,
profiling (14.905 s) : 14905000, 14905000
. : milestone, 14905000,
tracing (14.925 s) : 14925000, 14925000
. : milestone, 14925000,
section candidate
no_agent (15.313 s) : 15313000, 15313000
. : milestone, 15313000,
appsec (14.964 s) : 14964000, 14964000
. : milestone, 14964000,
iast (18.241 s) : 18241000, 18241000
. : milestone, 18241000,
iast_GLOBAL (18.0 s) : 18000000, 18000000
. : milestone, 18000000,
profiling (14.935 s) : 14935000, 14935000
. : milestone, 14935000,
tracing (14.82 s) : 14820000, 14820000
. : milestone, 14820000,
Execution time for tomcatgantt
title tomcat - execution time [CI 0.99] : candidate=1.62.0-SNAPSHOT~64dd1f56af, baseline=1.62.0-SNAPSHOT~9d737609c4
dateFormat X
axisFormat %s
section baseline
no_agent (1.478 ms) : 1467, 1490
. : milestone, 1478,
appsec (3.82 ms) : 3596, 4044
. : milestone, 3820,
iast (2.269 ms) : 2199, 2339
. : milestone, 2269,
iast_GLOBAL (2.314 ms) : 2243, 2384
. : milestone, 2314,
profiling (2.106 ms) : 2051, 2161
. : milestone, 2106,
tracing (2.093 ms) : 2039, 2148
. : milestone, 2093,
section candidate
no_agent (1.485 ms) : 1474, 1497
. : milestone, 1485,
appsec (3.818 ms) : 3594, 4042
. : milestone, 3818,
iast (2.276 ms) : 2206, 2346
. : milestone, 2276,
iast_GLOBAL (2.325 ms) : 2254, 2395
. : milestone, 2325,
profiling (2.52 ms) : 2361, 2679
. : milestone, 2520,
tracing (2.082 ms) : 2028, 2136
. : milestone, 2082,
|
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 43d9017c46
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 510b150f9c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
|
Codex Review: Didn't find any major issues. Nice work! ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
|
@codex review |
|
Codex Review: Didn't find any major issues. Can't wait for the next one! ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
When AppSec has a server.request.body.files_content subscriber but no requestBodyProcessed subscriber, the new callback == null && contentCb == null gate lets this loop run with callback == null, yet it still calls Attribute.getValue() for every non-file multipart field even though attributes is never published. A large, disk-backed, or unreadable form field can allocate unnecessarily or set exc and make the advice throw before/after file-content inspection, so a files-content-only WAF rule can break requests that contain ordinary form fields; guard this branch with callback != null or skip building attributes unless it will be sent.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
|
Codex Review: Didn't find any major issues. Keep it up! ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
20e59a8 to
5632a09
Compare
|
@codex review |
|
Codex Review: Didn't find any major issues. Keep it up! ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0241bc3a31
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…tipartHelper and add unit tests
09af9f3 to
fe101c7
Compare
…h decoder charset expectation
Deduplicates the identical RequestBlockingAction dispatch pattern that appeared three times in the Netty multipart advice.
|
@codex review |
|
Codex Review: Didn't find any major issues. Breezy! ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
| } | ||
| } | ||
| } | ||
| return exc; |
There was a problem hiding this comment.
The exception is later thrown in the advice, is that on purpose? this will be propagated to the framework code.
My bad, the tryBlock is the one propagated to be thrown in the advice, this one is thrown just to be logged afterwards.
…helper with addToContents() The constant now lives in the helper class (listed in helperClassNames()) where it is actually used, instead of the outer instrumentation class which is not visible from inlined advice bytecode in the app classloader. addToContents() encapsulates the limit check alongside the constant.
…ile fields in ParameterCollector Use separate volatile fields (cachedPartClass, cachedGetInputStream, cachedGetContentType, cachedGetFilename) instead of Map.Entry<Class<?>, Method[]> + Map.Entry<Class<?>, Method>. cachedPartClass is written last to safely publish the three methods per JMM volatile ordering.
4b6df53 to
a40ec38
Compare
…) limit behaviour
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: eef2b0adee
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…lock in Netty multipart Unconditionally assigning thr = tryBlock(...) would null out an original decoder exception (e.g. malformed multipart on an over-limit body) when tryBlock returns null for a non-blocking flow. Only overwrite thr when tryBlock returns a blocking exception.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fc8a83a21c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…older Four flat volatile fields have a TOCTOU race: thread A passes the cachedPartClass check, thread B overwrites the three method fields for a different class, and thread A invokes the wrong Method on its instance (IllegalArgumentException is swallowed, the part is silently dropped). Replace the four fields with a single volatile CachedMethods reference that holds an immutable snapshot of all three methods. Readers load the reference once into a local variable, so their snapshot stays consistent even if another thread publishes a new entry concurrently. Add a concurrency regression test that runs two threads simultaneously with different concrete Part classes; it detects dropped parts caused by the race.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c426af2f69
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…strumentation ByteBuddy only injects classes explicitly listed in helperClassNames(); nested inner classes are not auto-discovered. Without this entry, the first addPart() call triggers NoClassDefFoundError on CachedMethods, which is swallowed by the broad catch in addPart(), silently dropping all filenames and file contents.
|
@codex review |
|
Codex Review: Didn't find any major issues. Already looking forward to the next diff. ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
What Does This Do
Extends the
server.request.body.files_contentWAF address (introduced in #11137 for commons-fileupload) to Tomcat and Netty multipart. Each uploaded file contributes its firstDD_APPSEC_MAX_FILE_CONTENT_BYTESbytes (default 4 096), up toDD_APPSEC_MAX_FILE_CONTENT_COUNTfiles per request (default 25), with charset-aware decoding viaMultipartContentDecoder(shared across all three integrations viainternal-api).Netty (
HttpPostRequestDecoderInstrumentation+NettyMultipartHelper)NettyMultipartHelper(injected viahelperClassNames()) centralises all multipart logic:collectBodyData()— iteratesgetBodyHttpDatas(), populating form attributes, filenames and file contents; reads in-memory uploads viagetByteBuf()and disk-backed uploads viaFileInputStream(fileUpload.getFile())tryBlock()— deduplicates the three blocking paths (body / filenames / content): checksRequestBlockingAction, callstryCommitBlockingResponse, returnsBlockingExceptionornullreadContent()— reads up toMAX_CONTENT_BYTESbytes with charset decoding fromfileUpload.getContentType()PREEPILOGUEvsEPILOGUEstatus mismatch: when aFullHttpRequestarrives in one shot,parseBody()leaves status atPREEPILOGUE; the advice now also fires onPREEPILOGUE + isLastChunk == truerequestBodyProcessed,requestFilesFilenames,requestFilesContent) before the early-return guard; skips form attribute I/O whenrequestBodyProcessedis not registeredthrwith aBlockingExceptionwhentryBlockreturns non-null, so Netty decoder errors (malformed body, over-limit) are not silently swallowedTomcat (
ParameterCollector/ParsePartsInstrumentation)ParameterCollectorImpl.addPart()to read file content via reflection onPart.getInputStream()andPart.getContentType()(avoids direct bytecode references to Tomcat version-specificParttypes)getSubmittedFileName()(Servlet 3.1+ / Tomcat 8+) with fallback togetFilename()(Tomcat 7);null= form field (skip),""= file without name (inspect content)volatilefields —cachedPartClass,cachedGetInputStream,cachedGetContentType,cachedGetFilename— written inresolveAndCacheMethods()withcachedPartClasslast for safe publication under the JMMParsePartsInstrumentation: passesinspectContentflag (true only whenrequestFilesContentcallback is registered) to avoid unnecessarygetInputStream()I/O; all three blocking paths now correctly calleffectivelyBlocked()withtassigned before the callgetContents()/ParameterCollectorNoop.getContents()returns empty listCommonsFileUpload (
CommonsFileUploadAppSecInstrumentation/FileItemContentReader)FileItemContentReader.addToContents(FileItem, List<String>)encapsulates theMAX_FILES_TO_INSPECTlimit check, replacing the inline counter in the advice loop;MAX_CONTENT_BYTESandMAX_FILES_TO_INSPECTare now backed byConfig.getAppSecMaxFileContentBytes()/Config.getAppSecMaxFileContentCount()filenameslist allocation: only allocated when therequestFilesFilenamescallback is registered;readContent()usesMultipartContentDecoder.readInputStream()instead of a manual byte loopif (t == null)guard instead of earlyreturn, mirroring the Netty/Tomcat patternConfig / test infra
DD_APPSEC_MAX_FILE_CONTENT_BYTESandDD_APPSEC_MAX_FILE_CONTENT_COUNTadded toConfigDefaults,AppSecConfig,Config, andsupported-configurations.jsonNettyMultipartHelperTest(25+ unit tests),ParameterCollectorImplTestandaddToContentstests inFileItemContentReaderTestHttpServerTestextended withtestBodyFilesContent()integration test covering WAF detection, blocking, per-file byte limit and file count limitMotivation
Extends the AppSec file-upload attack surface to file content (not just filenames) on Tomcat and Netty, enabling WAF rules that inspect uploaded payloads for malicious content (e.g. PHP webshells, EICAR strings).
Jira ticket: APPSEC-61875
Additional Notes
NettyMultipartHelperas a separate class (not inline advice) — the advice runs in the agent classloader;ByteBuf,FileUploadand related Netty types only exist in the app classloader. Declaring the helper inhelperClassNames()lets ByteBuddy inject it into the right classloader. A second benefit: the helper is unit-testable without ByteBuddy.Reflection cache — four flat
volatilefields — the four fields arecachedPartClass,cachedGetInputStream,cachedGetContentType,cachedGetFilename. WritingcachedPartClasslast inresolveAndCacheMethods()acts as the JMM publication fence: any thread that observescachedPartClass == partClassis guaranteed to also see the three method fields written before it.cachedGetFilename == nullmeans "method not found in this class" (not "uninitialised"), which is safe becausecachedPartClassalways matches before the field is used.effectivelyBlocked()absent from all Netty blocking paths —NettyBlockResponseFunction.tryCommitBlockingResponsefinishes the span synchronously (viaBlockingResponseHandler), which internally callseffectivelyBlocked(). A second call on an already-finished span throws; withsuppress = Throwable.classthat exception is swallowed and the subsequentthr = new BlockingException(...)never executes. All Tomcat paths do calleffectivelyBlocked()explicitly (the Tomcat BRF does not), withtassigned before the call.Contributor Checklist
type:and (comp:orinst:) labels in addition to any other useful labelsclose,fix, or any linking keywords when referencing an issueUse
solvesinstead, and assign the PR milestone to the issueNote: Once your PR is ready to merge, add it to the merge queue by commenting
/merge./merge -ccancels the queue request./merge -f --reason "reason"skips all merge queue checks; please use this judiciously, as some checks do not run at the PR-level. For more information, see this doc.