← Back to Feed CACHED · 2026-11-04 08:49:10 · CACHE_KEY CVE-2025-2748
CVE-2025-2748 · CWE-79 · Disclosed 2025-03-24

Kentico Xperience multiple-file upload stored cross-site scripting

ASSESSED — NOISGATE
Vendor
—
—
—
Reassessed
—
—
—
Verdict: —
Do you agree?
01 · The Real Story

A mailroom that files unopened boxes and later hands them to employees

Kentico Xperience's multi-file upload does not fully validate or filter uploaded files, so a crafted SVG/HTML or polyglot file can be stored and later served from the CMS origin. The affected range is all versions through 13.0.178. When a victim opens the uploaded file, script executes in their authenticated CMS session, enabling session theft, content manipulation, or privilege escalation.

Vendor severity MEDIUM (6.1) is broadly right for the mechanics: network reachable, low complexity, no privileges assumed, user interaction required, scope changed. Real-world conditions support at most MEDIUM—upload endpoints are usually behind authentication in production Kentico sites, dangerous file types are often blocked by configuration, and a victim must actively open the planted file. The high EPSS score (0.60586) is suspicious given no known exploitation or public PoC, so treat it as an outlier.

"Stored XSS via Kentico upload needs a victim click; MEDIUM, not a fleet-critical emergency."
02 · The Attack Path

4 steps from start to impact.

STEP 01

Locate a reachable multi-file upload endpoint

The attacker identifies a Kentico Xperience site with the multi-file upload feature enabled. Depending on deployment, the endpoint may require authentication, but the CVSS assumes unauthenticated reachability. The attacker prepares one or more malicious files for submission.
Conditions required:
  • Network access to the Kentico web application
  • Multi-file upload endpoint enabled
  • If authentication is required, valid low-privilege credentials
Where this breaks in practice:
  • Most production Kentico sites restrict uploads to authenticated CMS editors
  • Custom upload forms without auth are uncommon
  • WAF or NGFW can block suspicious file upload requests
Detection/coverage: Web server logs and WAF may show upload attempts of unusual file types.
STEP 02

Upload a crafted file that survives validation

The application does not fully validate or filter files, so a file with script embedded in content, filename, or metadata passes checks. Attackers typically use .svg, .html, .xml, or polyglot files because browsers render them as active content. The file is stored in the CMS media library or upload directory.
Conditions required:
  • Server accepts active-content file extensions or can be induced to store one
  • No server-side filtering, MIME sniffing, or sanitization on uploaded files
Where this breaks in practice:
  • Default Kentico media library may restrict dangerous extensions
  • Some deployments set Content-Disposition: attachment for unknown types
  • Antivirus/file-integrity monitoring may flag HTML/SVG with scripts
Detection/coverage: File integrity monitoring can alert on new files in upload directories; antivirus may detect script-bearing uploads.
STEP 03

Lure a victim to open the stored file

The attacker sends a link to the stored file, embeds it in a page, or uses social engineering. When the victim opens the URL in a browser where they are authenticated to the CMS, the script executes in the Kentico origin context. Scope changes because the payload can affect other application resources.
Conditions required:
  • Victim is logged into the Kentico site
  • Victim clicks the link or views the file
  • No Content-Security-Policy or nosniff header blocking script execution
Where this breaks in practice:
  • Phishing-resistant user awareness may reduce clicks
  • If file is served with Content-Disposition: attachment, script won't run inline
  • CSP can block inline and external scripts
Detection/coverage: Email gateway may flag the lure; endpoint detection may alert on unusual script execution.
STEP 04

Execute script to act as the victim

The script reads session tokens, makes authenticated requests, modifies content, or adds a malicious admin user if the victim has sufficient privileges. Impact is stored XSS: persistent content manipulation, account takeover, and possible exfiltration of customer data from an affected portal.
Conditions required:
  • Victim session has elevated privileges (e.g., CMS admin)
  • Cookies or local storage tokens accessible to script
  • No CSRF token or SameSite cookie restricting cross-site actions
Where this breaks in practice:
  • HttpOnly session cookies prevent direct token theft
  • Multi-factor authentication on admin accounts limits session reuse
  • Victim may have low-privilege account, limiting impact
Detection/coverage: SIEM can detect anomalous admin actions (new user creation, content changes); XSS payload may trigger WAF on follow-on requests.
03 · Compensating Control

1
MEDIUM 5.0→MEDIUM 5.0
Restrict multi-file upload to authenticated editors only — Disable anonymous access to the upload endpoint and require editor/administrator role. This breaks the PR:N assumption and reduces the reachable attacker population. Implement as part of monthly hardening; if the endpoint is externally reachable, apply within 30 days. Residual severity MEDIUM (5.0) — low-privilege authenticated attacker can still upload, but the victim interaction gate remains.
2
MEDIUM 5.0→LOW 3.0
SEVERITY REDUCED
Enforce a strict file-type allowlist and force attachment disposition — Allow only safe extensions (e.g., image formats), validate MIME and content, and serve uploaded files with Content-Disposition: attachment plus X-Content-Type-Options: nosniff. This breaks script execution on access. Residual severity LOW (3.0).
3
MEDIUM 5.0→IGNORE 0.0
SEVERITY REDUCED
Upgrade Kentico Xperience beyond 13.0.178 — Apply the vendor patch from DevNet. Per noisgate remediation SLA, complete within 365 days for MEDIUM severity. This removes the vulnerable code path entirely. Residual severity IGNORE (0.0).
What doesn't work
  • Client-side input validation on the upload form — server-side validation is absent, so browser-level checks are trivially bypassed.
  • Weak password policies alone — the vulnerability is not credential-focused; an authenticated attacker with upload permission still triggers it.
  • Network segmentation alone — if the CMS is reachable by the intended user population, it is reachable by the attacker.
04 · Intelligence Metadata

The supporting signals.

In-the-wild statusNo known active exploitation; KEV not listed (as of 2025-12-27).
Proof of conceptNo public PoC identified in GitHub, ExploitDB, or nuclei templates in search results; no repo named after CVE-2025-2748.
EPSS0.60586 (60.586% 30-day probability) — unusually high for stored XSS; no exploitation evidence supports it.
KEV statusNot listed in CISA KEV.
CVSS v3.1 vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N = 6.1 MEDIUM. Low attack complexity, no privileges, user interaction required, scope changed.
Affected versionsKentico Xperience through 13.0.178 (all prior versions).
Fixed versionNot explicitly stated in NVD/INCIBE; patch likely in later DevNet release.
Disclosure date2025-03-24 (NVD published 2025-03-24 19:15 UTC).
Reported byVulnCheck (secondary source [email protected] in NVD); MITRE CVE.org record.
Scanning exposureNo public Shodan/GreyNoise/FOFA data for this CVE; exposure is limited to internet-facing Kentico installations with upload endpoints enabled.

Sources.

  1. NVD
  2. VulDB
  3. INCIBE
  4. CIRCL cvelistv5
  5. CIRCL fkie_nvd
  6. GHSA
  7. INCIBE EN
05 · The Call

Final Verdict
= UNCHANGED to MEDIUM (5.0/10)

Why this verdict

  • Role multiplier: Kentico Xperience is a CMS, not a canonical identity/hypervisor/edge/CA component; the worst plausible high-value role is a customer portal or e-commerce site where stored XSS yields site-level admin or session theft, not domain/fleet/supply-chain scale.
  • Upload surface is usually authenticated: CVSS assumes PR:N, but most production Kentico sites require editor credentials for multi-file upload, cutting reachable population.
  • User interaction and no active exploitation: victim must open a planted file; no KEV, no public PoC, no in-the-wild reports despite high EPSS.
  • Action timeline: noisgate mitigation SLA has no mandatory window for MEDIUM; noisgate remediation SLA is ≤ 365 days for the vendor patch.

Why not higher?

Stored XSS does not provide direct unauthenticated RCE, lateral movement, or domain escalation. The attack chain stalls unless a user with an active session opens the file, and typical Kentico deployments do not expose upload endpoints to anonymous users. No known exploitation or public PoC means real-world impact is currently limited.

Why not lower?

If an authenticated admin opens the malicious file, the attacker can take over the CMS—adding admin accounts, modifying content, and exfiltrating customer data. Stored XSS persists until the file is removed, and the product is an enterprise CMS often hosting sensitive websites. The EPSS value, though likely anomalous, suggests some exploitation probability if uploads are reachable.

06 · Verification

Crowdsourced verification payload.

Run on the Kentico Xperience web server as Administrator or with read access to the web root. From PowerShell: powershell -ExecutionPolicy Bypass -File .\Check-CVE-2025-2748.ps1. It scans common web roots for Kentico DLLs and compares the file version to 13.0.178; outputs VULNERABLE, PATCHED, or UNKNOWN. Requires read access to IIS web directories.

noisgate-verify.ps1
POWERSHELLREAD-ONLYSAFE
# Check-CVE-2025-2748.ps1
# Detects Kentico Xperience installations and compares version to 13.0.178
$ErrorActionPreference = 'SilentlyContinue'
$roots = @('C:\inetpub\wwwroot','C:\Program Files\Kentico','D:\websites','C:\web')
$dllPattern = 'Kentico*.dll'
$files = @()
foreach ($root in $roots) {
    if (Test-Path $root) {
        $files += Get-ChildItem -Path $root -Recurse -Filter $dllPattern -File | Where-Object { $_.Name -match 'Kentico\.(ContentManagement|CMS|Core)' }
    }
}
if ($files.Count -eq 0) {
    Write-Output 'UNKNOWN'
    exit 2
}
$vulnerable = $false
$patched = $false
foreach ($file in $files) {
    try {
        $version = $file.VersionInfo.FileVersion
        if ($version) {
            if ([version]$version -le [version]'13.0.178') {
                Write-Output ('VULNERABLE ' + $file.FullName + ' version ' + $version)
                $vulnerable = $true
            } else {
                Write-Output ('PATCHED ' + $file.FullName + ' version ' + $version)
                $patched = $true
            }
        }
    } catch {}
}
if ($vulnerable -and -not $patched) { Write-Output 'VULNERABLE'; exit 1 }
if ($patched -and -not $vulnerable) { Write-Output 'PATCHED'; exit 0 }
if ($vulnerable -and $patched) { Write-Output 'VULNERABLE (mixed)'; exit 1 }
Write-Output 'UNKNOWN'; exit 2