This is a misplaced office key behind the receptionist desk, not a front-door master key
CVE-2025-0227 is a remote file disclosure bug in Tsinghua Unigroup Electronic Archives System affecting version 3.2.210802(62532). The vulnerable component is the /Logs/Annals/downLoad.html handler, where a user-controlled path argument can be manipulated to retrieve unintended files readable by the application, yielding confidentiality impact without stated integrity or availability impact.
The vendor's MEDIUM 4.3 baseline is already restrained, and in enterprise reality it trends slightly lower. The decisive friction is PR:L: the attacker must already hold a valid low-privilege account or equivalent session, which makes this mostly a post-initial-access or post-credential-theft problem in a niche product with no KEV listing, very low EPSS, no public evidence of broad exploitation, and only partial impact.
4 steps from start to impact.
Land a valid application session
- Network reachability to the application
- A valid low-privilege user account or reusable authenticated session
- The target runs the affected
3.2.210802(62532)build
- MFA, SSO, or VPN gating can materially reduce reachable population
- Many deployments of this product are likely internal-only, not internet-facing
- Without credentials, the CVSS
PR:Lprerequisite blocks first-hop abuse
Probe the vulnerable download handler
Burp Suite, curl, or the PoC path referenced in the CVE record, the attacker sends requests to /Logs/Annals/downLoad.html while tampering with the path parameter. The goal is to coerce the handler into returning a file outside the intended access scope.- Authenticated access to the application
- The vulnerable endpoint is deployed and reachable
- Request parameter handling is unchanged from the affected release
- Endpoint paths can vary across reverse proxies or customized deployments
- WAF or reverse-proxy normalization may block obvious traversal-style payloads
- Some deployments may remove or restrict the module entirely
downLoad.html with anomalous path values; off-the-shelf external scanners have weak coverage unless they understand the app and authenticate.Read files the app account can access
- The server-side process has read access to useful files
- Requested files are not separately access-controlled by the application
- Returned content is not redacted or blocked by the server
- The impact is capped at confidentiality and only what the app account can read
- OS permissions and containerization can sharply limit what is obtainable
- There is no stated write, code execution, or service-crash path
Use disclosed data for follow-on abuse
- The disclosed files contain sensitive data or reusable secrets
- The attacker can operationalize the information elsewhere
- Many accessible files may be low-value operational artifacts
- No direct integrity or availability impact is built into this CVE
- Blast radius is usually limited to one application dataset or host context
PR:L prerequisite cannot be exercised from the open internet. For a LOW verdict there is no formal SLA; treat this as backlog hygiene and complete it in normal hardening work if exposure exists.downLoad.html access — Add reverse-proxy or application logging for repeated requests to /Logs/Annals/downLoad.html with unusual path values, then alert on spikes or off-hours access. For LOW, deploy as backlog hygiene rather than emergency change, unless the system holds highly sensitive records.- EDR alone does not solve this because the application can read files through normal process behavior; nothing about a successful read necessarily looks malicious at the OS level.
- Network segmentation by itself is weak if the attacker already has internal access or a valid app session; the bug lives in the authenticated web workflow.
- Password rotation without MFA or session controls is incomplete if session cookies can be stolen or reused.
The supporting signals.
| In-the-wild status | No reliable public evidence of active exploitation found in the sources reviewed; CISA ADP SSVC marks Exploitation: none. |
|---|---|
| Proof-of-concept availability | The CVE record references a public GitHub PoC at BxYQ/ld/file_read1/poc.py; the original repo path appears unavailable now, but the CVE/OpenCVE record still documents it as public exploit material. |
| EPSS | 0.00123 from your intel block, which is extremely low and consistent with a niche, auth-required issue. |
| KEV status | No as of this assessment; not present in the CISA KEV catalog. |
| CVSS vector reality check | CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N maps to *remote but authenticated* with *low confidentiality-only* impact. That is a built-in downward pressure compared with unauthenticated edge bugs. |
| Affected versions | CVE/OpenCVE lists Tsinghua Unigroup Electronic Archives System 3.2.210802(62532) as affected. No broader version range was published in the record I reviewed. |
| Fixed version | No vendor-fixed version or workaround was published in the cited record; treat patched_version as unknown and verify with the vendor or maintainer. |
| Disclosure timeline | Reserved 2025-01-04, published 2025-01-05, and CISA ADP enrichment updated 2025-01-06. |
| Reporter / assigning authority | Assigned by VulDB per the CVE metadata surfaced in OpenCVE. |
| Exposure / scanning data | I found no trustworthy public Shodan/Censys/FOFA count for this specific product+endpoint combination in the reviewed sources. That absence itself argues against assuming broad internet exposure. |
Sources.
Why this verdict
- Requires authenticated remote access:
PR:Lmeans the attacker needs a valid user account or stolen session first, which implies prior compromise, insider access, or successful credential abuse. - Narrow blast radius: the published impact is file disclosure within the application's readable scope, not host takeover, not arbitrary write, and not service outage.
- Low public threat signal: no KEV listing, extremely low EPSS, and no solid evidence of active campaigns reduce urgency despite the PoC reference.
- Likely niche exposure population: this is not a commodity internet edge product with massive U.S. enterprise footprint, so the vendor score slightly overstates typical fleet-wide urgency for a 10,000-host program.
Why not higher?
This is not an unauthenticated edge compromise and there is no published RCE, auth bypass, mass exploitation evidence, or destructive outcome. Even if reachable over the network, the attacker must already be inside the trust boundary of the application and the documented effect is only low confidentiality loss.
Why not lower?
It is still a real remote application flaw with a disclosed exploit reference, and once an attacker has credentials the path to abuse is straightforward. Archives platforms often hold sensitive documents, so even a low-impact disclosure bug can matter if this app stores HR, legal, or regulated records.
Crowdsourced verification payload.
Run this on the application server or on a mounted application image, not from a random auditor workstation, because it performs an offline install check rather than active exploitation. Invoke it with python3 check_cve_2025_0227.py --root /opt/earchives and supply read access to the installation directory; no admin rights are required beyond filesystem read permissions.
#!/usr/bin/env python3
# check_cve_2025_0227.py
# Offline checker for CVE-2025-0227 in Tsinghua Unigroup Electronic Archives System
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN, 3=usage/runtime error
import argparse
import os
import re
import sys
from pathlib import Path
AFFECTED_VERSION = "3.2.210802(62532)"
ENDPOINT_SUFFIX = Path("Logs") / "Annals" / "downLoad.html"
PRODUCT_HINTS = [
"Electronic Archives System",
"Tsinghua Unigroup",
"Archives",
"电子档案",
]
VERSION_FILE_CANDIDATES = [
"version.txt",
"VERSION",
"build.txt",
"manifest.mf",
"pom.properties",
"application.properties",
]
MAX_SCAN_FILES = 4000
MAX_READ_BYTES = 2 * 1024 * 1024
def read_text_safely(path: Path):
try:
if path.stat().st_size > MAX_READ_BYTES:
return None
return path.read_text(encoding="utf-8", errors="ignore")
except Exception:
return None
def find_endpoint(root: Path):
matches = []
for p in root.rglob("downLoad.html"):
try:
rel = p.relative_to(root)
except Exception:
rel = p
if str(rel).replace('\\', '/').endswith(str(ENDPOINT_SUFFIX).replace('\\', '/')):
matches.append(p)
return matches
def scan_for_version_and_product(root: Path):
version_match = False
product_hint = False
scanned = 0
preferred = []
for name in VERSION_FILE_CANDIDATES:
preferred.extend(root.rglob(name))
seen = set()
ordered_paths = []
for p in preferred:
if p.is_file() and p not in seen:
ordered_paths.append(p)
seen.add(p)
for p in root.rglob("*"):
if scanned >= MAX_SCAN_FILES:
break
if p.is_file() and p not in seen:
ordered_paths.append(p)
seen.add(p)
scanned += 1
for p in ordered_paths:
text = read_text_safely(p)
if not text:
continue
if AFFECTED_VERSION in text:
version_match = True
for hint in PRODUCT_HINTS:
if hint.lower() in text.lower():
product_hint = True
break
if version_match and product_hint:
break
return version_match, product_hint
def main():
parser = argparse.ArgumentParser(description="Offline check for CVE-2025-0227")
parser.add_argument("--root", required=True, help="Application installation root")
args = parser.parse_args()
root = Path(args.root)
if not root.exists() or not root.is_dir():
print("UNKNOWN - installation root not found or not a directory")
return 2
endpoint_hits = find_endpoint(root)
version_match, product_hint = scan_for_version_and_product(root)
if endpoint_hits and version_match:
print("VULNERABLE - found affected version '{}' and endpoint '{}'".format(
AFFECTED_VERSION, ENDPOINT_SUFFIX.as_posix()
))
return 1
if product_hint and not endpoint_hits:
print("PATCHED - product indicators found but vulnerable endpoint '{}' not present".format(
ENDPOINT_SUFFIX.as_posix()
))
return 0
if endpoint_hits and not version_match:
print("UNKNOWN - vulnerable endpoint exists but affected version string '{}' was not confirmed".format(
AFFECTED_VERSION
))
return 2
if version_match and not endpoint_hits:
print("UNKNOWN - affected version string found but endpoint '{}' was not located".format(
ENDPOINT_SUFFIX.as_posix()
))
return 2
print("UNKNOWN - insufficient evidence to confirm product, version, or endpoint")
return 2
if __name__ == "__main__":
try:
sys.exit(main())
except KeyboardInterrupt:
print("UNKNOWN - interrupted")
sys.exit(2)
except Exception as exc:
print(f"UNKNOWN - runtime error: {exc}")
sys.exit(3)