Skip to content

Add server.request.body.files_content AppSec address for Tomcat and Netty multipart#11198

Draft
jandro996 wants to merge 20 commits intoalejandro.gonzalez/APPSEC-61875-file-upload-contentfrom
alejandro.gonzalez/APPSEC-61875-files-content-tomcat-netty
Draft

Add server.request.body.files_content AppSec address for Tomcat and Netty multipart#11198
jandro996 wants to merge 20 commits intoalejandro.gonzalez/APPSEC-61875-file-upload-contentfrom
alejandro.gonzalez/APPSEC-61875-files-content-tomcat-netty

Conversation

@jandro996
Copy link
Copy Markdown
Member

@jandro996 jandro996 commented Apr 24, 2026

What Does This Do

Extends the server.request.body.files_content WAF address (introduced in #11137) to Tomcat and Netty multipart instrumentation. Each uploaded file contributes its first 4 096 bytes (ISO-8859-1), up to 25 files per request.

Netty instrumentation (HttpPostRequestDecoderInstrumentation)

  • Extends ParseBodyAdvice to collect file contents; adds NettyFileUploadContentReader helper (injected via helperClassNames()) that reads in-memory uploads via getByteBuf() and disk-backed uploads via FileInputStream(fileUpload.getFile())
  • Fixes a PREEPILOGUE vs EPILOGUE status mismatch: when a FullHttpRequest arrives in one shot, HttpPostMultipartRequestDecoder.parseBody() leaves status at PREEPILOGUE (the second parseBody() call that would advance to EPILOGUE never comes); the advice now also fires on PREEPILOGUE + isLastChunk == true
  • Fetches both requestBodyProcessed and requestFilesContent callbacks before the early-return guard, using callback == null && contentCb == null as the exit condition; skips form attribute I/O when requestBodyProcessed is not registered

Tomcat instrumentation (ParameterCollector / ParsePartsInstrumentation)

  • Extends ParameterCollector.addPart() to read file content via reflection on Part.getInputStream() (avoids a direct bytecode reference to Tomcat version-specific Part types); resolves getSubmittedFileName() (Servlet 3.1+ / Tomcat 8+) with fallback to getFilename() (Tomcat 7)
  • Caches the resolved Method per concrete Part class using a volatile Map.Entry<Class<?>, Method> for safe, one-shot publication under the Java Memory Model
  • Correctly skips form fields: null filename = no filename parameter = form field (skip); empty string = file upload without a name (inspect content)
  • ParsePartsInstrumentation: passes inspectContent flag (only true when requestFilesContent is registered) to ParameterCollectorImpl to avoid unnecessary I/O

Motivation

Extends the AppSec file upload attack surface to cover 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

Reflection cache design for TomcatParameterCollector uses a volatile Map.Entry<Class<?>, Method> (not a plain volatile Method) because the Part concrete class can vary across Tomcat versions in the same JVM. The cache entry stores both the class identity and the resolved method; when the class changes the method is re-resolved. This follows the static-field pattern for multi-version library support without a direct bytecode reference to the varying type.

effectivelyBlocked() absent from all three Netty blocking pathsNettyBlockResponseFunction.tryCommitBlockingResponse finishes the Netty span synchronously (via BlockingResponseHandler), which internally calls effectivelyBlocked(). Calling it a second time on an already-finished span throws. The Tomcat paths do not have this constraint and correctly call effectivelyBlocked() after t = new BlockingException(...).

Contributor Checklist

Note: Once your PR is ready to merge, add it to the merge queue by commenting /merge. /merge -c cancels 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.

…ltipart

Read up to 4096 bytes per file (ISO-8859-1, max 25 files) and fire the
server.request.body.files_content callback after the filenames callback, only
when the request has not already been blocked.

- ParameterCollector: add readContent() via reflection on getInputStream(),
  getContents() getter, and MAX_FILES_TO_INSPECT guard
- ParsePartsInstrumentation: dispatch requestFilesContent() after
  requestFilesFilenames() when t == null
- HttpPostRequestDecoderInstrumentation: collect file content inline in the
  getBodyHttpDatas() loop (in-memory via ByteBuf, on-disk via FileInputStream)
  and dispatch requestFilesContent() when thr == null after filenames
- Add ParameterCollectorImplTest covering truncation, 25-file cap, form-field
  skip, IOException fallback, and ISO-8859-1 round-trip
…tation

Issue 1 — Netty: extract MAX_CONTENT_BYTES=4096 and MAX_FILES_TO_INSPECT=25 as
named constants in ParseBodyAdvice, replacing raw magic literals.

Issue 3 — Tomcat + Netty: call effectivelyBlocked() after tryCommitBlockingResponse
in both the filenames and files_content blocking paths, matching the behaviour
already present in CommonsFileUploadAppSecInstrumentation.

Issue 4 — Netty: collect file content for ALL FileUpload data items regardless
of whether filename is present or empty; HttpDataType.FileUpload is the
file-vs-form-field discriminator in Netty's model, so the filename-empty check
was incorrectly skipping content for unnamed file parts (inconsistent with
FileItemContentReader which only skips isFormField() items).
…ation

Issue 1 — Tomcat: inspect file content even when submitted filename is empty.
getSubmittedFileName() returns null for form fields (no filename parameter) and ""
for file uploads whose client explicitly sent filename="". Null is now the only
skip condition, so file parts with an empty filename are inspected but not added
to the filenames list, matching the commons-fileupload and Netty behaviour.

Issue 2 — Netty: remove unnecessary (long) casts in Math.min; both operands are
already int so Math.min(int,int) resolves directly.

Issue 3 — Netty: replace manual try/finally on FileInputStream with
try-with-resources, consistent with FileItemContentReader style.
…tty files_content

Move BlockingException assignment inside the brf != null guard so it is
only thrown when the blocking response was actually committed.  Also add
effectivelyBlocked() to the Tomcat body-processed path, and remove the
redundant if (t == null) guard there.

For the Netty body-processed path (urlencoded), effectivelyBlocked() is
intentionally omitted: tryCommitBlockingResponse() finishes the Netty
span synchronously, so calling effectivelyBlocked() afterwards would
interact with an already-closed TraceSegment.
…callback is unregistered

Pre-fetch the requestFilesContent callback before the body-data loop and
guard ByteBuf/FileInputStream reads behind it, consistent with how
CommonsFileUploadAppSecInstrumentation already does. Also flattens the
post-loop dispatch block by one nesting level.
…ad loop

Move thr = new BlockingException(...) for the filenames path in Netty
inside the brf != null guard, consistent with the body-processed and
content paths in the same advice and with the Tomcat/Liberty pattern.

Merge the two FileItem iterations in CommonsFileUploadAppSecInstrumentation
into a single loop that builds both filenames and filesContent in one pass,
calling FileItemContentReader.readContent() per item instead of a separate
FileItemContentReader.readContents() sweep.
The bulk readContents(List<FileItem>) method is no longer called — the
advice iterates file items inline calling readContent(FileItem) per item.
Remove the method, its now-unused ArrayList/List imports, and the
corresponding test cases. Also fix redundant type witness on ArrayList
construction in CommonsFileUploadAppSecInstrumentation.
…oad guard style

Skip filesContent ArrayList allocation in Netty ParseBodyAdvice when the
requestFilesContent callback is not registered, matching the null-sentinel
pattern already used in CommonsFileUploadAppSecInstrumentation.

Replace the early-return in CommonsFileUploadAppSecInstrumentation's
filenames blocking branch with a t == null guard on the content dispatch
block, aligning control flow with ParsePartsInstrumentation and
HttpPostRequestDecoderInstrumentation.
… callback is unregistered

Add an inspectContent boolean to ParameterCollectorImpl, set from the
presence of the requestFilesContent callback in ParsePartsInstrumentation
before(). When false, addPart() still collects filenames but skips the
getInputStream() read, matching the lazy-init approach already used by
the Netty and commons-fileupload integrations.
… paths

The content path in Netty and both the filenames and content paths in
Tomcat were setting the BlockingException outside the if (brf != null)
block, meaning the exception would be thrown even when no blocking
response had actually been committed. Align all three with the canonical
pattern: tryCommitBlockingResponse + effectivelyBlocked + exception
assignment all inside if (brf != null).

The Netty body-processed path intentionally still omits effectivelyBlocked()
because tryCommitBlockingResponse() closes the Netty span synchronously in
the test environment, making a subsequent effectivelyBlocked() call fail.
…meterCollector

- Replace per-call getMethod() with volatile (Class, Method) entry cache so
  reflection resolves once per concrete Part class rather than per file per request.
- Use try-with-resources for InputStream in readContent() instead of try/finally.
- Add unit test covering the Tomcat 7 getFilename() fallback path.
… file content

Also fix HttpPostRequestDecoderInstrumentation to fire on PREEPILOGUE+isLastChunk
so that multipart requests delivered as a FullHttpRequest (single shot) trigger the
requestBodyProcessed/requestFilesFilenames/requestFilesContent callbacks. The
PREEPILOGUE→EPILOGUE transition requires a second parseBody() call which never
comes when the full request arrives in one shot; PREEPILOGUE+isLastChunk is
equivalent to EPILOGUE in that scenario.
@jandro996 jandro996 added type: enhancement Enhancements and improvements comp: asm waf Application Security Management (WAF) labels Apr 24, 2026
…adContentReader helper

Move the in-memory/disk-backed FileUpload content reading logic out of ParseBodyAdvice
into a testable static helper class. Also fixes the partial-read risk on disk-backed
uploads (single fis.read() replaced by a loop) and broadens the catch to Exception to
handle IllegalReferenceCountException from released ByteBufs.
@pr-commenter
Copy link
Copy Markdown

pr-commenter Bot commented Apr 24, 2026

Benchmarks

Startup

Parameters

Baseline Candidate
baseline_or_candidate baseline candidate
git_branch master alejandro.gonzalez/APPSEC-61875-files-content-tomcat-netty
git_commit_date 1776685998 1777044120
git_commit_sha 71f9713 cac2d3d
release_version 1.62.0-SNAPSHOT~71f9713d93 1.62.0-SNAPSHOT~cac2d3d976
See matching parameters
Baseline Candidate
application insecure-bank insecure-bank
ci_job_date 1777045908 1777045908
ci_job_id 1629013894 1629013894
ci_pipeline_id 109588337 109588337
cpu_model Intel(R) Xeon(R) Platinum 8259CL CPU @ 2.50GHz Intel(R) Xeon(R) Platinum 8259CL CPU @ 2.50GHz
kernel_version Linux runner-zfyrx7zua-project-304-concurrent-5-0llws8dt 6.8.0-1031-aws #33~22.04.1-Ubuntu SMP Thu Jun 26 14:22:30 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux Linux runner-zfyrx7zua-project-304-concurrent-5-0llws8dt 6.8.0-1031-aws #33~22.04.1-Ubuntu SMP Thu Jun 26 14:22:30 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux
module Agent Agent
parent None None

Summary

Found 0 performance improvements and 0 performance regressions! Performance is the same for 62 metrics, 9 unstable metrics.

Startup time reports for insecure-bank
gantt
    title insecure-bank - global startup overhead: candidate=1.62.0-SNAPSHOT~cac2d3d976, baseline=1.62.0-SNAPSHOT~71f9713d93

    dateFormat X
    axisFormat %s
section tracing
Agent [baseline] (1.067 s) : 0, 1066951
Total [baseline] (8.92 s) : 0, 8920026
Agent [candidate] (1.061 s) : 0, 1061385
Total [candidate] (8.856 s) : 0, 8855524
section iast
Agent [baseline] (1.233 s) : 0, 1233167
Total [baseline] (9.582 s) : 0, 9581557
Agent [candidate] (1.233 s) : 0, 1232990
Total [candidate] (9.567 s) : 0, 9566770
Loading
  • baseline results
Module Variant Duration Δ tracing
Agent tracing 1.067 s -
Agent iast 1.233 s 166.216 ms (15.6%)
Total tracing 8.92 s -
Total iast 9.582 s 661.531 ms (7.4%)
  • candidate results
Module Variant Duration Δ tracing
Agent tracing 1.061 s -
Agent iast 1.233 s 171.605 ms (16.2%)
Total tracing 8.856 s -
Total iast 9.567 s 711.246 ms (8.0%)
gantt
    title insecure-bank - break down per module: candidate=1.62.0-SNAPSHOT~cac2d3d976, baseline=1.62.0-SNAPSHOT~71f9713d93

    dateFormat X
    axisFormat %s
section tracing
crashtracking [baseline] (1.272 ms) : 0, 1272
crashtracking [candidate] (1.254 ms) : 0, 1254
BytebuddyAgent [baseline] (640.596 ms) : 0, 640596
BytebuddyAgent [candidate] (635.992 ms) : 0, 635992
AgentMeter [baseline] (29.825 ms) : 0, 29825
AgentMeter [candidate] (29.625 ms) : 0, 29625
GlobalTracer [baseline] (250.347 ms) : 0, 250347
GlobalTracer [candidate] (249.882 ms) : 0, 249882
AppSec [baseline] (32.631 ms) : 0, 32631
AppSec [candidate] (32.481 ms) : 0, 32481
Debugger [baseline] (59.448 ms) : 0, 59448
Debugger [candidate] (59.212 ms) : 0, 59212
Remote Config [baseline] (604.384 µs) : 0, 604
Remote Config [candidate] (590.108 µs) : 0, 590
Telemetry [baseline] (8.081 ms) : 0, 8081
Telemetry [candidate] (8.021 ms) : 0, 8021
Flare Poller [baseline] (7.604 ms) : 0, 7604
Flare Poller [candidate] (8.029 ms) : 0, 8029
section iast
crashtracking [baseline] (1.234 ms) : 0, 1234
crashtracking [candidate] (1.245 ms) : 0, 1245
BytebuddyAgent [baseline] (810.387 ms) : 0, 810387
BytebuddyAgent [candidate] (810.531 ms) : 0, 810531
AgentMeter [baseline] (11.439 ms) : 0, 11439
AgentMeter [candidate] (11.459 ms) : 0, 11459
GlobalTracer [baseline] (239.616 ms) : 0, 239616
GlobalTracer [candidate] (240.288 ms) : 0, 240288
IAST [baseline] (29.272 ms) : 0, 29272
IAST [candidate] (29.089 ms) : 0, 29089
AppSec [baseline] (31.163 ms) : 0, 31163
AppSec [candidate] (28.458 ms) : 0, 28458
Debugger [baseline] (62.151 ms) : 0, 62151
Debugger [candidate] (63.298 ms) : 0, 63298
Remote Config [baseline] (542.707 µs) : 0, 543
Remote Config [candidate] (529.079 µs) : 0, 529
Telemetry [baseline] (7.755 ms) : 0, 7755
Telemetry [candidate] (7.695 ms) : 0, 7695
Flare Poller [baseline] (3.422 ms) : 0, 3422
Flare Poller [candidate] (3.405 ms) : 0, 3405
Loading
Startup time reports for petclinic
gantt
    title petclinic - global startup overhead: candidate=1.62.0-SNAPSHOT~cac2d3d976, baseline=1.62.0-SNAPSHOT~71f9713d93

    dateFormat X
    axisFormat %s
section tracing
Agent [baseline] (1.067 s) : 0, 1067480
Total [baseline] (11.134 s) : 0, 11134210
Agent [candidate] (1.06 s) : 0, 1060126
Total [candidate] (11.096 s) : 0, 11096275
section appsec
Agent [baseline] (1.273 s) : 0, 1272817
Total [baseline] (11.013 s) : 0, 11012956
Agent [candidate] (1.275 s) : 0, 1275176
Total [candidate] (11.033 s) : 0, 11032719
section iast
Agent [baseline] (1.24 s) : 0, 1239852
Total [baseline] (11.413 s) : 0, 11413195
Agent [candidate] (1.235 s) : 0, 1234940
Total [candidate] (11.399 s) : 0, 11399176
section profiling
Agent [baseline] (1.205 s) : 0, 1204549
Total [baseline] (11.137 s) : 0, 11137464
Agent [candidate] (1.188 s) : 0, 1187938
Total [candidate] (11.137 s) : 0, 11137105
Loading
  • baseline results
Module Variant Duration Δ tracing
Agent tracing 1.067 s -
Agent appsec 1.273 s 205.337 ms (19.2%)
Agent iast 1.24 s 172.371 ms (16.1%)
Agent profiling 1.205 s 137.069 ms (12.8%)
Total tracing 11.134 s -
Total appsec 11.013 s -121.255 ms (-1.1%)
Total iast 11.413 s 278.985 ms (2.5%)
Total profiling 11.137 s 3.253 ms (0.0%)
  • candidate results
Module Variant Duration Δ tracing
Agent tracing 1.06 s -
Agent appsec 1.275 s 215.05 ms (20.3%)
Agent iast 1.235 s 174.814 ms (16.5%)
Agent profiling 1.188 s 127.812 ms (12.1%)
Total tracing 11.096 s -
Total appsec 11.033 s -63.556 ms (-0.6%)
Total iast 11.399 s 302.902 ms (2.7%)
Total profiling 11.137 s 40.83 ms (0.4%)
gantt
    title petclinic - break down per module: candidate=1.62.0-SNAPSHOT~cac2d3d976, baseline=1.62.0-SNAPSHOT~71f9713d93

    dateFormat X
    axisFormat %s
section tracing
crashtracking [baseline] (1.25 ms) : 0, 1250
crashtracking [candidate] (1.23 ms) : 0, 1230
BytebuddyAgent [baseline] (639.925 ms) : 0, 639925
BytebuddyAgent [candidate] (633.811 ms) : 0, 633811
AgentMeter [baseline] (29.898 ms) : 0, 29898
AgentMeter [candidate] (29.624 ms) : 0, 29624
GlobalTracer [baseline] (251.281 ms) : 0, 251281
GlobalTracer [candidate] (249.716 ms) : 0, 249716
AppSec [baseline] (32.417 ms) : 0, 32417
AppSec [candidate] (32.448 ms) : 0, 32448
Debugger [baseline] (60.001 ms) : 0, 60001
Debugger [candidate] (59.951 ms) : 0, 59951
Remote Config [baseline] (589.091 µs) : 0, 589
Remote Config [candidate] (603.571 µs) : 0, 604
Telemetry [baseline] (8.847 ms) : 0, 8847
Telemetry [candidate] (8.051 ms) : 0, 8051
Flare Poller [baseline] (6.812 ms) : 0, 6812
Flare Poller [candidate] (8.371 ms) : 0, 8371
section appsec
crashtracking [baseline] (1.242 ms) : 0, 1242
crashtracking [candidate] (1.239 ms) : 0, 1239
BytebuddyAgent [baseline] (680.972 ms) : 0, 680972
BytebuddyAgent [candidate] (680.637 ms) : 0, 680637
AgentMeter [baseline] (12.249 ms) : 0, 12249
AgentMeter [candidate] (12.32 ms) : 0, 12320
GlobalTracer [baseline] (251.363 ms) : 0, 251363
GlobalTracer [candidate] (252.455 ms) : 0, 252455
IAST [baseline] (24.547 ms) : 0, 24547
IAST [candidate] (24.657 ms) : 0, 24657
AppSec [baseline] (187.41 ms) : 0, 187410
AppSec [candidate] (188.675 ms) : 0, 188675
Debugger [baseline] (66.337 ms) : 0, 66337
Debugger [candidate] (66.646 ms) : 0, 66646
Remote Config [baseline] (583.449 µs) : 0, 583
Remote Config [candidate] (576.857 µs) : 0, 577
Telemetry [baseline] (7.975 ms) : 0, 7975
Telemetry [candidate] (7.908 ms) : 0, 7908
Flare Poller [baseline] (3.504 ms) : 0, 3504
Flare Poller [candidate] (3.452 ms) : 0, 3452
section iast
crashtracking [baseline] (1.264 ms) : 0, 1264
crashtracking [candidate] (1.241 ms) : 0, 1241
BytebuddyAgent [baseline] (813.879 ms) : 0, 813879
BytebuddyAgent [candidate] (809.34 ms) : 0, 809340
AgentMeter [baseline] (11.489 ms) : 0, 11489
AgentMeter [candidate] (11.416 ms) : 0, 11416
GlobalTracer [baseline] (241.489 ms) : 0, 241489
GlobalTracer [candidate] (241.011 ms) : 0, 241011
IAST [baseline] (30.108 ms) : 0, 30108
IAST [candidate] (29.22 ms) : 0, 29220
AppSec [baseline] (27.606 ms) : 0, 27606
AppSec [candidate] (29.852 ms) : 0, 29852
Debugger [baseline] (65.97 ms) : 0, 65970
Debugger [candidate] (64.989 ms) : 0, 64989
Remote Config [baseline] (542.007 µs) : 0, 542
Remote Config [candidate] (533.574 µs) : 0, 534
Telemetry [baseline] (7.844 ms) : 0, 7844
Telemetry [candidate] (7.802 ms) : 0, 7802
Flare Poller [baseline] (3.44 ms) : 0, 3440
Flare Poller [candidate] (3.384 ms) : 0, 3384
section profiling
crashtracking [baseline] (1.213 ms) : 0, 1213
crashtracking [candidate] (1.197 ms) : 0, 1197
BytebuddyAgent [baseline] (703.51 ms) : 0, 703510
BytebuddyAgent [candidate] (693.736 ms) : 0, 693736
AgentMeter [baseline] (9.314 ms) : 0, 9314
AgentMeter [candidate] (9.195 ms) : 0, 9195
GlobalTracer [baseline] (210.53 ms) : 0, 210530
GlobalTracer [candidate] (207.417 ms) : 0, 207417
AppSec [baseline] (33.33 ms) : 0, 33330
AppSec [candidate] (32.838 ms) : 0, 32838
Debugger [baseline] (66.915 ms) : 0, 66915
Debugger [candidate] (65.688 ms) : 0, 65688
Remote Config [baseline] (610.791 µs) : 0, 611
Remote Config [candidate] (586.511 µs) : 0, 587
Telemetry [baseline] (7.977 ms) : 0, 7977
Telemetry [candidate] (7.741 ms) : 0, 7741
Flare Poller [baseline] (3.598 ms) : 0, 3598
Flare Poller [candidate] (3.497 ms) : 0, 3497
ProfilingAgent [baseline] (95.293 ms) : 0, 95293
ProfilingAgent [candidate] (94.699 ms) : 0, 94699
Profiling [baseline] (95.864 ms) : 0, 95864
Profiling [candidate] (95.268 ms) : 0, 95268
Loading

Load

Parameters

Baseline Candidate
baseline_or_candidate baseline candidate
git_branch master alejandro.gonzalez/APPSEC-61875-files-content-tomcat-netty
git_commit_date 1776685998 1777044120
git_commit_sha 71f9713 cac2d3d
release_version 1.62.0-SNAPSHOT~71f9713d93 1.62.0-SNAPSHOT~cac2d3d976
See matching parameters
Baseline Candidate
application insecure-bank insecure-bank
ci_job_date 1777046379 1777046379
ci_job_id 1629013895 1629013895
ci_pipeline_id 109588337 109588337
cpu_model Intel(R) Xeon(R) Platinum 8259CL CPU @ 2.50GHz Intel(R) Xeon(R) Platinum 8259CL CPU @ 2.50GHz
kernel_version Linux runner-zfyrx7zua-project-304-concurrent-3-97qg6qtf 6.8.0-1031-aws #33~22.04.1-Ubuntu SMP Thu Jun 26 14:22:30 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux Linux runner-zfyrx7zua-project-304-concurrent-3-97qg6qtf 6.8.0-1031-aws #33~22.04.1-Ubuntu SMP Thu Jun 26 14:22:30 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux

Summary

Found 4 performance improvements and 3 performance regressions! Performance is the same for 12 metrics, 17 unstable metrics.

scenario Δ mean agg_http_req_duration_p50 Δ mean agg_http_req_duration_p95 Δ mean throughput candidate mean agg_http_req_duration_p50 candidate mean agg_http_req_duration_p95 candidate mean throughput baseline mean agg_http_req_duration_p50 baseline mean agg_http_req_duration_p95 baseline mean throughput
scenario:load:petclinic:iast:high_load worse
[+1.219ms; +2.540ms] or [+7.006%; +14.595%]
worse
[+1.290ms; +2.806ms] or [+4.546%; +9.887%]
unstable
[-46.622op/s; +3.685op/s] or [-17.736%; +1.402%]
19.281ms 30.427ms 241.406op/s 17.401ms 28.379ms 262.875op/s
scenario:load:petclinic:tracing:high_load better
[-2.343ms; -1.192ms] or [-12.126%; -6.167%]
better
[-2.837ms; -1.268ms] or [-9.198%; -4.110%]
unstable
[-4.009op/s; +45.884op/s] or [-1.681%; +19.239%]
17.554ms 28.790ms 259.438op/s 19.322ms 30.843ms 238.500op/s
scenario:load:petclinic:profiling:high_load worse
[+371.263µs; +1261.602µs] or [+2.052%; +6.973%]
unsure
[+0.341ms; +2.039ms] or [+1.154%; +6.907%]
unstable
[-34.216op/s; +14.466op/s] or [-13.536%; +5.723%]
18.909ms 30.719ms 242.906op/s 18.093ms 29.529ms 252.781op/s
scenario:load:petclinic:code_origins:high_load better
[-2.079ms; -1.758ms] or [-10.695%; -9.043%]
better
[-2.341ms; -1.233ms] or [-7.606%; -4.008%]
unstable
[-0.461op/s; +47.649op/s] or [-0.195%; +20.137%]
17.524ms 28.987ms 260.219op/s 19.443ms 30.774ms 236.625op/s
Request duration reports for petclinic
gantt
    title petclinic - request duration [CI 0.99] : candidate=1.62.0-SNAPSHOT~cac2d3d976, baseline=1.62.0-SNAPSHOT~71f9713d93
    dateFormat X
    axisFormat %s
section baseline
no_agent (17.858 ms) : 17675, 18040
.   : milestone, 17858,
appsec (18.431 ms) : 18245, 18617
.   : milestone, 18431,
code_origins (19.729 ms) : 19533, 19925
.   : milestone, 19729,
iast (17.749 ms) : 17576, 17921
.   : milestone, 17749,
profiling (18.456 ms) : 18272, 18641
.   : milestone, 18456,
tracing (19.569 ms) : 19372, 19766
.   : milestone, 19569,
section candidate
no_agent (18.167 ms) : 17980, 18354
.   : milestone, 18167,
appsec (18.628 ms) : 18435, 18821
.   : milestone, 18628,
code_origins (17.934 ms) : 17754, 18113
.   : milestone, 17934,
iast (19.335 ms) : 19141, 19529
.   : milestone, 19335,
profiling (19.214 ms) : 19017, 19411
.   : milestone, 19214,
tracing (17.983 ms) : 17805, 18162
.   : milestone, 17983,
Loading
  • baseline results
Variant Request duration [CI 0.99] Δ no_agent
no_agent 17.858 ms [17.675 ms, 18.04 ms] -
appsec 18.431 ms [18.245 ms, 18.617 ms] 573.325 µs (3.2%)
code_origins 19.729 ms [19.533 ms, 19.925 ms] 1.872 ms (10.5%)
iast 17.749 ms [17.576 ms, 17.921 ms] -108.721 µs (-0.6%)
profiling 18.456 ms [18.272 ms, 18.641 ms] 598.908 µs (3.4%)
tracing 19.569 ms [19.372 ms, 19.766 ms] 1.711 ms (9.6%)
  • candidate results
Variant Request duration [CI 0.99] Δ no_agent
no_agent 18.167 ms [17.98 ms, 18.354 ms] -
appsec 18.628 ms [18.435 ms, 18.821 ms] 461.372 µs (2.5%)
code_origins 17.934 ms [17.754 ms, 18.113 ms] -233.311 µs (-1.3%)
iast 19.335 ms [19.141 ms, 19.529 ms] 1.168 ms (6.4%)
profiling 19.214 ms [19.017 ms, 19.411 ms] 1.047 ms (5.8%)
tracing 17.983 ms [17.805 ms, 18.162 ms] -183.463 µs (-1.0%)
Request duration reports for insecure-bank
gantt
    title insecure-bank - request duration [CI 0.99] : candidate=1.62.0-SNAPSHOT~cac2d3d976, baseline=1.62.0-SNAPSHOT~71f9713d93
    dateFormat X
    axisFormat %s
section baseline
no_agent (1.267 ms) : 1254, 1280
.   : milestone, 1267,
iast (3.398 ms) : 3351, 3445
.   : milestone, 3398,
iast_FULL (6.073 ms) : 6011, 6136
.   : milestone, 6073,
iast_GLOBAL (3.686 ms) : 3625, 3747
.   : milestone, 3686,
profiling (2.333 ms) : 2311, 2356
.   : milestone, 2333,
tracing (1.869 ms) : 1853, 1884
.   : milestone, 1869,
section candidate
no_agent (1.313 ms) : 1300, 1325
.   : milestone, 1313,
iast (3.403 ms) : 3356, 3451
.   : milestone, 3403,
iast_FULL (6.053 ms) : 5991, 6114
.   : milestone, 6053,
iast_GLOBAL (3.654 ms) : 3598, 3710
.   : milestone, 3654,
profiling (2.232 ms) : 2209, 2255
.   : milestone, 2232,
tracing (1.843 ms) : 1828, 1859
.   : milestone, 1843,
Loading
  • baseline results
Variant Request duration [CI 0.99] Δ no_agent
no_agent 1.267 ms [1.254 ms, 1.28 ms] -
iast 3.398 ms [3.351 ms, 3.445 ms] 2.131 ms (168.1%)
iast_FULL 6.073 ms [6.011 ms, 6.136 ms] 4.806 ms (379.3%)
iast_GLOBAL 3.686 ms [3.625 ms, 3.747 ms] 2.419 ms (190.9%)
profiling 2.333 ms [2.311 ms, 2.356 ms] 1.066 ms (84.1%)
tracing 1.869 ms [1.853 ms, 1.884 ms] 601.54 µs (47.5%)
  • candidate results
Variant Request duration [CI 0.99] Δ no_agent
no_agent 1.313 ms [1.3 ms, 1.325 ms] -
iast 3.403 ms [3.356 ms, 3.451 ms] 2.091 ms (159.3%)
iast_FULL 6.053 ms [5.991 ms, 6.114 ms] 4.74 ms (361.1%)
iast_GLOBAL 3.654 ms [3.598 ms, 3.71 ms] 2.342 ms (178.4%)
profiling 2.232 ms [2.209 ms, 2.255 ms] 919.473 µs (70.1%)
tracing 1.843 ms [1.828 ms, 1.859 ms] 530.701 µs (40.4%)

Dacapo

Parameters

Baseline Candidate
baseline_or_candidate baseline candidate
git_branch master alejandro.gonzalez/APPSEC-61875-files-content-tomcat-netty
git_commit_date 1776685998 1777044120
git_commit_sha 71f9713 cac2d3d
release_version 1.62.0-SNAPSHOT~71f9713d93 1.62.0-SNAPSHOT~cac2d3d976
See matching parameters
Baseline Candidate
application biojava biojava
ci_job_date 1777046176 1777046176
ci_job_id 1629013896 1629013896
ci_pipeline_id 109588337 109588337
cpu_model Intel(R) Xeon(R) Platinum 8259CL CPU @ 2.50GHz Intel(R) Xeon(R) Platinum 8259CL CPU @ 2.50GHz
kernel_version Linux runner-zfyrx7zua-project-304-concurrent-0-2q8ku9lx 6.8.0-1031-aws #33~22.04.1-Ubuntu SMP Thu Jun 26 14:22:30 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux Linux runner-zfyrx7zua-project-304-concurrent-0-2q8ku9lx 6.8.0-1031-aws #33~22.04.1-Ubuntu SMP Thu Jun 26 14:22:30 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux

Summary

Found 0 performance improvements and 0 performance regressions! Performance is the same for 10 metrics, 2 unstable metrics.

Execution time for biojava
gantt
    title biojava - execution time [CI 0.99] : candidate=1.62.0-SNAPSHOT~cac2d3d976, baseline=1.62.0-SNAPSHOT~71f9713d93
    dateFormat X
    axisFormat %s
section baseline
no_agent (14.788 s) : 14788000, 14788000
.   : milestone, 14788000,
appsec (15.052 s) : 15052000, 15052000
.   : milestone, 15052000,
iast (18.314 s) : 18314000, 18314000
.   : milestone, 18314000,
iast_GLOBAL (17.948 s) : 17948000, 17948000
.   : milestone, 17948000,
profiling (14.581 s) : 14581000, 14581000
.   : milestone, 14581000,
tracing (14.957 s) : 14957000, 14957000
.   : milestone, 14957000,
section candidate
no_agent (15.315 s) : 15315000, 15315000
.   : milestone, 15315000,
appsec (15.098 s) : 15098000, 15098000
.   : milestone, 15098000,
iast (18.108 s) : 18108000, 18108000
.   : milestone, 18108000,
iast_GLOBAL (18.037 s) : 18037000, 18037000
.   : milestone, 18037000,
profiling (15.129 s) : 15129000, 15129000
.   : milestone, 15129000,
tracing (15.034 s) : 15034000, 15034000
.   : milestone, 15034000,
Loading
  • baseline results
Variant Execution Time [CI 0.99] Δ no_agent
no_agent 14.788 s [14.788 s, 14.788 s] -
appsec 15.052 s [15.052 s, 15.052 s] 264.0 ms (1.8%)
iast 18.314 s [18.314 s, 18.314 s] 3.526 s (23.8%)
iast_GLOBAL 17.948 s [17.948 s, 17.948 s] 3.16 s (21.4%)
profiling 14.581 s [14.581 s, 14.581 s] -207.0 ms (-1.4%)
tracing 14.957 s [14.957 s, 14.957 s] 169.0 ms (1.1%)
  • candidate results
Variant Execution Time [CI 0.99] Δ no_agent
no_agent 15.315 s [15.315 s, 15.315 s] -
appsec 15.098 s [15.098 s, 15.098 s] -217.0 ms (-1.4%)
iast 18.108 s [18.108 s, 18.108 s] 2.793 s (18.2%)
iast_GLOBAL 18.037 s [18.037 s, 18.037 s] 2.722 s (17.8%)
profiling 15.129 s [15.129 s, 15.129 s] -186.0 ms (-1.2%)
tracing 15.034 s [15.034 s, 15.034 s] -281.0 ms (-1.8%)
Execution time for tomcat
gantt
    title tomcat - execution time [CI 0.99] : candidate=1.62.0-SNAPSHOT~cac2d3d976, baseline=1.62.0-SNAPSHOT~71f9713d93
    dateFormat X
    axisFormat %s
section baseline
no_agent (1.485 ms) : 1474, 1497
.   : milestone, 1485,
appsec (2.547 ms) : 2491, 2603
.   : milestone, 2547,
iast (2.276 ms) : 2206, 2347
.   : milestone, 2276,
iast_GLOBAL (2.309 ms) : 2239, 2380
.   : milestone, 2309,
profiling (2.51 ms) : 2287, 2733
.   : milestone, 2510,
tracing (2.09 ms) : 2036, 2144
.   : milestone, 2090,
section candidate
no_agent (1.486 ms) : 1474, 1498
.   : milestone, 1486,
appsec (3.817 ms) : 3594, 4040
.   : milestone, 3817,
iast (2.279 ms) : 2209, 2349
.   : milestone, 2279,
iast_GLOBAL (2.313 ms) : 2243, 2384
.   : milestone, 2313,
profiling (2.095 ms) : 2040, 2149
.   : milestone, 2095,
tracing (2.075 ms) : 2022, 2129
.   : milestone, 2075,
Loading
  • baseline results
Variant Execution Time [CI 0.99] Δ no_agent
no_agent 1.485 ms [1.474 ms, 1.497 ms] -
appsec 2.547 ms [2.491 ms, 2.603 ms] 1.062 ms (71.5%)
iast 2.276 ms [2.206 ms, 2.347 ms] 791.011 µs (53.3%)
iast_GLOBAL 2.309 ms [2.239 ms, 2.38 ms] 823.831 µs (55.5%)
profiling 2.51 ms [2.287 ms, 2.733 ms] 1.025 ms (69.0%)
tracing 2.09 ms [2.036 ms, 2.144 ms] 604.356 µs (40.7%)
  • candidate results
Variant Execution Time [CI 0.99] Δ no_agent
no_agent 1.486 ms [1.474 ms, 1.498 ms] -
appsec 3.817 ms [3.594 ms, 4.04 ms] 2.331 ms (156.9%)
iast 2.279 ms [2.209 ms, 2.349 ms] 793.102 µs (53.4%)
iast_GLOBAL 2.313 ms [2.243 ms, 2.384 ms] 827.325 µs (55.7%)
profiling 2.095 ms [2.04 ms, 2.149 ms] 608.515 µs (40.9%)
tracing 2.075 ms [2.022 ms, 2.129 ms] 589.442 µs (39.7%)

@jandro996
Copy link
Copy Markdown
Member Author

@codex review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

@jandro996
Copy link
Copy Markdown
Member Author

@codex review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

@jandro996
Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Nice work!

ℹ️ 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".

@jandro996
Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Can't wait for the next one!

ℹ️ 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".

@jandro996
Copy link
Copy Markdown
Member Author

@codex review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review


P2 Badge Skip form attributes when only file content is requested

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

…k is absent

When only requestFilesContent is registered, avoid calling getValue()
on form attributes (which may trigger disk reads for large fields).
@jandro996
Copy link
Copy Markdown
Member Author

@codex review

@jandro996 jandro996 changed the title Add server.request.body.files_content AppSec address for commons-fileupload, Tomcat, and Netty Add server.request.body.files_content AppSec address for Tomcat and Netty multipart Apr 24, 2026
@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Keep it up!

ℹ️ 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".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp: asm waf Application Security Management (WAF) type: enhancement Enhancements and improvements

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant