Skip to content

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

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

Add server.request.body.filenames support for Jetty#10988
jandro996 wants to merge 46 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 1776763381
git_commit_sha 081af53 ce166be
release_version 1.62.0-SNAPSHOT~081af53226 1.61.0-SNAPSHOT~ce166bef0a
See matching parameters
Baseline Candidate
application insecure-bank insecure-bank
ci_job_date 1776765210 1776765210
ci_job_id 1614290057 1614290057
ci_pipeline_id 108733530 108733530
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-z2b206cj 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-z2b206cj 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 1 performance improvements and 0 performance regressions! Performance is the same for 61 metrics, 9 unstable metrics.

scenario Δ mean execution_time candidate mean execution_time baseline mean execution_time
scenario:startup:petclinic:profiling:AgentMeter better
[-381.131µs; -198.294µs] or [-4.128%; -2.148%]
8.944ms 9.233ms
Startup time reports for petclinic
gantt
    title petclinic - global startup overhead: candidate=1.61.0-SNAPSHOT~ce166bef0a, baseline=1.62.0-SNAPSHOT~081af53226

    dateFormat X
    axisFormat %s
section tracing
Agent [baseline] (1.064 s) : 0, 1063718
Total [baseline] (11.035 s) : 0, 11035363
Agent [candidate] (1.06 s) : 0, 1059665
Total [candidate] (11.118 s) : 0, 11118047
section appsec
Agent [baseline] (1.253 s) : 0, 1252620
Total [baseline] (11.169 s) : 0, 11168943
Agent [candidate] (1.256 s) : 0, 1255729
Total [candidate] (11.088 s) : 0, 11088142
section iast
Agent [baseline] (1.228 s) : 0, 1228265
Total [baseline] (11.314 s) : 0, 11313825
Agent [candidate] (1.236 s) : 0, 1235974
Total [candidate] (11.332 s) : 0, 11332234
section profiling
Agent [baseline] (1.187 s) : 0, 1186558
Total [baseline] (11.022 s) : 0, 11022199
Agent [candidate] (1.188 s) : 0, 1188015
Total [candidate] (11.053 s) : 0, 11053247
Loading
  • baseline results
Module Variant Duration Δ tracing
Agent tracing 1.064 s -
Agent appsec 1.253 s 188.902 ms (17.8%)
Agent iast 1.228 s 164.548 ms (15.5%)
Agent profiling 1.187 s 122.84 ms (11.5%)
Total tracing 11.035 s -
Total appsec 11.169 s 133.58 ms (1.2%)
Total iast 11.314 s 278.461 ms (2.5%)
Total profiling 11.022 s -13.164 ms (-0.1%)
  • candidate results
Module Variant Duration Δ tracing
Agent tracing 1.06 s -
Agent appsec 1.256 s 196.064 ms (18.5%)
Agent iast 1.236 s 176.309 ms (16.6%)
Agent profiling 1.188 s 128.35 ms (12.1%)
Total tracing 11.118 s -
Total appsec 11.088 s -29.905 ms (-0.3%)
Total iast 11.332 s 214.187 ms (1.9%)
Total profiling 11.053 s -64.8 ms (-0.6%)
gantt
    title petclinic - break down per module: candidate=1.61.0-SNAPSHOT~ce166bef0a, baseline=1.62.0-SNAPSHOT~081af53226

    dateFormat X
    axisFormat %s
section tracing
crashtracking [baseline] (1.248 ms) : 0, 1248
crashtracking [candidate] (1.231 ms) : 0, 1231
BytebuddyAgent [baseline] (634.72 ms) : 0, 634720
BytebuddyAgent [candidate] (633.648 ms) : 0, 633648
AgentMeter [baseline] (29.646 ms) : 0, 29646
AgentMeter [candidate] (29.46 ms) : 0, 29460
GlobalTracer [baseline] (250.113 ms) : 0, 250113
GlobalTracer [candidate] (249.016 ms) : 0, 249016
AppSec [baseline] (32.522 ms) : 0, 32522
AppSec [candidate] (32.38 ms) : 0, 32380
Debugger [baseline] (60.266 ms) : 0, 60266
Debugger [candidate] (59.923 ms) : 0, 59923
Remote Config [baseline] (597.373 µs) : 0, 597
Remote Config [candidate] (588.654 µs) : 0, 589
Telemetry [baseline] (8.032 ms) : 0, 8032
Telemetry [candidate] (8.728 ms) : 0, 8728
Flare Poller [baseline] (10.251 ms) : 0, 10251
Flare Poller [candidate] (8.363 ms) : 0, 8363
section appsec
crashtracking [baseline] (1.231 ms) : 0, 1231
crashtracking [candidate] (1.221 ms) : 0, 1221
BytebuddyAgent [baseline] (662.94 ms) : 0, 662940
BytebuddyAgent [candidate] (666.11 ms) : 0, 666110
AgentMeter [baseline] (12.341 ms) : 0, 12341
AgentMeter [candidate] (12.255 ms) : 0, 12255
GlobalTracer [baseline] (250.201 ms) : 0, 250201
GlobalTracer [candidate] (249.245 ms) : 0, 249245
AppSec [baseline] (186.158 ms) : 0, 186158
AppSec [candidate] (186.47 ms) : 0, 186470
Debugger [baseline] (65.99 ms) : 0, 65990
Debugger [candidate] (66.651 ms) : 0, 66651
Remote Config [baseline] (609.889 µs) : 0, 610
Remote Config [candidate] (619.361 µs) : 0, 619
Telemetry [baseline] (8.472 ms) : 0, 8472
Telemetry [candidate] (8.579 ms) : 0, 8579
Flare Poller [baseline] (3.604 ms) : 0, 3604
Flare Poller [candidate] (3.565 ms) : 0, 3565
IAST [baseline] (24.612 ms) : 0, 24612
IAST [candidate] (24.548 ms) : 0, 24548
section iast
crashtracking [baseline] (1.235 ms) : 0, 1235
crashtracking [candidate] (1.234 ms) : 0, 1234
BytebuddyAgent [baseline] (803.35 ms) : 0, 803350
BytebuddyAgent [candidate] (809.129 ms) : 0, 809129
AgentMeter [baseline] (11.656 ms) : 0, 11656
AgentMeter [candidate] (11.713 ms) : 0, 11713
GlobalTracer [baseline] (239.801 ms) : 0, 239801
GlobalTracer [candidate] (240.875 ms) : 0, 240875
AppSec [baseline] (29.681 ms) : 0, 29681
AppSec [candidate] (29.118 ms) : 0, 29118
Debugger [baseline] (66.239 ms) : 0, 66239
Debugger [candidate] (67.967 ms) : 0, 67967
Remote Config [baseline] (531.873 µs) : 0, 532
Remote Config [candidate] (544.454 µs) : 0, 544
Telemetry [baseline] (9.279 ms) : 0, 9279
Telemetry [candidate] (9.373 ms) : 0, 9373
Flare Poller [baseline] (3.563 ms) : 0, 3563
Flare Poller [candidate] (3.626 ms) : 0, 3626
IAST [baseline] (26.636 ms) : 0, 26636
IAST [candidate] (25.963 ms) : 0, 25963
section profiling
ProfilingAgent [baseline] (94.037 ms) : 0, 94037
ProfilingAgent [candidate] (93.972 ms) : 0, 93972
crashtracking [baseline] (1.181 ms) : 0, 1181
crashtracking [candidate] (1.19 ms) : 0, 1190
BytebuddyAgent [baseline] (692.537 ms) : 0, 692537
BytebuddyAgent [candidate] (694.286 ms) : 0, 694286
AgentMeter [baseline] (9.233 ms) : 0, 9233
AgentMeter [candidate] (8.944 ms) : 0, 8944
GlobalTracer [baseline] (207.311 ms) : 0, 207311
GlobalTracer [candidate] (207.612 ms) : 0, 207612
AppSec [baseline] (32.843 ms) : 0, 32843
AppSec [candidate] (32.857 ms) : 0, 32857
Debugger [baseline] (65.913 ms) : 0, 65913
Debugger [candidate] (65.609 ms) : 0, 65609
Remote Config [baseline] (595.224 µs) : 0, 595
Remote Config [candidate] (568.982 µs) : 0, 569
Telemetry [baseline] (7.769 ms) : 0, 7769
Telemetry [candidate] (7.801 ms) : 0, 7801
Flare Poller [baseline] (3.516 ms) : 0, 3516
Flare Poller [candidate] (3.575 ms) : 0, 3575
Profiling [baseline] (94.611 ms) : 0, 94611
Profiling [candidate] (94.552 ms) : 0, 94552
Loading
Startup time reports for insecure-bank
gantt
    title insecure-bank - global startup overhead: candidate=1.61.0-SNAPSHOT~ce166bef0a, baseline=1.62.0-SNAPSHOT~081af53226

    dateFormat X
    axisFormat %s
section tracing
Agent [baseline] (1.059 s) : 0, 1059176
Total [baseline] (8.871 s) : 0, 8870757
Agent [candidate] (1.064 s) : 0, 1063727
Total [candidate] (8.852 s) : 0, 8852037
section iast
Agent [baseline] (1.226 s) : 0, 1226259
Total [baseline] (9.584 s) : 0, 9583563
Agent [candidate] (1.226 s) : 0, 1226029
Total [candidate] (9.571 s) : 0, 9570616
Loading
  • baseline results
Module Variant Duration Δ tracing
Agent tracing 1.059 s -
Agent iast 1.226 s 167.083 ms (15.8%)
Total tracing 8.871 s -
Total iast 9.584 s 712.805 ms (8.0%)
  • candidate results
Module Variant Duration Δ tracing
Agent tracing 1.064 s -
Agent iast 1.226 s 162.302 ms (15.3%)
Total tracing 8.852 s -
Total iast 9.571 s 718.58 ms (8.1%)
gantt
    title insecure-bank - break down per module: candidate=1.61.0-SNAPSHOT~ce166bef0a, baseline=1.62.0-SNAPSHOT~081af53226

    dateFormat X
    axisFormat %s
section tracing
crashtracking [baseline] (1.241 ms) : 0, 1241
crashtracking [candidate] (1.234 ms) : 0, 1234
BytebuddyAgent [baseline] (634.504 ms) : 0, 634504
BytebuddyAgent [candidate] (638.501 ms) : 0, 638501
AgentMeter [baseline] (29.624 ms) : 0, 29624
AgentMeter [candidate] (29.798 ms) : 0, 29798
GlobalTracer [baseline] (249.432 ms) : 0, 249432
GlobalTracer [candidate] (250.614 ms) : 0, 250614
AppSec [baseline] (32.517 ms) : 0, 32517
AppSec [candidate] (32.559 ms) : 0, 32559
Debugger [baseline] (59.457 ms) : 0, 59457
Debugger [candidate] (59.5 ms) : 0, 59500
Remote Config [baseline] (617.995 µs) : 0, 618
Remote Config [candidate] (594.939 µs) : 0, 595
Telemetry [baseline] (7.998 ms) : 0, 7998
Telemetry [candidate] (8.027 ms) : 0, 8027
Flare Poller [baseline] (7.408 ms) : 0, 7408
Flare Poller [candidate] (6.516 ms) : 0, 6516
section iast
crashtracking [baseline] (1.239 ms) : 0, 1239
crashtracking [candidate] (1.227 ms) : 0, 1227
BytebuddyAgent [baseline] (802.978 ms) : 0, 802978
BytebuddyAgent [candidate] (803.065 ms) : 0, 803065
AgentMeter [baseline] (11.598 ms) : 0, 11598
AgentMeter [candidate] (11.624 ms) : 0, 11624
GlobalTracer [baseline] (239.459 ms) : 0, 239459
GlobalTracer [candidate] (239.548 ms) : 0, 239548
AppSec [baseline] (33.639 ms) : 0, 33639
AppSec [candidate] (32.053 ms) : 0, 32053
Debugger [baseline] (61.908 ms) : 0, 61908
Debugger [candidate] (63.25 ms) : 0, 63250
Remote Config [baseline] (536.338 µs) : 0, 536
Remote Config [candidate] (547.122 µs) : 0, 547
Telemetry [baseline] (9.295 ms) : 0, 9295
Telemetry [candidate] (9.171 ms) : 0, 9171
Flare Poller [baseline] (3.542 ms) : 0, 3542
Flare Poller [candidate] (3.53 ms) : 0, 3530
IAST [baseline] (25.878 ms) : 0, 25878
IAST [candidate] (25.855 ms) : 0, 25855
Loading

Load

Parameters

Baseline Candidate
baseline_or_candidate baseline candidate
git_branch master alejandro.gonzalez/APPSEC-61873-3
git_commit_date 1776642285 1776763381
git_commit_sha 081af53 ce166be
release_version 1.62.0-SNAPSHOT~081af53226 1.61.0-SNAPSHOT~ce166bef0a
See matching parameters
Baseline Candidate
application insecure-bank insecure-bank
ci_job_date 1776765610 1776765610
ci_job_id 1614290061 1614290061
ci_pipeline_id 108733530 108733530
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-v52f4pfq 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-v52f4pfq 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 1 performance regressions! Performance is the same for 17 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:petclinic:iast:high_load better
[-1.448ms; -0.847ms] or [-7.666%; -4.485%]
better
[-2.207ms; -0.671ms] or [-7.231%; -2.197%]
unstable
[-9.584op/s; +41.146op/s] or [-3.954%; +16.976%]
17.738ms 29.089ms 258.156op/s 18.885ms 30.528ms 242.375op/s
scenario:load:petclinic:profiling:high_load worse
[+0.755ms; +1.724ms] or [+4.178%; +9.545%]
unsure
[+129.197µs; +1617.912µs] or [+0.435%; +5.445%]
unstable
[-39.242op/s; +11.805op/s] or [-15.511%; +4.666%]
19.299ms 30.587ms 239.281op/s 18.060ms 29.713ms 253.000op/s
Request duration reports for insecure-bank
gantt
    title insecure-bank - request duration [CI 0.99] : candidate=1.61.0-SNAPSHOT~ce166bef0a, baseline=1.62.0-SNAPSHOT~081af53226
    dateFormat X
    axisFormat %s
section baseline
no_agent (1.256 ms) : 1243, 1268
.   : milestone, 1256,
iast (3.258 ms) : 3213, 3303
.   : milestone, 3258,
iast_FULL (6.005 ms) : 5944, 6067
.   : milestone, 6005,
iast_GLOBAL (3.62 ms) : 3563, 3678
.   : milestone, 3620,
profiling (2.327 ms) : 2306, 2349
.   : milestone, 2327,
tracing (1.939 ms) : 1923, 1955
.   : milestone, 1939,
section candidate
no_agent (1.245 ms) : 1233, 1258
.   : milestone, 1245,
iast (3.38 ms) : 3330, 3431
.   : milestone, 3380,
iast_FULL (6.13 ms) : 6067, 6193
.   : milestone, 6130,
iast_GLOBAL (3.706 ms) : 3644, 3768
.   : milestone, 3706,
profiling (2.184 ms) : 2163, 2205
.   : milestone, 2184,
tracing (1.868 ms) : 1853, 1883
.   : milestone, 1868,
Loading
  • baseline results
Variant Request duration [CI 0.99] Δ no_agent
no_agent 1.256 ms [1.243 ms, 1.268 ms] -
iast 3.258 ms [3.213 ms, 3.303 ms] 2.002 ms (159.4%)
iast_FULL 6.005 ms [5.944 ms, 6.067 ms] 4.749 ms (378.2%)
iast_GLOBAL 3.62 ms [3.563 ms, 3.678 ms] 2.364 ms (188.3%)
profiling 2.327 ms [2.306 ms, 2.349 ms] 1.071 ms (85.3%)
tracing 1.939 ms [1.923 ms, 1.955 ms] 682.93 µs (54.4%)
  • candidate results
Variant Request duration [CI 0.99] Δ no_agent
no_agent 1.245 ms [1.233 ms, 1.258 ms] -
iast 3.38 ms [3.33 ms, 3.431 ms] 2.135 ms (171.5%)
iast_FULL 6.13 ms [6.067 ms, 6.193 ms] 4.885 ms (392.3%)
iast_GLOBAL 3.706 ms [3.644 ms, 3.768 ms] 2.461 ms (197.6%)
profiling 2.184 ms [2.163 ms, 2.205 ms] 939.146 µs (75.4%)
tracing 1.868 ms [1.853 ms, 1.883 ms] 622.9 µs (50.0%)
Request duration reports for petclinic
gantt
    title petclinic - request duration [CI 0.99] : candidate=1.61.0-SNAPSHOT~ce166bef0a, baseline=1.62.0-SNAPSHOT~081af53226
    dateFormat X
    axisFormat %s
section baseline
no_agent (19.01 ms) : 18817, 19204
.   : milestone, 19010,
appsec (18.604 ms) : 18414, 18794
.   : milestone, 18604,
code_origins (18.046 ms) : 17867, 18225
.   : milestone, 18046,
iast (19.26 ms) : 19061, 19458
.   : milestone, 19260,
profiling (18.44 ms) : 18255, 18626
.   : milestone, 18440,
tracing (17.938 ms) : 17766, 18111
.   : milestone, 17938,
section candidate
no_agent (19.647 ms) : 19443, 19850
.   : milestone, 19647,
appsec (18.467 ms) : 18285, 18649
.   : milestone, 18467,
code_origins (17.904 ms) : 17725, 18082
.   : milestone, 17904,
iast (18.075 ms) : 17895, 18254
.   : milestone, 18075,
profiling (19.514 ms) : 19319, 19710
.   : milestone, 19514,
tracing (17.548 ms) : 17377, 17720
.   : milestone, 17548,
Loading
  • baseline results
Variant Request duration [CI 0.99] Δ no_agent
no_agent 19.01 ms [18.817 ms, 19.204 ms] -
appsec 18.604 ms [18.414 ms, 18.794 ms] -406.251 µs (-2.1%)
code_origins 18.046 ms [17.867 ms, 18.225 ms] -964.244 µs (-5.1%)
iast 19.26 ms [19.061 ms, 19.458 ms] 249.228 µs (1.3%)
profiling 18.44 ms [18.255 ms, 18.626 ms] -569.934 µs (-3.0%)
tracing 17.938 ms [17.766 ms, 18.111 ms] -1.072 ms (-5.6%)
  • candidate results
Variant Request duration [CI 0.99] Δ no_agent
no_agent 19.647 ms [19.443 ms, 19.85 ms] -
appsec 18.467 ms [18.285 ms, 18.649 ms] -1.18 ms (-6.0%)
code_origins 17.904 ms [17.725 ms, 18.082 ms] -1.743 ms (-8.9%)
iast 18.075 ms [17.895 ms, 18.254 ms] -1.572 ms (-8.0%)
profiling 19.514 ms [19.319 ms, 19.71 ms] -132.305 µs (-0.7%)
tracing 17.548 ms [17.377 ms, 17.72 ms] -2.099 ms (-10.7%)

Dacapo

Parameters

Baseline Candidate
baseline_or_candidate baseline candidate
git_branch master alejandro.gonzalez/APPSEC-61873-3
git_commit_date 1776642285 1776763381
git_commit_sha 081af53 ce166be
release_version 1.62.0-SNAPSHOT~081af53226 1.61.0-SNAPSHOT~ce166bef0a
See matching parameters
Baseline Candidate
application biojava biojava
ci_job_date 1776765395 1776765395
ci_job_id 1614290066 1614290066
ci_pipeline_id 108733530 108733530
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-0eazryls 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-0eazryls 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 1 performance improvements and 0 performance regressions! Performance is the same for 11 metrics, 0 unstable metrics.

scenario Δ mean execution_time candidate mean execution_time baseline mean execution_time
scenario:dacapo:tomcat:appsec better
[-1.401ms; -1.056ms] or [-36.893%; -27.819%]
2.568ms 3.797ms
Execution time for biojava
gantt
    title biojava - execution time [CI 0.99] : candidate=1.61.0-SNAPSHOT~ce166bef0a, baseline=1.62.0-SNAPSHOT~081af53226
    dateFormat X
    axisFormat %s
section baseline
no_agent (15.715 s) : 15715000, 15715000
.   : milestone, 15715000,
appsec (14.829 s) : 14829000, 14829000
.   : milestone, 14829000,
iast (18.679 s) : 18679000, 18679000
.   : milestone, 18679000,
iast_GLOBAL (18.498 s) : 18498000, 18498000
.   : milestone, 18498000,
profiling (15.736 s) : 15736000, 15736000
.   : milestone, 15736000,
tracing (14.907 s) : 14907000, 14907000
.   : milestone, 14907000,
section candidate
no_agent (15.304 s) : 15304000, 15304000
.   : milestone, 15304000,
appsec (14.716 s) : 14716000, 14716000
.   : milestone, 14716000,
iast (18.695 s) : 18695000, 18695000
.   : milestone, 18695000,
iast_GLOBAL (18.065 s) : 18065000, 18065000
.   : milestone, 18065000,
profiling (15.214 s) : 15214000, 15214000
.   : milestone, 15214000,
tracing (14.9 s) : 14900000, 14900000
.   : milestone, 14900000,
Loading
  • baseline results
Variant Execution Time [CI 0.99] Δ no_agent
no_agent 15.715 s [15.715 s, 15.715 s] -
appsec 14.829 s [14.829 s, 14.829 s] -886.0 ms (-5.6%)
iast 18.679 s [18.679 s, 18.679 s] 2.964 s (18.9%)
iast_GLOBAL 18.498 s [18.498 s, 18.498 s] 2.783 s (17.7%)
profiling 15.736 s [15.736 s, 15.736 s] 21.0 ms (0.1%)
tracing 14.907 s [14.907 s, 14.907 s] -808.0 ms (-5.1%)
  • candidate results
Variant Execution Time [CI 0.99] Δ no_agent
no_agent 15.304 s [15.304 s, 15.304 s] -
appsec 14.716 s [14.716 s, 14.716 s] -588.0 ms (-3.8%)
iast 18.695 s [18.695 s, 18.695 s] 3.391 s (22.2%)
iast_GLOBAL 18.065 s [18.065 s, 18.065 s] 2.761 s (18.0%)
profiling 15.214 s [15.214 s, 15.214 s] -90.0 ms (-0.6%)
tracing 14.9 s [14.9 s, 14.9 s] -404.0 ms (-2.6%)
Execution time for tomcat
gantt
    title tomcat - execution time [CI 0.99] : candidate=1.61.0-SNAPSHOT~ce166bef0a, baseline=1.62.0-SNAPSHOT~081af53226
    dateFormat X
    axisFormat %s
section baseline
no_agent (1.5 ms) : 1489, 1512
.   : milestone, 1500,
appsec (3.797 ms) : 3577, 4016
.   : milestone, 3797,
iast (2.289 ms) : 2219, 2359
.   : milestone, 2289,
iast_GLOBAL (2.338 ms) : 2267, 2408
.   : milestone, 2338,
profiling (2.118 ms) : 2062, 2173
.   : milestone, 2118,
tracing (2.091 ms) : 2037, 2145
.   : milestone, 2091,
section candidate
no_agent (1.493 ms) : 1481, 1505
.   : milestone, 1493,
appsec (2.568 ms) : 2513, 2624
.   : milestone, 2568,
iast (2.3 ms) : 2230, 2370
.   : milestone, 2300,
iast_GLOBAL (2.345 ms) : 2274, 2415
.   : milestone, 2345,
profiling (2.109 ms) : 2054, 2164
.   : milestone, 2109,
tracing (2.095 ms) : 2041, 2149
.   : milestone, 2095,
Loading
  • baseline results
Variant Execution Time [CI 0.99] Δ no_agent
no_agent 1.5 ms [1.489 ms, 1.512 ms] -
appsec 3.797 ms [3.577 ms, 4.016 ms] 2.296 ms (153.1%)
iast 2.289 ms [2.219 ms, 2.359 ms] 788.755 µs (52.6%)
iast_GLOBAL 2.338 ms [2.267 ms, 2.408 ms] 837.419 µs (55.8%)
profiling 2.118 ms [2.062 ms, 2.173 ms] 617.324 µs (41.1%)
tracing 2.091 ms [2.037 ms, 2.145 ms] 591.179 µs (39.4%)
  • candidate results
Variant Execution Time [CI 0.99] Δ no_agent
no_agent 1.493 ms [1.481 ms, 1.505 ms] -
appsec 2.568 ms [2.513 ms, 2.624 ms] 1.075 ms (72.0%)
iast 2.3 ms [2.23 ms, 2.37 ms] 807.215 µs (54.1%)
iast_GLOBAL 2.345 ms [2.274 ms, 2.415 ms] 851.667 µs (57.0%)
profiling 2.109 ms [2.054 ms, 2.164 ms] 615.607 µs (41.2%)
tracing 2.095 ms [2.041 ms, 2.149 ms] 602.253 µs (40.3%)

@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.
The jetty-appsec-9.4 early_10_series muzzle pass covers [10.0.0, 10.0.10)
where _multiParts is MultiPartFormInputStream (before the type changed to
MultiParts in 10.0.10). The existing test suite used 10.0.10, leaving the
early versions untested.

Add earlyDep10ForkedTest (Jetty 10.0.9) to exercise the OR-muzzle reference
and verify that multipart filename events fire correctly on the old field type.
All three filename tests pass: filenames, filenames-called-once, filenames-combined.
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