Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') vulnerability in NerdPress Hubbub Lite allows Stored XSS.
This issue affects Hubbub Lite: from n/a through 1.36.3.
In Progress® Telerik® UI for AJAX prior to v2026.2.708, insufficient validation of the language parameter in the spell check handler may allow an attacker to influence server-side file path resolution and trigger unintended server-side requests.
## Summary
The fix for GHSA-6jxm-fv7w-rw5j (CVE-2026-23845, "Server-Side Request Forgery (SSRF) via HTML Check API"), shipped in mailpit `v1.28.3`, hardened `internal/htmlcheck/css.go::downloadCSSToBytes` with a 5MB size cap, a `text/css` content-type check, login-info stripping in `isValidURL`, and an opt-in `--block-remote-css-and-fonts` config flag — but **did not add the IP-filtering dialer that the same codebase already uses on the two sister SSRF endpoints** (the proxy handler and link-check). At HEAD `8bc966e61834a24c48b4465da418f75e73be0afd` (2026-05-06), `internal/htmlcheck/css.go::newSafeHTTPClient` is mis-named — it builds an `http.Client` whose `Transport.DialContext` calls `net.Dialer.DialContext` directly with no IP allowlisting. As a result, the SSRF originally reported by Bao Anh Phan still permits the server to dial:
- loopback (`127.0.0.0/8`, `::1`),
- private (`10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`, `fc00::/7`),
- link-local incl. **cloud IMDS** (`169.254.0.0/16`, especially `169.254.169.254`),
- CGNAT (`100.64.0.0/10`),
- and any other reserved/multicast range,
— provided the target replies with `HTTP/200` and a content-type beginning with `text/css`. With redirect-following (`CheckRedirect` allows redirects to any `isValidURL` URL with no IP filter), an attacker-controlled public site can redirect mailpit's request into the private network without ever appearing in the email's HTML.
In the default mailpit deploy (no UI auth, no SMTP auth, port 1025/8025 exposed), this is an unauthenticated, network-reachable SSRF triggered by sending an HTML email and then issuing one HTTP `GET` to `/api/v1/message/{id}/html-check`.
## Affected versions
- `internal/htmlcheck/css.go` at HEAD `8bc966e61834a24c48b4465da418f75e73be0afd` (2026-05-06).
- All versions `>= v1.28.3` (the version that shipped the GHSA-6jxm fix). Versions `<= v1.28.2` are vulnerable to the original GHSA-6jxm; versions `>= v1.28.3` carry the still-vulnerable variant described here.
## The incomplete fix
The original GHSA-6jxm fix added size+content-type+login-info hardening to `downloadCSSToBytes`. But the dialer it uses still has no `safeDialContext`. The companion `linkcheck` and `proxy` handlers in the same codebase have all-three protections: size cap, content-type/redirect filter, **AND** a `safeDialContext` that runs `tools.IsInternalIP(ip.IP)` per resolved address — same pattern the htmlcheck dialer should adopt.
Side-by-side at HEAD `8bc966e`:
| File | Function | `safeDialContext` (IP filter)? | TOCTOU-safe (dial-by-IP)? |
|---|---|---|---|
| `internal/linkcheck/status.go::safeDialContext` line 140-163 | dial check | YES | YES (resolved IP joined with port) |
| `server/handlers/proxy.go::safeDialContext` line 393-415 | dial check | YES | YES |
| `internal/htmlcheck/css.go::newSafeHTTPClient` line 275-310 | dial check | **NO** | n/a |
The mis-named `newSafeHTTPClient` reads:
```go
// internal/htmlcheck/css.go:275-310
func newSafeHTTPClient() *http.Client {
dialer := &net.Dialer{
Timeout: 5 * time.Second,
KeepAlive: 30 * time.Second,
}
tr := &http.Transport{
Proxy: nil,
DialContext: func(ctx context.Context, network, address string) (net.Conn, error) {
return dialer.DialContext(ctx, network, address) // no IP filter
},
...
}
client := &http.Client{
Transport: tr,
Timeout: 15 * time.Second,
CheckRedirect: func(req *http.Request, via []*http.Request) error {
if len(via) >= 3 { return errors.New("too many redirects") }
if !isValidURL(req.URL.String()) { return errors.New("invalid redirect URL") }
return nil
},
}
return client
}
```
`isValidURL` only rejects non-http(s) and userinfo URLs — it does NOT reject internal IPs. Compare `linkcheck/status.go::safeDialContext`:
```go
ips, err := net.DefaultResolver.LookupIPAddr(ctx, host)
...
if !config.AllowInternalHTTPRequests {
for _, ip := range ips {
if tools.IsInternalIP(ip.IP) {
return nil, fmt.Errorf("blocked request to %s (%s): private/reserved address", host, ip)
}
}
}
return dialer.DialContext(ctx, network, net.JoinHostPort(ips[0].IP.String(), port))
```
That's the protection htmlcheck is missing.
## Reachability chain (default deploy)
```
Listen() # config/config.go:36 SMTPListen = "[::]:1025"
↓
SMTP server # internal/smtpd/main.go:222-249 AuthRequired: false, AuthHandler: nil
↓ attacker injects HTML body with <link rel="stylesheet" href="...attacker.com/redirect.css">
↓
storage.Store(...)
↓
Listen() # server/server.go HTTPListen
↓ attacker sends GET /api/v1/message/{id}/html-check
apiv1.HTMLCheck # server/apiv1/other.go:18
↓ no UI auth in default deploy (auth.UICredentials == nil)
htmlcheck.RunTests(msg.HTML)
Between May and July 2026, researchers tracked the Latin America-focused threat actor Blind Eagle through multiple exposed staging servers, identifying significant toolkit evolution. Four key developments emerged: a third string-obfuscation scheme featuring JavaScript with custom AES S-box substitution, a RunPE loader using bare AutoIt3 interpreter staged via GitHub, a reusable 'Photo Studio' persistence mechanism shared across three distinct toolchains, and a materially upgraded AsyncRAT variant codenamed JC-46. This enhanced RAT incorporates Windows Notification Facility process injection, custom Base28 encoding, Hidden VNC banking-fraud capabilities with browser profile cloning, and a Chrome App-Bound Encryption v20 bypass. Despite operational security weaknesses including exposed directories and hardcoded credentials, the group demonstrates selective sophistication targeting banking operations across Spanish-speaking regions.
Symfony UX is a JavaScript ecosystem for Symfony. From 2.22.0 until 2.36.0 and 3.1.0, Symfony\UX\LiveComponent\EventListener\LiveComponentSubscriber::isLiveComponentRequest() gates #[LiveAction] invocations on Accept: application/vnd.live-component+html, but the Accept header is CORS-safelisted and cross-origin fetch() can set it without preflight, allowing forged cross-origin #[LiveAction] requests against a victim session when applications use SameSite=None, credentials: 'include', a permissive cookie policy, or a same-origin pivot. This issue is fixed in versions 2.36.0 and 3.1.0.
Symfony UX is a JavaScript ecosystem for Symfony. From 2.2.0 until 2.36.0 and 3.1.0, the Stimulus controller in symfony/ux-autocomplete renders AJAX response items in _createAutocompleteWithRemoteData() by interpolating the text field into HTML template literals (<div>${item[labelField]}</div>) rather than text, allowing attacker-controlled markup from user-supplied dropdown values to execute in the browser of any user who opens an autocomplete widget backed by the same data. This issue is fixed in versions 2.36.0 and 3.1.0.
Symfony UX is a JavaScript ecosystem for Symfony. From 2.2.0 until 2.36.0 and 3.1.0, Symfony\UX\Autocomplete\Doctrine\EntitySearchUtil::addSearchClause() builds the LIKE expression used by the autocomplete endpoint by wrapping the client-supplied query in %...% without escaping SQL LIKE wildcards (%, _, \), allowing unauthenticated users to turn the public BaseEntityAutocompleteType endpoint into a broad matcher or blind boolean oracle against every column in default searchable_fields. This issue is fixed in versions 2.36.0 and 3.1.0.
Symfony UX is a JavaScript ecosystem for Symfony. From 2.8.0 until 2.36.0 and 3.1.0, when a #[LiveProp] is typed as DateTimeInterface and no explicit format is configured, Symfony\UX\LiveComponent\LiveComponentHydrator::hydrateObjectValue() falls back to new $className($value), allowing client-supplied relative strings such as now, tomorrow, or +10 years to move a writable, format-less date prop past time-based business logic checks. This issue is fixed in versions 2.36.0 and 3.1.0.
Symfony UX is a JavaScript ecosystem for Symfony. From 2.8.0 until 2.36.0 and 3.1.0, Symfony\UX\LiveComponent\Util\ChildComponentPartialRenderer::createHtml() interpolates the client-controlled children[id].tag value from LiveComponentSubscriber and InterceptChildComponentRenderSubscriber directly into HTML as a tag name without escaping or validation, allowing arbitrary HTML, including <script> tags, on any Live Component re-render that contains at least one child component. This issue is fixed in versions 2.36.0 and 3.1.0.
Symfony UX is a JavaScript ecosystem for Symfony. From 2.8.0 until 2.36.0 and 3.1.0, the HMAC computed by Symfony\UX\LiveComponent\LiveComponentHydrator covered only sorted prop key/value pairs and did not include the component name, the slot identifier (props vs propsFromParent), or request context, allowing a signed blob minted for one component or slot to be replayed in another and set a read-only prop on a target component. This issue is fixed in versions 2.36.0 and 3.1.0.
Symfony UX is a JavaScript ecosystem for Symfony. From 2.5.0 until 2.36.0 and 3.1.0, Symfony\UX\LiveComponent\Controller\BatchActionController::__invoke() iterates over the client-supplied actions array and issues a full HttpKernel sub-request for each entry; because the array size is never bounded, an authenticated client can submit a single _batch request containing thousands of actions and exhaust CPU, memory, and database connections on the application server. This issue is fixed in versions 2.36.0 and 3.1.0.
Vaultwarden is a Bitwarden-compatible server written in Rust. Prior to 1.36.0, Vaultwarden's /icons/{domain}/icon.png endpoint used src/http_client.rs checks including should_block_address() and post_resolve() that missed decimal, hexadecimal, and octal IP representations, allowing SSRF through the icon-fetching HTTP client for blind internal network or port discovery. This issue is fixed in version 1.36.0.
Vaultwarden is a Bitwarden-compatible server written in Rust. Prior to 1.36.0, Vaultwarden's SSO discovery and pre-validation flow returned organization-related SSO metadata including organizationIdentifier values for arbitrary email addresses and allowed a valid pre-validation JWT to be obtained with only the discovered identifier, enabling SSO-enabled organization enumeration and authentication workflow abuse. This issue is fixed in version 1.36.0.
A vulnerability has been found in will-moss Isaiah up to 1.36.9. This affects an unknown function of the file app/main.go of the component Websocket Connection Authentication. The manipulation leads to improper authentication. The attack can be initiated remotely. The pull request to fix this issue awaits acceptance.
A flaw has been found in will-moss Isaiah up to 1.36.9. The impacted element is the function Server.Handle of the file app/server/server/server.go of the component Master Websocket Handler. Executing a manipulation of the argument Agent can lead to missing authorization. It is possible to launch the attack remotely. The pull request to fix this issue awaits acceptance.
RabbitMQ is a messaging and streaming broker. Prior to 4.1.11 and 4.2.6 on Windows, the RabbitMQ management plugin static file handler rabbit_mgmt_wm_static can pass URL-encoded backslashes to erl_prim_loader:read_file_info before path validation when multiple management extension plugins are enabled, causing outbound DNS and SMB requests to attacker-controlled UNC paths. This issue is fixed in versions 4.1.11 and 4.2.6.
### Summary
The restrictions on redirect URLs in `openrun` can be bypassed by attackers, leading to open redirect attacks.
### Details
In the current project, the referrer header value is used for subsequent redirects, so there is currently a validation for this redirect value. The current validation logic requires that the host and schema of the redirect URL be the same as the current website's URL, and finally, the path part is used for redirection. This check seems robust, but it can still be bypassed by attackers.
<img width="1606" height="1346" alt="QQ20260602-140205-2-2" src="https://github.com/user-attachments/assets/83c549f3-38d7-444d-90f0-131d806f67ff" />
Here's the problem: Assuming the current website is `http://127.0.0.1:25222/`, if the attacker passes in a redirect URL of `http://127.0.0.1:25222//fushuling.com`, its host and schema are obviously the same as the current website, thus bypassing the verification. However, the issue lies in the final redirect URL, which is the path part of the URL, i.e., `//fushuling.com`.
Browsers automatically complete the HTTP header for URLs starting with `//`, ultimately successfully bypassing the restriction and redirecting to the external address `http://fushuling.com`.
This vulnerable behavior was successfully reproduced locally. Normally, specifying an external address directly will be blocked, so it will not redirect.
<img width="1587" height="717" alt="QQ20260602-140756-2-3" src="https://github.com/user-attachments/assets/51430c42-bd10-401b-9c9f-27a91a0bc648" />
However, if the redirect URL is `http://127.0.0.1:25222//fushuling.com`, the existing validation logic is bypassed, and the Location header is successfully set to `//fushuling.com`.
```
POST /redirecttest/abc/frag HTTP/1.1
Host: 127.0.0.1:25222
Referer: http://127.0.0.1:25222//fushuling.com
Cache-Control: max-age=0
sec-ch-ua: "Not(A:Brand";v="24", "Chromium";v="122"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.6261.57 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 0
```
<img width="1536" height="729" alt="QQ20260602-140925-2-4" src="https://github.com/user-attachments/assets/31fde919-5f90-409f-8b14-af6c9c71761b" />
The user was then successfully redirected to the external address `http://fushuling.com`.
<img width="1692" height="855" alt="QQ20260602-141005-2-5" src="https://github.com/user-attachments/assets/83b43ef6-52fa-4218-908b-7795394ae707" />
### PoC
```
http://127.0.0.1:25222//fushuling.com
```
### Impact
Open Redirect
Symfony UX is a JavaScript ecosystem for Symfony. From 2.17.0 before 2.36.1 and from 3.0.0 before 3.2.0, the ux_icon() Twig function is marked is_safe=['html'] and Icon::toHtml() inlines SVG source verbatim, allowing unsanitized local SVG files or Iconify on-demand JSON body responses containing nested script elements, on* event handlers, or dangerous URL schemes to execute cross-site scripting. This issue is fixed in versions 2.36.1 and 3.2.0.
Wasmtime is a runtime for WebAssembly. Prior to 24.0.11, 36.0.12, 45.0.3, and 46.0.1, wasmtime-wasi hard-link creation and renaming check directory permissions but not matching FilePerms on source and destination preopens, allowing a WASI guest with a read-only source file capability to overwrite host files exposed as FilePerms::READ through wasip1, wasip2, or wasip3 filesystem interfaces. This issue is fixed in versions 24.0.11, 36.0.12, 45.0.3, and 46.0.1.