Skip to content

Add server.request.body.filenames support for Jetty#10988

Open
jandro996 wants to merge 45 commits intomasterfrom
alejandro.gonzalez/APPSEC-61873-3
Open

Add server.request.body.filenames support for Jetty#10988
jandro996 wants to merge 45 commits intomasterfrom
alejandro.gonzalez/APPSEC-61873-3

Conversation

@jandro996
Copy link
Copy Markdown
Member

@jandro996 jandro996 commented Mar 27, 2026

What Does This Do

Instruments Jetty's multipart request handling to fire the requestFilesFilenames AppSec gateway event, enabling WAF rules that act on uploaded file names.

Jetty parses multipart bodies through two code paths depending on how the application accesses the request:

  • getParameterMap()extractContentParameters() → internal getParts(MultiMap)
  • Direct getParts() / getPart(String) call from user code

Both paths are instrumented where they exist. Guards on internal state fields (_contentParameters, _multiParts, _multiPartInputStream) prevent double-firing when the same method is called more than once per request.

Module Status Coverage Why
jetty-appsec-7.0 unchanged ≤ 8.1.2 getParts() does not exist in Jetty 7.x
jetty-appsec-8.1.3 rewritten [8.1.3, 9.2.0.RC0) Replaced brittle ASM bytecode injection (GetPartsMethodVisitor) with clean exit advice on getParts() and getPart(String). In Jetty 8.x, getPart(String) calls _multiPartInputStream.getPart() directly without going through getParts(), so it requires its own advice to catch single-part uploads. Added PartHelper to parse Content-Disposition headers manually — Part.getSubmittedFileName() is Servlet 3.1+ and unavailable in Jetty 8.x (Servlet 3.0). The _multiPartInputStream == null guard in GetFilenamesAdvice prevents WAF callbacks from re-firing on repeated getParts() calls (the field is set on first parse and non-null on cached calls).
jetty-appsec-9.2 unchanged [9.2, 9.3) Already fires requestBodyProcessed; no filename support needed at this range
jetty-appsec-9.3 modified [9.3, 9.4.10) Narrowed from [9.3, 12) to [9.3, 9.4.10). Added GetFilenamesAdvice + GetFilenamesFromMultiPartAdvice. Double-fire guard uses _multiPartInputStream (present only in this range; replaced by _multiParts in 9.4.10). Added MultipartHelper using Part.getSubmittedFileName() (Servlet 3.1).
jetty-appsec-9.4 new [9.4.10, 11.0) Covers all javax.servlet versions from 9.4.10 onward: [9.4.10, 10.0) where _multiParts is MultiParts, and [10.0.0, 11.0) (Jetty 10.0.0–10.0.9 used _multiParts: MultiPartFormInputStream; 10.0.10+ switched to MultiParts). An OR-muzzle reference covers both field types. The _dispatcherType: Ljavax/servlet/DispatcherType; bytecode field discriminates against Jetty 11+ (which uses Ljakarta/servlet/DispatcherType;). Previously handled by jetty-appsec-9.3 via reflection.
jetty-appsec-11.0 new [11.0, 12.0) First Jetty version to use Jakarta Servlet (jakarta.servlet.http.Part). Identical structure to 9.4 but compiled against jakarta. The muzzle discriminator uses _dispatcherType: Ljakarta/servlet/DispatcherType; in Request.class bytecode — checking for jakarta.servlet.http.Part on the classpath was unreliable when both javax and jakarta were present, causing double instrumentation. Previously handled by jetty-appsec-9.3 via reflection.

Motivation

Part of APPSEC-61873server.request.body.filenames implementation across server frameworks.

Additional Notes

Depends on #10973 (merged)

Contributor Checklist

@jandro996 jandro996 added comp: asm waf Application Security Management (WAF) type: enhancement Enhancements and improvements labels Mar 27, 2026
@pr-commenter
Copy link
Copy Markdown

pr-commenter bot commented Mar 27, 2026

Benchmarks

Startup

Parameters

Baseline Candidate
baseline_or_candidate baseline candidate
git_branch master alejandro.gonzalez/APPSEC-61873-3
git_commit_date 1776642285 1776695291
git_commit_sha 081af53 1799f8b
release_version 1.62.0-SNAPSHOT~081af53226 1.61.0-SNAPSHOT~1799f8b303
See matching parameters
Baseline Candidate
application insecure-bank insecure-bank
ci_job_date 1776697159 1776697159
ci_job_id 1610983421 1610983421
ci_pipeline_id 108562767 108562767
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-tj4x57ty 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-tj4x57ty 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 63 metrics, 8 unstable metrics.

Startup time reports for petclinic
gantt
    title petclinic - global startup overhead: candidate=1.61.0-SNAPSHOT~1799f8b303, baseline=1.62.0-SNAPSHOT~081af53226

    dateFormat X
    axisFormat %s
section tracing
Agent [baseline] (1.058 s) : 0, 1057837
Total [baseline] (11.154 s) : 0, 11153535
Agent [candidate] (1.057 s) : 0, 1057473
Total [candidate] (11.088 s) : 0, 11088136
section appsec
Agent [baseline] (1.257 s) : 0, 1257407
Total [baseline] (11.119 s) : 0, 11119147
Agent [candidate] (1.259 s) : 0, 1258511
Total [candidate] (11.082 s) : 0, 11081537
section iast
Agent [baseline] (1.233 s) : 0, 1232906
Total [baseline] (11.322 s) : 0, 11322317
Agent [candidate] (1.228 s) : 0, 1228438
Total [candidate] (11.322 s) : 0, 11321693
section profiling
Agent [baseline] (1.185 s) : 0, 1184585
Total [baseline] (11.057 s) : 0, 11056842
Agent [candidate] (1.188 s) : 0, 1187531
Total [candidate] (11.073 s) : 0, 11073499
Loading
  • baseline results
Module Variant Duration Δ tracing
Agent tracing 1.058 s -
Agent appsec 1.257 s 199.57 ms (18.9%)
Agent iast 1.233 s 175.069 ms (16.5%)
Agent profiling 1.185 s 126.749 ms (12.0%)
Total tracing 11.154 s -
Total appsec 11.119 s -34.388 ms (-0.3%)
Total iast 11.322 s 168.783 ms (1.5%)
Total profiling 11.057 s -96.693 ms (-0.9%)
  • candidate results
Module Variant Duration Δ tracing
Agent tracing 1.057 s -
Agent appsec 1.259 s 201.038 ms (19.0%)
Agent iast 1.228 s 170.965 ms (16.2%)
Agent profiling 1.188 s 130.058 ms (12.3%)
Total tracing 11.088 s -
Total appsec 11.082 s -6.599 ms (-0.1%)
Total iast 11.322 s 233.557 ms (2.1%)
Total profiling 11.073 s -14.637 ms (-0.1%)
gantt
    title petclinic - break down per module: candidate=1.61.0-SNAPSHOT~1799f8b303, baseline=1.62.0-SNAPSHOT~081af53226

    dateFormat X
    axisFormat %s
section tracing
crashtracking [baseline] (1.234 ms) : 0, 1234
crashtracking [candidate] (1.222 ms) : 0, 1222
BytebuddyAgent [baseline] (633.432 ms) : 0, 633432
BytebuddyAgent [candidate] (632.044 ms) : 0, 632044
AgentMeter [baseline] (29.511 ms) : 0, 29511
AgentMeter [candidate] (29.722 ms) : 0, 29722
GlobalTracer [baseline] (249.049 ms) : 0, 249049
GlobalTracer [candidate] (249.599 ms) : 0, 249599
AppSec [baseline] (32.422 ms) : 0, 32422
AppSec [candidate] (32.544 ms) : 0, 32544
Debugger [baseline] (59.784 ms) : 0, 59784
Debugger [candidate] (60.17 ms) : 0, 60170
Remote Config [baseline] (588.946 µs) : 0, 589
Remote Config [candidate] (602.295 µs) : 0, 602
Telemetry [baseline] (8.024 ms) : 0, 8024
Telemetry [candidate] (8.068 ms) : 0, 8068
Flare Poller [baseline] (7.576 ms) : 0, 7576
Flare Poller [candidate] (7.388 ms) : 0, 7388
section appsec
crashtracking [baseline] (1.239 ms) : 0, 1239
crashtracking [candidate] (1.221 ms) : 0, 1221
BytebuddyAgent [baseline] (667.328 ms) : 0, 667328
BytebuddyAgent [candidate] (667.236 ms) : 0, 667236
AgentMeter [baseline] (12.258 ms) : 0, 12258
AgentMeter [candidate] (12.292 ms) : 0, 12292
GlobalTracer [baseline] (250.534 ms) : 0, 250534
GlobalTracer [candidate] (250.662 ms) : 0, 250662
IAST [baseline] (24.654 ms) : 0, 24654
IAST [candidate] (24.771 ms) : 0, 24771
AppSec [baseline] (185.935 ms) : 0, 185935
AppSec [candidate] (186.416 ms) : 0, 186416
Debugger [baseline] (66.348 ms) : 0, 66348
Debugger [candidate] (66.619 ms) : 0, 66619
Remote Config [baseline] (607.161 µs) : 0, 607
Remote Config [candidate] (623.887 µs) : 0, 624
Telemetry [baseline] (8.493 ms) : 0, 8493
Telemetry [candidate] (8.568 ms) : 0, 8568
Flare Poller [baseline] (3.565 ms) : 0, 3565
Flare Poller [candidate] (3.612 ms) : 0, 3612
section iast
crashtracking [baseline] (1.239 ms) : 0, 1239
crashtracking [candidate] (1.227 ms) : 0, 1227
BytebuddyAgent [baseline] (807.295 ms) : 0, 807295
BytebuddyAgent [candidate] (803.643 ms) : 0, 803643
AgentMeter [baseline] (11.682 ms) : 0, 11682
AgentMeter [candidate] (11.577 ms) : 0, 11577
GlobalTracer [baseline] (241.178 ms) : 0, 241178
GlobalTracer [candidate] (239.706 ms) : 0, 239706
IAST [baseline] (26.655 ms) : 0, 26655
IAST [candidate] (25.975 ms) : 0, 25975
AppSec [baseline] (29.468 ms) : 0, 29468
AppSec [candidate] (33.98 ms) : 0, 33980
Debugger [baseline] (65.795 ms) : 0, 65795
Debugger [candidate] (62.85 ms) : 0, 62850
Remote Config [baseline] (529.711 µs) : 0, 530
Remote Config [candidate] (537.904 µs) : 0, 538
Telemetry [baseline] (9.319 ms) : 0, 9319
Telemetry [candidate] (9.233 ms) : 0, 9233
Flare Poller [baseline] (3.567 ms) : 0, 3567
Flare Poller [candidate] (3.581 ms) : 0, 3581
section profiling
crashtracking [baseline] (1.172 ms) : 0, 1172
crashtracking [candidate] (1.182 ms) : 0, 1182
BytebuddyAgent [baseline] (691.127 ms) : 0, 691127
BytebuddyAgent [candidate] (693.682 ms) : 0, 693682
AgentMeter [baseline] (9.239 ms) : 0, 9239
AgentMeter [candidate] (8.984 ms) : 0, 8984
GlobalTracer [baseline] (207.179 ms) : 0, 207179
GlobalTracer [candidate] (207.428 ms) : 0, 207428
AppSec [baseline] (32.789 ms) : 0, 32789
AppSec [candidate] (32.849 ms) : 0, 32849
Debugger [baseline] (65.924 ms) : 0, 65924
Debugger [candidate] (65.944 ms) : 0, 65944
Remote Config [baseline] (587.481 µs) : 0, 587
Remote Config [candidate] (574.259 µs) : 0, 574
Telemetry [baseline] (7.838 ms) : 0, 7838
Telemetry [candidate] (7.827 ms) : 0, 7827
Flare Poller [baseline] (3.589 ms) : 0, 3589
Flare Poller [candidate] (3.555 ms) : 0, 3555
ProfilingAgent [baseline] (93.863 ms) : 0, 93863
ProfilingAgent [candidate] (94.108 ms) : 0, 94108
Profiling [baseline] (94.425 ms) : 0, 94425
Profiling [candidate] (94.671 ms) : 0, 94671
Loading
Startup time reports for insecure-bank
gantt
    title insecure-bank - global startup overhead: candidate=1.61.0-SNAPSHOT~1799f8b303, baseline=1.62.0-SNAPSHOT~081af53226

    dateFormat X
    axisFormat %s
section tracing
Agent [baseline] (1.068 s) : 0, 1068373
Total [baseline] (8.906 s) : 0, 8906185
Agent [candidate] (1.058 s) : 0, 1058219
Total [candidate] (8.849 s) : 0, 8848892
section iast
Agent [baseline] (1.233 s) : 0, 1232890
Total [baseline] (9.597 s) : 0, 9596656
Agent [candidate] (1.236 s) : 0, 1235865
Total [candidate] (9.568 s) : 0, 9567920
Loading
  • baseline results
Module Variant Duration Δ tracing
Agent tracing 1.068 s -
Agent iast 1.233 s 164.516 ms (15.4%)
Total tracing 8.906 s -
Total iast 9.597 s 690.471 ms (7.8%)
  • candidate results
Module Variant Duration Δ tracing
Agent tracing 1.058 s -
Agent iast 1.236 s 177.646 ms (16.8%)
Total tracing 8.849 s -
Total iast 9.568 s 719.028 ms (8.1%)
gantt
    title insecure-bank - break down per module: candidate=1.61.0-SNAPSHOT~1799f8b303, baseline=1.62.0-SNAPSHOT~081af53226

    dateFormat X
    axisFormat %s
section tracing
crashtracking [baseline] (1.259 ms) : 0, 1259
crashtracking [candidate] (1.242 ms) : 0, 1242
BytebuddyAgent [baseline] (638.984 ms) : 0, 638984
BytebuddyAgent [candidate] (634.688 ms) : 0, 634688
AgentMeter [baseline] (29.807 ms) : 0, 29807
AgentMeter [candidate] (29.458 ms) : 0, 29458
GlobalTracer [baseline] (250.549 ms) : 0, 250549
GlobalTracer [candidate] (249.127 ms) : 0, 249127
AppSec [baseline] (32.704 ms) : 0, 32704
AppSec [candidate] (32.265 ms) : 0, 32265
Debugger [baseline] (59.922 ms) : 0, 59922
Debugger [candidate] (59.334 ms) : 0, 59334
Remote Config [baseline] (596.205 µs) : 0, 596
Remote Config [candidate] (587.947 µs) : 0, 588
Telemetry [baseline] (8.1 ms) : 0, 8100
Telemetry [candidate] (9.435 ms) : 0, 9435
Flare Poller [baseline] (9.915 ms) : 0, 9915
Flare Poller [candidate] (5.967 ms) : 0, 5967
section iast
crashtracking [baseline] (1.245 ms) : 0, 1245
crashtracking [candidate] (1.235 ms) : 0, 1235
BytebuddyAgent [baseline] (807.13 ms) : 0, 807130
BytebuddyAgent [candidate] (809.695 ms) : 0, 809695
AgentMeter [baseline] (11.62 ms) : 0, 11620
AgentMeter [candidate] (11.686 ms) : 0, 11686
GlobalTracer [baseline] (240.471 ms) : 0, 240471
GlobalTracer [candidate] (240.639 ms) : 0, 240639
IAST [baseline] (25.955 ms) : 0, 25955
IAST [candidate] (26.037 ms) : 0, 26037
AppSec [baseline] (29.216 ms) : 0, 29216
AppSec [candidate] (31.391 ms) : 0, 31391
Debugger [baseline] (67.436 ms) : 0, 67436
Debugger [candidate] (65.31 ms) : 0, 65310
Remote Config [baseline] (539.71 µs) : 0, 540
Remote Config [candidate] (558.64 µs) : 0, 559
Telemetry [baseline] (9.41 ms) : 0, 9410
Telemetry [candidate] (9.309 ms) : 0, 9309
Flare Poller [baseline] (3.631 ms) : 0, 3631
Flare Poller [candidate] (3.571 ms) : 0, 3571
Loading

Load

Parameters

Baseline Candidate
baseline_or_candidate baseline candidate
git_branch master alejandro.gonzalez/APPSEC-61873-3
git_commit_date 1776642285 1776695291
git_commit_sha 081af53 1799f8b
release_version 1.62.0-SNAPSHOT~081af53226 1.61.0-SNAPSHOT~1799f8b303
See matching parameters
Baseline Candidate
application insecure-bank insecure-bank
ci_job_date 1776697641 1776697641
ci_job_id 1610983425 1610983425
ci_pipeline_id 108562767 108562767
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-1-fp4qwatu 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-1-fp4qwatu 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 2 performance improvements and 2 performance regressions! Performance is the same for 16 metrics, 16 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:insecure-bank:profiling:high_load worse
[+68.374µs; +205.044µs] or [+4.091%; +12.267%]
unstable
[+85.724µs; +1044.780µs] or [+1.811%; +22.068%]
unstable
[-460.671op/s; +27.358op/s] or [-20.793%; +1.235%]
1.808ms 5.300ms 1998.844op/s 1.671ms 4.734ms 2215.500op/s
scenario:load:insecure-bank:iast_GLOBAL:high_load worse
[+94.115µs; +212.948µs] or [+3.386%; +7.662%]
unsure
[+32.697µs; +462.508µs] or [+0.413%; +5.842%]
unstable
[-179.948op/s; +69.323op/s] or [-13.893%; +5.352%]
2.933ms 8.165ms 1239.938op/s 2.779ms 7.917ms 1295.250op/s
scenario:load:petclinic:no_agent:high_load better
[-1.788ms; -0.394ms] or [-9.534%; -2.102%]
unstable
[-2.903ms; +0.285ms] or [-9.396%; +0.921%]
unstable
[-12.247op/s; +41.497op/s] or [-5.042%; +17.086%]
17.661ms 29.584ms 257.500op/s 18.752ms 30.893ms 242.875op/s
scenario:load:petclinic:iast:high_load better
[-1.433ms; -0.667ms] or [-7.743%; -3.605%]
unsure
[-1.798ms; -0.553ms] or [-6.014%; -1.849%]
unstable
[-11.884op/s; +39.134op/s] or [-4.788%; +15.766%]
17.458ms 28.717ms 261.844op/s 18.508ms 29.892ms 248.219op/s
Request duration reports for petclinic
gantt
    title petclinic - request duration [CI 0.99] : candidate=1.61.0-SNAPSHOT~1799f8b303, baseline=1.62.0-SNAPSHOT~081af53226
    dateFormat X
    axisFormat %s
section baseline
no_agent (19.215 ms) : 19022, 19408
.   : milestone, 19215,
appsec (18.615 ms) : 18432, 18798
.   : milestone, 18615,
code_origins (17.731 ms) : 17553, 17909
.   : milestone, 17731,
iast (18.802 ms) : 18613, 18990
.   : milestone, 18802,
profiling (18.157 ms) : 17976, 18338
.   : milestone, 18157,
tracing (17.929 ms) : 17749, 18108
.   : milestone, 17929,
section candidate
no_agent (18.118 ms) : 17935, 18301
.   : milestone, 18118,
appsec (19.005 ms) : 18815, 19196
.   : milestone, 19005,
code_origins (17.832 ms) : 17655, 18008
.   : milestone, 17832,
iast (17.817 ms) : 17642, 17992
.   : milestone, 17817,
profiling (18.304 ms) : 18124, 18484
.   : milestone, 18304,
tracing (17.988 ms) : 17809, 18167
.   : milestone, 17988,
Loading
  • baseline results
Variant Request duration [CI 0.99] Δ no_agent
no_agent 19.215 ms [19.022 ms, 19.408 ms] -
appsec 18.615 ms [18.432 ms, 18.798 ms] -599.47 µs (-3.1%)
code_origins 17.731 ms [17.553 ms, 17.909 ms] -1.483 ms (-7.7%)
iast 18.802 ms [18.613 ms, 18.99 ms] -412.779 µs (-2.1%)
profiling 18.157 ms [17.976 ms, 18.338 ms] -1.058 ms (-5.5%)
tracing 17.929 ms [17.749 ms, 18.108 ms] -1.286 ms (-6.7%)
  • candidate results
Variant Request duration [CI 0.99] Δ no_agent
no_agent 18.118 ms [17.935 ms, 18.301 ms] -
appsec 19.005 ms [18.815 ms, 19.196 ms] 887.558 µs (4.9%)
code_origins 17.832 ms [17.655 ms, 18.008 ms] -286.011 µs (-1.6%)
iast 17.817 ms [17.642 ms, 17.992 ms] -300.962 µs (-1.7%)
profiling 18.304 ms [18.124 ms, 18.484 ms] 186.199 µs (1.0%)
tracing 17.988 ms [17.809 ms, 18.167 ms] -130.201 µs (-0.7%)
Request duration reports for insecure-bank
gantt
    title insecure-bank - request duration [CI 0.99] : candidate=1.61.0-SNAPSHOT~1799f8b303, baseline=1.62.0-SNAPSHOT~081af53226
    dateFormat X
    axisFormat %s
section baseline
no_agent (1.232 ms) : 1221, 1243
.   : milestone, 1232,
iast (3.393 ms) : 3344, 3443
.   : milestone, 3393,
iast_FULL (5.812 ms) : 5754, 5870
.   : milestone, 5812,
iast_GLOBAL (3.54 ms) : 3487, 3592
.   : milestone, 3540,
profiling (2.038 ms) : 2020, 2056
.   : milestone, 2038,
tracing (1.907 ms) : 1891, 1923
.   : milestone, 1907,
section candidate
no_agent (1.225 ms) : 1213, 1237
.   : milestone, 1225,
iast (3.347 ms) : 3298, 3395
.   : milestone, 3347,
iast_FULL (5.92 ms) : 5860, 5980
.   : milestone, 5920,
iast_GLOBAL (3.699 ms) : 3639, 3760
.   : milestone, 3699,
profiling (2.266 ms) : 2243, 2289
.   : milestone, 2266,
tracing (1.957 ms) : 1940, 1973
.   : milestone, 1957,
Loading
  • baseline results
Variant Request duration [CI 0.99] Δ no_agent
no_agent 1.232 ms [1.221 ms, 1.243 ms] -
iast 3.393 ms [3.344 ms, 3.443 ms] 2.161 ms (175.4%)
iast_FULL 5.812 ms [5.754 ms, 5.87 ms] 4.58 ms (371.8%)
iast_GLOBAL 3.54 ms [3.487 ms, 3.592 ms] 2.308 ms (187.3%)
profiling 2.038 ms [2.02 ms, 2.056 ms] 806.063 µs (65.4%)
tracing 1.907 ms [1.891 ms, 1.923 ms] 675.006 µs (54.8%)
  • candidate results
Variant Request duration [CI 0.99] Δ no_agent
no_agent 1.225 ms [1.213 ms, 1.237 ms] -
iast 3.347 ms [3.298 ms, 3.395 ms] 2.121 ms (173.1%)
iast_FULL 5.92 ms [5.86 ms, 5.98 ms] 4.695 ms (383.2%)
iast_GLOBAL 3.699 ms [3.639 ms, 3.76 ms] 2.474 ms (202.0%)
profiling 2.266 ms [2.243 ms, 2.289 ms] 1.041 ms (85.0%)
tracing 1.957 ms [1.94 ms, 1.973 ms] 731.695 µs (59.7%)

Dacapo

Parameters

Baseline Candidate
baseline_or_candidate baseline candidate
git_branch master alejandro.gonzalez/APPSEC-61873-3
git_commit_date 1776642285 1776695291
git_commit_sha 081af53 1799f8b
release_version 1.62.0-SNAPSHOT~081af53226 1.61.0-SNAPSHOT~1799f8b303
See matching parameters
Baseline Candidate
application biojava biojava
ci_job_date 1776697342 1776697342
ci_job_id 1610983429 1610983429
ci_pipeline_id 108562767 108562767
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-1-994i8g4x 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-1-994i8g4x 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 11 metrics, 1 unstable metrics.

Execution time for tomcat
gantt
    title tomcat - execution time [CI 0.99] : candidate=1.61.0-SNAPSHOT~1799f8b303, baseline=1.62.0-SNAPSHOT~081af53226
    dateFormat X
    axisFormat %s
section baseline
no_agent (1.491 ms) : 1480, 1503
.   : milestone, 1491,
appsec (3.777 ms) : 3559, 3996
.   : milestone, 3777,
iast (2.278 ms) : 2209, 2347
.   : milestone, 2278,
iast_GLOBAL (2.312 ms) : 2242, 2381
.   : milestone, 2312,
profiling (2.097 ms) : 2042, 2151
.   : milestone, 2097,
tracing (2.082 ms) : 2028, 2135
.   : milestone, 2082,
section candidate
no_agent (1.495 ms) : 1484, 1507
.   : milestone, 1495,
appsec (3.773 ms) : 3556, 3991
.   : milestone, 3773,
iast (2.28 ms) : 2211, 2350
.   : milestone, 2280,
iast_GLOBAL (2.321 ms) : 2251, 2391
.   : milestone, 2321,
profiling (2.104 ms) : 2049, 2159
.   : milestone, 2104,
tracing (2.095 ms) : 2041, 2149
.   : milestone, 2095,
Loading
  • baseline results
Variant Execution Time [CI 0.99] Δ no_agent
no_agent 1.491 ms [1.48 ms, 1.503 ms] -
appsec 3.777 ms [3.559 ms, 3.996 ms] 2.286 ms (153.3%)
iast 2.278 ms [2.209 ms, 2.347 ms] 786.636 µs (52.7%)
iast_GLOBAL 2.312 ms [2.242 ms, 2.381 ms] 820.245 µs (55.0%)
profiling 2.097 ms [2.042 ms, 2.151 ms] 605.502 µs (40.6%)
tracing 2.082 ms [2.028 ms, 2.135 ms] 590.502 µs (39.6%)
  • candidate results
Variant Execution Time [CI 0.99] Δ no_agent
no_agent 1.495 ms [1.484 ms, 1.507 ms] -
appsec 3.773 ms [3.556 ms, 3.991 ms] 2.278 ms (152.3%)
iast 2.28 ms [2.211 ms, 2.35 ms] 784.876 µs (52.5%)
iast_GLOBAL 2.321 ms [2.251 ms, 2.391 ms] 825.24 µs (55.2%)
profiling 2.104 ms [2.049 ms, 2.159 ms] 608.384 µs (40.7%)
tracing 2.095 ms [2.041 ms, 2.149 ms] 599.542 µs (40.1%)
Execution time for biojava
gantt
    title biojava - execution time [CI 0.99] : candidate=1.61.0-SNAPSHOT~1799f8b303, baseline=1.62.0-SNAPSHOT~081af53226
    dateFormat X
    axisFormat %s
section baseline
no_agent (15.585 s) : 15585000, 15585000
.   : milestone, 15585000,
appsec (14.419 s) : 14419000, 14419000
.   : milestone, 14419000,
iast (18.22 s) : 18220000, 18220000
.   : milestone, 18220000,
iast_GLOBAL (18.249 s) : 18249000, 18249000
.   : milestone, 18249000,
profiling (15.848 s) : 15848000, 15848000
.   : milestone, 15848000,
tracing (15.053 s) : 15053000, 15053000
.   : milestone, 15053000,
section candidate
no_agent (15.303 s) : 15303000, 15303000
.   : milestone, 15303000,
appsec (14.651 s) : 14651000, 14651000
.   : milestone, 14651000,
iast (18.299 s) : 18299000, 18299000
.   : milestone, 18299000,
iast_GLOBAL (18.209 s) : 18209000, 18209000
.   : milestone, 18209000,
profiling (14.797 s) : 14797000, 14797000
.   : milestone, 14797000,
tracing (14.839 s) : 14839000, 14839000
.   : milestone, 14839000,
Loading
  • baseline results
Variant Execution Time [CI 0.99] Δ no_agent
no_agent 15.585 s [15.585 s, 15.585 s] -
appsec 14.419 s [14.419 s, 14.419 s] -1.166 s (-7.5%)
iast 18.22 s [18.22 s, 18.22 s] 2.635 s (16.9%)
iast_GLOBAL 18.249 s [18.249 s, 18.249 s] 2.664 s (17.1%)
profiling 15.848 s [15.848 s, 15.848 s] 263.0 ms (1.7%)
tracing 15.053 s [15.053 s, 15.053 s] -532.0 ms (-3.4%)
  • candidate results
Variant Execution Time [CI 0.99] Δ no_agent
no_agent 15.303 s [15.303 s, 15.303 s] -
appsec 14.651 s [14.651 s, 14.651 s] -652.0 ms (-4.3%)
iast 18.299 s [18.299 s, 18.299 s] 2.996 s (19.6%)
iast_GLOBAL 18.209 s [18.209 s, 18.209 s] 2.906 s (19.0%)
profiling 14.797 s [14.797 s, 14.797 s] -506.0 ms (-3.3%)
tracing 14.839 s [14.839 s, 14.839 s] -464.0 ms (-3.0%)

@jandro996 jandro996 force-pushed the alejandro.gonzalez/APPSEC-61873-3 branch from e3d4073 to e2d5ed0 Compare April 6, 2026 08:02
Add GetFilenamesAdvice to all three Jetty AppSec modules to collect
uploaded file names from multipart requests and fire the
requestFilesFilenames() IG callback:

- jetty-appsec-8.1.3: intercepts getParts() return value; includes
  Content-Disposition header fallback for Servlet 3.0 (Jetty 9.0)
  where getSubmittedFileName() is not available
- jetty-appsec-9.2: intercepts no-arg getParts() for Servlet 3.1+
- jetty-appsec-9.3: same, applies to Jetty 9.3, 10, 11

Enable testBodyFilenames() in Jetty 9.x, 10 and 11 server tests.
@jandro996 jandro996 force-pushed the alejandro.gonzalez/APPSEC-61873-3 branch from f2998c3 to 629f074 Compare April 6, 2026 10:50
@jandro996 jandro996 marked this pull request as ready for review April 6, 2026 13:08
@jandro996 jandro996 requested a review from a team as a code owner April 6, 2026 13:08
}
}
// Fallback: parse filename from Content-Disposition header (Servlet 3.0)
if (name == null) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Shouldn't this be outside of the main parts loop?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed. Restructured into two separate loops chosen once before iteration: if getSubmittedFileName != null (Servlet 3.1+) iterate using that method; otherwise iterate parsing the Content-Disposition header (Servlet 3.0 fallback). No per-part branching inside the loop.

transformer.applyAdvice(
named("extractContentParameters").and(takesArguments(0)).or(named("getParts")),
getClass().getName() + "$ExtractContentParametersAdvice");
transformer.applyAdvice(named("getParts"), getClass().getName() + "$GetFilenamesAdvice");
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Same as before

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed. GetFilenamesAdvice now has a call-depth guard (CallDepthThreadLocalMap with Collection.class) to avoid double-firing when getParts() internally calls getParts(MultiMap)

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: c732823549

ℹ️ 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-61873-3 branch 2 times, most recently from ecf65c5 to eae08aa Compare April 6, 2026 14:13
…MultiMap) path

- jetty-appsec-9.3: add call-depth guard (Collection.class) to GetFilenamesAdvice
  to prevent double callback invocation when getParts() calls getParts(MultiMap) internally
- jetty-appsec-9.2: extend GetFilenamesAdvice matcher to all getParts overloads
  (not just no-arg) to cover getParameter*()/getParameterMap() code paths,
  guarded with same call-depth mechanism to avoid double-firing
@jandro996 jandro996 force-pushed the alejandro.gonzalez/APPSEC-61873-3 branch 2 times, most recently from 3ab9ff7 to 77ec572 Compare April 7, 2026 07:33
@jandro996 jandro996 enabled auto-merge April 7, 2026 08:52
@jandro996 jandro996 force-pushed the alejandro.gonzalez/APPSEC-61873-3 branch from 2e72584 to d37e03e Compare April 7, 2026 09:23
@jandro996 jandro996 disabled auto-merge April 7, 2026 09:42
@jandro996 jandro996 marked this pull request as draft April 7, 2026 09:48
@jandro996 jandro996 force-pushed the alejandro.gonzalez/APPSEC-61873-3 branch from d37e03e to d8a92f8 Compare April 7, 2026 09:52
- Add BODY_MULTIPART_REPEATED case to TestServlet3 (javax) so Jetty 9.x/10.x
  test modules can exercise the repeated getParts() scenario
- Enable testBodyFilenamesCalledOnce() for Jetty 9.0, 9.0.4, 9.3, 9.4.21, and 10.0
…vice path

- New BODY_MULTIPART_COMBINED endpoint: calls getParameterMap() first (triggers
  GetFilenamesFromMultiPartAdvice via extractContentParameters -> getParts(MultiMap)),
  then getParts() explicitly (GetFilenamesAdvice must not double-fire since
  _contentParameters is already set)
- New test 'file upload filenames called once via parameter map' verifies the
  callback fires exactly once across both advice paths
- Enabled in Jetty 9.0, 9.0.4, 9.3, 9.4.21, 10.0 and 11.0
…eplaces _contentParameters as the getParts() cache

In Jetty 9.3, getParts(MultiMap) sets _contentParameters, so the map==null guard prevents
re-firing on repeated getParts() calls. In Jetty 9.4+, getParts() delegates to getParts(null)
and caches the result in _multiParts instead, leaving _contentParameters null on every call.
Add _multiParts==null as an additional guard (optional=true handles Jetty 9.3 where the
field does not exist).
…ith exit-advice

Replace the brittle GetPartsMethodVisitor ASM bytecode injection (intercepting
MultiMap.add() calls inside getParts()) with a clean ByteBuddy exit-advice approach:

- Remove ParameterCollector, GetPartsAdvice, GetPartsVisitorWrapper, RequestClassVisitor,
  and GetPartsMethodVisitor; drop HasTypeAdvice from the instrumentation module.
- Add PartHelper with extractFormFields() (reads InputStream per part) and
  extractFilenames() (parses Content-Disposition manually, since
  Part.getSubmittedFileName() is Servlet 3.1+ and not available in Jetty 8.x).
- Add GetFilenamesAdvice (@RequiresRequestContext / @ActiveRequestContext) on
  getParts():Collection that fires requestBodyProcessed() with form fields and
  requestFilesFilenames() with upload filenames. Uses CallDepthThreadLocalMap to
  guard against reentrant calls.
- Jetty8LatestDepForkedTest: set testBodyFilenamesCalledOnce() and
  testBodyFilenamesCalledOnceCombined() to false because Jetty 8.x has no
  _multiParts / _contentParameters field guards to suppress duplicate firings.
@jandro996 jandro996 marked this pull request as ready for review April 20, 2026 08:13
@jandro996 jandro996 requested review from a team as code owners April 20, 2026 08:13
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: e43466fc5b

ℹ️ 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 draft April 20, 2026 08:29
…utStream

- jetty-appsec-9.4: extend muzzle to also cover Jetty 10.0.0–10.0.9, which were
  previously a gap. In those versions _multiParts is typed MultiPartFormInputStream
  (not MultiParts); the primary Reference spec matches 9.4.10+ and 10.0.10+, and an
  OrReference alternative matches 10.0.0–10.0.9. The GetFilenamesAdvice already uses
  typing=DYNAMIC so no advice changes are needed.

- jetty-appsec-8.1.3 PartHelper: wrap part.getInputStream() in try-with-resources to
  avoid leaking file descriptors on file-backed multipart form fields.
@jandro996 jandro996 marked this pull request as ready for review April 20, 2026 08:55
@jandro996
Copy link
Copy Markdown
Member Author

@codex review

@jandro996 jandro996 marked this pull request as draft April 20, 2026 09:01
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: 1f2e2b3998

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

Splitting the header on ';' naively truncated filenames that contain
semicolons inside a quoted value, e.g. filename="shell;evil.php" would
produce "shell" instead of the full name. Replace the split() loop with
a quote-aware state-machine parser that skips semicolons inside quoted
strings and handles backslash-escaped characters. Add test cases for
semicolons in filenames, escaped quotes, and filename appearing before
other parameters.
@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: 0ce4bf1084

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

…c-11.0

Replace the JAKARTA_PART_REFERENCE classpath check with a _dispatcherType
field descriptor check on Request.class bytecode, mirroring the approach
already used by jetty-appsec-9.4. The classpath check passes on any
Jetty 9.4/10 app that has jakarta.servlet-api as a dependency, causing
double-instrumentation of extractContentParameters. The bytecode check is
authoritative: in Jetty 11+ Request.class carries _dispatcherType as
Ljakarta/servlet/DispatcherType;, while 9.4/10 carry the javax descriptor.
@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: 74948a75d6

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

…uploads

In Jetty 8.x, getPart(String name) calls _multiPartInputStream.getPart(String)
directly without delegating to getParts(). Applications that retrieve only one
file via getPart() without ever calling getParts() would have their filename
event missed. Add GetPartAdvice to cover this path.

The charset fix (AI comment 2) was investigated and is not applicable: HTML5
form submissions always use UTF-8 and browsers never include charset= on
individual part Content-Type headers, so the existing hardcoded UTF-8 is correct.
@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: 1508fef49c

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

…ilename tests in async suite

1. Add _multiPartInputStream == null guard to GetFilenamesAdvice.before() so that
   repeated getParts() calls on the same request (which Jetty caches) do not
   re-fire requestFilesFilenames/requestBodyProcessed WAF callbacks. The field is
   null before the first multipart parse and non-null on all subsequent cached
   calls, matching the pattern used in the 9.4/11.0 advice (_multiParts guard).

2. JettyAsyncHandlerTest already disabled testBodyFilenames() but neglected to
   disable testBodyFilenamesCalledOnce() and testBodyFilenamesCalledOnceCombined(),
   which are now enabled in the Jetty11Test parent. Override both to false in the
   async handler suite to prevent spurious test failures.
@jandro996
Copy link
Copy Markdown
Member Author

@codex review

@jandro996 jandro996 marked this pull request as ready for review April 20, 2026 13:36
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: bece33644c

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

…elper

filenameFromPart() was returning null for both 'no filename parameter' and
'filename=""', causing extractFormFields() to buffer the full body of file
inputs submitted with no file chosen (filename=""). An empty <input type=file>
is still a file part, not a form field. Return "" instead of null so that
callers using != null correctly skip those parts without reading their content.

Update tests to assert "" for empty-filename cases and add regression tests
for extractFormFields/extractFilenames with empty-filename parts.

Note: the second AI comment about getPart(String) double-firing was not
implemented. The bytecode shows the internal call is to
MultiPartInputStream.getParts() (not Request.getParts()), so GetFilenamesAdvice
(which instruments Request.getParts()) is never triggered during a getPart()
call. There is no double-firing.
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