Title: Java: Model Spring reactive `WebClient.uri` as a request forgery sink by joshimar · Pull Request #22132 · github/codeql · GitHub
Open Graph Title: Java: Model Spring reactive `WebClient.uri` as a request forgery sink by joshimar · Pull Request #22132 · github/codeql
X Title: Java: Model Spring reactive `WebClient.uri` as a request forgery sink by joshimar · Pull Request #22132 · github/codeql
Description: Spring WebFlux's reactive WebClient sends a request to the URL passed to the per-request uri(...) method (for example webClient.get().uri(url)), declared on WebClient.UriSpec. The request-forgery model covers WebClient.create(url) and WebClient.builder().baseUrl(url). It does not yet cover the per-request uri(...) method, which is the usual way to set a request URL, so a URL built from untrusted input and sent through uri(...) is a java/ssrf sink that is currently unmodeled.
Change
Adds WebClient$UriSpec.uri as a request-forgery sink:
- ["org.springframework.web.reactive.function.client", "WebClient$UriSpec", True, "uri", "", "", "Argument[0]", "request-forgery", "manual"]
subtypes is True so the row also applies to RequestHeadersUriSpec and RequestBodyUriSpec, the receiver types returned by get(), post() and similar methods.
The signature is left blank to cover all URL-bearing overloads: uri(URI), uri(String, Object...) and uri(String, Map).
Testing
Validated at three levels.
Query tests. ReactiveWebClientSSRF.java adds tainted flows into uri(String) and uri(URI), and RequestForgery.expected is regenerated. The CWE-918 tests pass.
True positives (full-build database). Compiled against the Spring WebFlux library, the sink reports untrusted input reaching the request URL:
directly, via uri(String);
as a URI template, via uri(String, Object...);
via a UriComponentsBuilder whose host is attacker-controlled (fromUriString, host).
Multi-repository variant analysis.
Dataset: 34 popular public Java projects (Spring and WebFlux based), using the CodeQL databases GitHub publishes for them, fetched through the code scanning API. The full list is below:
Repositories analyzed (34)
alibaba/arthas
alibaba/canal
alibaba/nacos
alibaba/spring-cloud-alibaba
apache/dolphinscheduler
apache/dubbo
apache/rocketmq
apache/shenyu
apache/skywalking
apolloconfig/apollo
elunez/eladmin
google/guava
graphhopper/graphhopper
halo-dev/halo
jeecgboot/jeecg-boot
macrozheng/mall
macrozheng/mall-swarm
Netflix/zuul
openzipkin/zipkin
resilience4j/resilience4j
sofastack/sofa-boot
spring-cloud/spring-cloud-commons
spring-cloud/spring-cloud-config
spring-cloud/spring-cloud-gateway
spring-cloud/spring-cloud-netflix
spring-cloud/spring-cloud-openfeign
spring-projects/spring-boot
spring-projects/spring-framework
spring-projects/spring-security
square/okhttp
thingsboard/thingsboard
YunaiV/ruoyi-vue-pro
zalando/logbook
zhoutaoo/SpringCloud
Coverage check: the sink resolves and matches WebClient.uri call sites across the dataset, confirming the run exercises the new model.
Result: no alerts, confirming no false positives on the dataset.
Overload coverage
The blank signature also matches the uri(Function
Open Graph Description: Spring WebFlux's reactive WebClient sends a request to the URL passed to the per-request uri(...) method (for example webClient.get().uri(url)), declared on WebClient.UriSpec. The request-forge...
X Description: Spring WebFlux's reactive WebClient sends a request to the URL passed to the per-request uri(...) method (for example webClient.get().uri(url)), declared on WebClient.UriSpec. The request-f...
Opengraph URL: https://github.com/github/codeql/pull/22132
X: @github
Domain: github.com
| route-pattern | /:user_id/:repository/pull/:id/files(.:format) |
| route-controller | pull_requests |
| route-action | files |
| fetch-nonce | v2:c022f87e-a48a-9611-1282-f1bb9d13bb69 |
| current-catalog-service-hash | ae870bc5e265a340912cde392f23dad3671a0a881730ffdadd82f2f57d81641b |
| request-id | DD9A:E1B7B:163C828:2077B4C:6A4E4E5A |
| html-safe-nonce | 7165c33bc0408593ba1d04048e17a4a451745190b83a48cd526877429e99cbc8 |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJERDlBOkUxQjdCOjE2M0M4Mjg6MjA3N0I0Qzo2QTRFNEU1QSIsInZpc2l0b3JfaWQiOiIxNTk0MTQwNDEyOTIxOTI1MjEwIiwicmVnaW9uX2VkZ2UiOiJpYWQiLCJyZWdpb25fcmVuZGVyIjoiaWFkIn0= |
| visitor-hmac | 2d65cc8a0ae14641463580e5201fdaeddba5a77d074210faf633dfd55134dc47 |
| hovercard-subject-tag | pull_request:4009794440 |
| github-keyboard-shortcuts | repository,pull-request-list,pull-request-conversation,pull-request-files-changed,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/github/codeql/pull/22132/files |
| twitter:image | https://avatars.githubusercontent.com/u/5940328?s=400&v=4 |
| twitter:card | summary_large_image |
| og:image | https://avatars.githubusercontent.com/u/5940328?s=400&v=4 |
| og:image:alt | Spring WebFlux's reactive WebClient sends a request to the URL passed to the per-request uri(...) method (for example webClient.get().uri(url)), declared on WebClient.UriSpec. The request-forge... |
| og:site_name | GitHub |
| og:type | object |
| hostname | github.com |
| expected-hostname | github.com |
| None | 030096ee0db095447bfe77409d33bfac127ca7128299c58deef27c52eaa1b1f0 |
| turbo-cache-control | no-preview |
| diff-view | unified |
| go-import | github.com/github/codeql git https://github.com/github/codeql.git |
| octolytics-dimension-user_id | 9919 |
| octolytics-dimension-user_login | github |
| octolytics-dimension-repository_id | 143040428 |
| octolytics-dimension-repository_nwo | github/codeql |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 143040428 |
| octolytics-dimension-repository_network_root_nwo | github/codeql |
| turbo-body-classes | logged-out env-production page-responsive full-width |
| disable-turbo | true |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | e8506f6d0538364886e3f0153c154c410965e70d |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width