Skip to content

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

Open
jandro996 wants to merge 45 commits intomasterfrom
alejandro.gonzalez/APPSEC-61875-files-content-tomcat-netty
Open

Add server.request.body.files_content AppSec address for Tomcat and Netty multipart#11198
jandro996 wants to merge 45 commits intomasterfrom
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 for commons-fileupload) to Tomcat and Netty multipart. Each uploaded file contributes its first DD_APPSEC_MAX_FILE_CONTENT_BYTES bytes (default 4 096), up to DD_APPSEC_MAX_FILE_CONTENT_COUNT files per request (default 25), with charset-aware decoding via MultipartContentDecoder (shared across all three integrations via internal-api).

Netty (HttpPostRequestDecoderInstrumentation + NettyMultipartHelper)

  • New NettyMultipartHelper (injected via helperClassNames()) centralises all multipart logic:
    • collectBodyData() — iterates getBodyHttpDatas(), populating form attributes, filenames and file contents; reads in-memory uploads via getByteBuf() and disk-backed uploads via FileInputStream(fileUpload.getFile())
    • tryBlock() — deduplicates the three blocking paths (body / filenames / content): checks RequestBlockingAction, calls tryCommitBlockingResponse, returns BlockingException or null
    • readContent() — reads up to MAX_CONTENT_BYTES bytes with charset decoding from fileUpload.getContentType()
  • Fixes a PREEPILOGUE vs EPILOGUE status mismatch: when a FullHttpRequest arrives in one shot, parseBody() leaves status at PREEPILOGUE; the advice now also fires on PREEPILOGUE + isLastChunk == true
  • Fetches all three callbacks (requestBodyProcessed, requestFilesFilenames, requestFilesContent) before the early-return guard; skips form attribute I/O when requestBodyProcessed is not registered
  • Preserves original decoder exceptions: only overwrites thr with a BlockingException when tryBlock returns non-null, so Netty decoder errors (malformed body, over-limit) are not silently swallowed

Tomcat (ParameterCollector / ParsePartsInstrumentation)

  • Extends ParameterCollectorImpl.addPart() to read file content via reflection on Part.getInputStream() and Part.getContentType() (avoids direct bytecode references to Tomcat version-specific Part types)
  • Resolves getSubmittedFileName() (Servlet 3.1+ / Tomcat 8+) with fallback to getFilename() (Tomcat 7); null = form field (skip), "" = file without name (inspect content)
  • Caches resolved methods in four flat volatile fields — cachedPartClass, cachedGetInputStream, cachedGetContentType, cachedGetFilename — written in resolveAndCacheMethods() with cachedPartClass last for safe publication under the JMM
  • ParsePartsInstrumentation: passes inspectContent flag (true only when requestFilesContent callback is registered) to avoid unnecessary getInputStream() I/O; all three blocking paths now correctly call effectivelyBlocked() with t assigned before the call
  • New getContents() / ParameterCollectorNoop.getContents() returns empty list

CommonsFileUpload (CommonsFileUploadAppSecInstrumentation / FileItemContentReader)

  • FileItemContentReader.addToContents(FileItem, List<String>) encapsulates the MAX_FILES_TO_INSPECT limit check, replacing the inline counter in the advice loop; MAX_CONTENT_BYTES and MAX_FILES_TO_INSPECT are now backed by Config.getAppSecMaxFileContentBytes() / Config.getAppSecMaxFileContentCount()
  • Lazy filenames list allocation: only allocated when the requestFilesFilenames callback is registered; readContent() uses MultipartContentDecoder.readInputStream() instead of a manual byte loop
  • Content blocking path uses if (t == null) guard instead of early return, mirroring the Netty/Tomcat pattern

Config / test infra

  • DD_APPSEC_MAX_FILE_CONTENT_BYTES and DD_APPSEC_MAX_FILE_CONTENT_COUNT added to ConfigDefaults, AppSecConfig, Config, and supported-configurations.json
  • New NettyMultipartHelperTest (25+ unit tests), ParameterCollectorImplTest and addToContents tests in FileItemContentReaderTest
  • HttpServerTest extended with testBodyFilesContent() integration test covering WAF detection, blocking, per-file byte limit and file count limit

Motivation

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

NettyMultipartHelper as a separate class (not inline advice) — the advice runs in the agent classloader; ByteBuf, FileUpload and related Netty types only exist in the app classloader. Declaring the helper in helperClassNames() lets ByteBuddy inject it into the right classloader. A second benefit: the helper is unit-testable without ByteBuddy.

Reflection cache — four flat volatile fields — the four fields are cachedPartClass, cachedGetInputStream, cachedGetContentType, cachedGetFilename. Writing cachedPartClass last in resolveAndCacheMethods() acts as the JMM publication fence: any thread that observes cachedPartClass == partClass is guaranteed to also see the three method fields written before it. cachedGetFilename == null means "method not found in this class" (not "uninitialised"), which is safe because cachedPartClass always matches before the field is used.

effectivelyBlocked() absent from all Netty blocking pathsNettyBlockResponseFunction.tryCommitBlockingResponse finishes the span synchronously (via BlockingResponseHandler), which internally calls effectivelyBlocked(). A second call on an already-finished span throws; with suppress = Throwable.class that exception is swallowed and the subsequent thr = new BlockingException(...) never executes. All Tomcat paths do call effectivelyBlocked() explicitly (the Tomcat BRF does not), with t assigned before the call.

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.

@jandro996 jandro996 added type: enhancement Enhancements and improvements comp: asm waf Application Security Management (WAF) labels Apr 24, 2026
@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 1777379592 1777474755
git_commit_sha 9d73760 64dd1f5
release_version 1.62.0-SNAPSHOT~9d737609c4 1.62.0-SNAPSHOT~64dd1f56af
See matching parameters
Baseline Candidate
application insecure-bank insecure-bank
ci_job_date 1777476536 1777476536
ci_job_id 1642750936 1642750936
ci_pipeline_id 110464529 110464529
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-vbt3atmj 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-vbt3atmj 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~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
Loading
  • baseline results
Module Variant Duration Δ tracing
Agent tracing 1.066 s -
Agent iast 1.256 s 189.405 ms (17.8%)
Total tracing 8.865 s -
Total iast 9.572 s 706.468 ms (8.0%)
  • candidate results
Module Variant Duration Δ tracing
Agent tracing 1.072 s -
Agent iast 1.246 s 173.231 ms (16.2%)
Total tracing 8.86 s -
Total iast 9.568 s 708.022 ms (8.0%)
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
Loading
Startup time reports for petclinic
gantt
    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
Loading
  • baseline results
Module Variant Duration Δ tracing
Agent tracing 1.073 s -
Agent appsec 1.267 s 194.06 ms (18.1%)
Agent iast 1.254 s 181.077 ms (16.9%)
Agent profiling 1.198 s 124.445 ms (11.6%)
Total tracing 11.17 s -
Total appsec 11.141 s -28.79 ms (-0.3%)
Total iast 11.41 s 239.379 ms (2.1%)
Total profiling 11.002 s -167.813 ms (-1.5%)
  • candidate results
Module Variant Duration Δ tracing
Agent tracing 1.078 s -
Agent appsec 1.271 s 192.958 ms (17.9%)
Agent iast 1.254 s 175.113 ms (16.2%)
Agent profiling 1.189 s 110.211 ms (10.2%)
Total tracing 11.161 s -
Total appsec 11.085 s -76.24 ms (-0.7%)
Total iast 11.387 s 226.419 ms (2.0%)
Total profiling 11.073 s -88.188 ms (-0.8%)
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
Loading

Load

Parameters

Baseline Candidate
baseline_or_candidate baseline candidate
git_branch master alejandro.gonzalez/APPSEC-61875-files-content-tomcat-netty
git_commit_date 1777379592 1777474755
git_commit_sha 9d73760 64dd1f5
release_version 1.62.0-SNAPSHOT~9d737609c4 1.62.0-SNAPSHOT~64dd1f56af
See matching parameters
Baseline Candidate
application insecure-bank insecure-bank
ci_job_date 1777476926 1777476926
ci_job_id 1642750939 1642750939
ci_pipeline_id 110464529 110464529
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-4-zhv6vwjk 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-4-zhv6vwjk 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 20 metrics, 16 unstable metrics.

Request duration reports for insecure-bank
gantt
    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,
Loading
  • baseline results
Variant Request duration [CI 0.99] Δ no_agent
no_agent 1.245 ms [1.233 ms, 1.256 ms] -
iast 3.414 ms [3.365 ms, 3.462 ms] 2.169 ms (174.3%)
iast_FULL 6.258 ms [6.191 ms, 6.324 ms] 5.013 ms (402.8%)
iast_GLOBAL 3.75 ms [3.681 ms, 3.818 ms] 2.505 ms (201.3%)
profiling 2.321 ms [2.298 ms, 2.344 ms] 1.076 ms (86.5%)
tracing 1.953 ms [1.934 ms, 1.971 ms] 708.046 µs (56.9%)
  • candidate results
Variant Request duration [CI 0.99] Δ no_agent
no_agent 1.266 ms [1.253 ms, 1.278 ms] -
iast 3.5 ms [3.445 ms, 3.555 ms] 2.234 ms (176.5%)
iast_FULL 6.409 ms [6.342 ms, 6.476 ms] 5.143 ms (406.4%)
iast_GLOBAL 3.707 ms [3.646 ms, 3.768 ms] 2.442 ms (192.9%)
profiling 2.129 ms [2.111 ms, 2.148 ms] 863.67 µs (68.2%)
tracing 1.868 ms [1.853 ms, 1.883 ms] 602.405 µs (47.6%)
Request duration reports for petclinic
gantt
    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,
Loading
  • baseline results
Variant Request duration [CI 0.99] Δ no_agent
no_agent 18.701 ms [18.504 ms, 18.897 ms] -
appsec 18.815 ms [18.629 ms, 19.0 ms] 113.81 µs (0.6%)
code_origins 18.259 ms [18.08 ms, 18.438 ms] -441.666 µs (-2.4%)
iast 18.009 ms [17.831 ms, 18.188 ms] -691.609 µs (-3.7%)
profiling 18.707 ms [18.518 ms, 18.896 ms] 6.249 µs (0.0%)
tracing 18.163 ms [17.981 ms, 18.344 ms] -538.184 µs (-2.9%)
  • candidate results
Variant Request duration [CI 0.99] Δ no_agent
no_agent 19.219 ms [19.025 ms, 19.412 ms] -
appsec 18.632 ms [18.444 ms, 18.82 ms] -586.301 µs (-3.1%)
code_origins 18.167 ms [17.985 ms, 18.349 ms] -1.052 ms (-5.5%)
iast 17.986 ms [17.807 ms, 18.166 ms] -1.232 ms (-6.4%)
profiling 18.358 ms [18.176 ms, 18.54 ms] -860.27 µs (-4.5%)
tracing 18.235 ms [18.055 ms, 18.414 ms] -983.781 µs (-5.1%)

Dacapo

Parameters

Baseline Candidate
baseline_or_candidate baseline candidate
git_branch master alejandro.gonzalez/APPSEC-61875-files-content-tomcat-netty
git_commit_date 1777379592 1777474755
git_commit_sha 9d73760 64dd1f5
release_version 1.62.0-SNAPSHOT~9d737609c4 1.62.0-SNAPSHOT~64dd1f56af
See matching parameters
Baseline Candidate
application biojava biojava
ci_job_date 1777476630 1777476630
ci_job_id 1642750942 1642750942
ci_pipeline_id 110464529 110464529
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-7uu3bses 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-7uu3bses 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~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,
Loading
  • baseline results
Variant Execution Time [CI 0.99] Δ no_agent
no_agent 14.836 s [14.836 s, 14.836 s] -
appsec 15.116 s [15.116 s, 15.116 s] 280.0 ms (1.9%)
iast 18.557 s [18.557 s, 18.557 s] 3.721 s (25.1%)
iast_GLOBAL 17.837 s [17.837 s, 17.837 s] 3.001 s (20.2%)
profiling 14.905 s [14.905 s, 14.905 s] 69.0 ms (0.5%)
tracing 14.925 s [14.925 s, 14.925 s] 89.0 ms (0.6%)
  • candidate results
Variant Execution Time [CI 0.99] Δ no_agent
no_agent 15.313 s [15.313 s, 15.313 s] -
appsec 14.964 s [14.964 s, 14.964 s] -349.0 ms (-2.3%)
iast 18.241 s [18.241 s, 18.241 s] 2.928 s (19.1%)
iast_GLOBAL 18.0 s [18.0 s, 18.0 s] 2.687 s (17.5%)
profiling 14.935 s [14.935 s, 14.935 s] -378.0 ms (-2.5%)
tracing 14.82 s [14.82 s, 14.82 s] -493.0 ms (-3.2%)
Execution time for tomcat
gantt
    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,
Loading
  • baseline results
Variant Execution Time [CI 0.99] Δ no_agent
no_agent 1.478 ms [1.467 ms, 1.49 ms] -
appsec 3.82 ms [3.596 ms, 4.044 ms] 2.342 ms (158.4%)
iast 2.269 ms [2.199 ms, 2.339 ms] 790.593 µs (53.5%)
iast_GLOBAL 2.314 ms [2.243 ms, 2.384 ms] 835.362 µs (56.5%)
profiling 2.106 ms [2.051 ms, 2.161 ms] 627.731 µs (42.5%)
tracing 2.093 ms [2.039 ms, 2.148 ms] 614.984 µs (41.6%)
  • candidate results
Variant Execution Time [CI 0.99] Δ no_agent
no_agent 1.485 ms [1.474 ms, 1.497 ms] -
appsec 3.818 ms [3.594 ms, 4.042 ms] 2.333 ms (157.1%)
iast 2.276 ms [2.206 ms, 2.346 ms] 790.753 µs (53.2%)
iast_GLOBAL 2.325 ms [2.254 ms, 2.395 ms] 839.65 µs (56.5%)
profiling 2.52 ms [2.361 ms, 2.679 ms] 1.035 ms (69.7%)
tracing 2.082 ms [2.028 ms, 2.136 ms] 596.267 µs (40.1%)

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

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

Base automatically changed from alejandro.gonzalez/APPSEC-61875-file-upload-content to master April 27, 2026 08:21
@jandro996 jandro996 force-pushed the alejandro.gonzalez/APPSEC-61875-files-content-tomcat-netty branch from 20e59a8 to 5632a09 Compare April 27, 2026 08:27
@jandro996
Copy link
Copy Markdown
Member Author

@codex review

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

@jandro996 jandro996 marked this pull request as ready for review April 27, 2026 10:51
@jandro996 jandro996 requested review from a team as code owners April 27, 2026 10:51
@jandro996 jandro996 requested review from daniel-romano-DD, manuel-alvarez-alvarez and sarahchen6 and removed request for a team April 27, 2026 10:51
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: 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".

@jandro996 jandro996 force-pushed the alejandro.gonzalez/APPSEC-61875-files-content-tomcat-netty branch from 09af9f3 to fe101c7 Compare April 28, 2026 13:14
Deduplicates the identical RequestBlockingAction dispatch pattern
that appeared three times in the Netty multipart advice.
@jandro996
Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector
Copy link
Copy Markdown

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

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

}
}
}
return exc;
Copy link
Copy Markdown
Member

@manuel-alvarez-alvarez manuel-alvarez-alvarez Apr 29, 2026

Choose a reason for hiding this comment

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

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.
@jandro996 jandro996 force-pushed the alejandro.gonzalez/APPSEC-61875-files-content-tomcat-netty branch from 4b6df53 to a40ec38 Compare April 29, 2026 14:03
@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: 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.
@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: 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.
@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: 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.
@jandro996
Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Already looking forward to the next diff.

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

2 participants