This is a sharp knife left in a locked classroom, not a grenade in the lobby
CVE-2025-0203 is a SQL injection flaw in code-projects Student Management System 1.0, specifically the showSubject1 function in /config/DbFunction.php where the sid parameter is mishandled. The authoritative records disagree on preconditions: the CNA/VulDB vector says PR:L while NVD later enriched it to PR:N; the product page describes a simple PHP app with only an admin login, which makes the authenticated interpretation more believable in real deployments.
Vendor MEDIUM 6.3 is closer to reality than NVD's later 9.8 enrichment. The biggest reason is friction: this looks like a low-end school/demo PHP application with narrow enterprise presence, no KEV listing, very low EPSS, and only public PoC evidence; even if exploitation is straightforward on a live target, most 10,000-host estates either do not run it at all or run it in a limited web-app corner rather than as a core platform.
3 steps from start to impact.
Reach a live instance and the vulnerable route
Student Management System 1.0 instance and reach functionality that calls showSubject1 in /config/DbFunction.php. In practice this is usually done with manual browsing, Burp Suite, or a simple crawler against the admin workflow rather than mass internet exploitation tooling.- A real deployment of code-projects Student Management System 1.0 exists
- The web app is reachable from the attacker's position
- If the CNA vector is correct, the attacker also needs a valid low-privilege session or admin credentials
- This is a niche PHP project, not a mainstream enterprise platform
- Many organizations will have zero sanctioned instances
- The stock app appears admin-centric, which makes authenticated reachability plausible
Exploit sid with SQLi tooling
sqlmap, the attacker manipulates the sid parameter passed into showSubject1 until database errors, boolean differences, or time-based behavior confirm injection. NVD and VulDB both reference a public exploit/PoC, so the exploit-development burden is low.- The vulnerable endpoint is callable
- The
sidparameter reaches a SQL query without proper parameterization - The application/database stack returns enough signal for exploitation
- Custom routing or session checks may block direct access
- WAF rules and generic PHP hardening can disrupt noisy tools like
sqlmap - Database error suppression can force slower blind techniques
Read or alter application data
- The DB account used by the app has meaningful read/write rights
- Useful tables exist and are reachable from the vulnerable query path
- Shared-hosting style DB accounts are often scoped only to the app schema
- No evidence here points to built-in RCE or OS command execution
- Operational impact is usually local to one app/tenant, not domain-wide
The supporting signals.
| In-the-wild status | No confirmed active exploitation found. CISA KEV does not list this CVE, and OpenCVE's CISA ADP enrichment marks exploitation as poc, not known in-the-wild campaign use. |
|---|---|
| Public exploit / PoC | Yes. NVD and OpenCVE both reference a public GitHub Gist PoC by th4s1s. |
| EPSS | 0.00096 from the user intel block, which is roughly 0.096% 30-day exploitation probability; third-party enrichment pages place it around the low percentile range (~P21). |
| KEV status | Not KEV-listed. No CISA Known Exploited Vulnerabilities catalog entry was found for CVE-2025-0203. |
| CVSS disagreement | CNA/VulDB: 6.3 MEDIUM, PR:L. NVD enrichment: 9.8 CRITICAL, PR:N. That precondition disagreement is the whole case here. |
| Affected versions | code-projects Student Management System 1.0 is the only affected version explicitly listed in CNA/NVD data. |
| Fixed version | No vendor fixed version published. I found no authoritative patch advisory or newer safe release mapping. |
| Exposure reality | Likely narrow. This is a free PHP source-code project rather than a broadly deployed enterprise product. VulDB notes Google-dork discoverability, but I found no reliable Shodan/Censys/FOFA population data worth treating as hard exposure telemetry. |
| Disclosure timeline | Disclosed January 4, 2025. OpenCVE shows advisory activity on 2025-01-03, with NVD publication on 2025-01-04. |
| Reporter | lio346 (VulDB User) is credited in the CNA/OpenCVE record. |
noisgate verdict.
The decisive factor is the likely authenticated reachability requirement combined with a tiny real deployment population. This is a real remote SQL injection, but it does not behave like a front-of-queue enterprise exposure unless you actually run this niche PHP app and expose it to untrusted users.
Why this verdict
- Authenticated friction likely applies: the CNA vector is
PR:L, and the product's own page describes a simple admin-login workflow; that sharply undercuts NVD's later unauthenticated9.8interpretation. - Exposure population is tiny: this is a free
code-projectsPHP application, not Exchange, Citrix, or SharePoint. In a 10,000-host estate, the most common outcome is *not present at all*. - Threat telemetry is cold: no KEV listing, no observed campaign reporting, and EPSS is extremely low. Public PoC exists, but that is a weak amplifier by itself.
Why not higher?
If this were clearly unauthenticated and broadly internet-exposed, the score would move up fast because SQLi is easy to weaponize and the PoC is public. I am not giving it that bump because the most credible precondition data says PR:L, and the product itself looks narrow, low-maturity, and rarely deployed in enterprise fleets.
Why not lower?
It is still a remote SQL injection against a live web app with a public exploit reference, so dismissing it as pure noise would be sloppy. If your org actually runs this application, compromise of app data is plausible and the vulnerability merits real remediation rather than documentation-only closure.
What to do — in priority order.
- Remove internet exposure or IP-restrict the app — If this app exists, the best stopgap is to stop treating it like a public service. Put it behind VPN, campus IP allowlists, or a reverse proxy ACL; for a MEDIUM verdict there is no formal mitigation SLA, so do this at the next practical change window while you decide whether to retire the app.
- Add an authenticated DAST test for
sid— Most generic scanning will miss auth-gated routes. Build an authenticated check that exercises theshowSubject1path and thesidparameter so you can prove presence or absence across all copies of the app; for MEDIUM, there is no mitigation SLA — go straight to the 365-day remediation window and use this to scope exposure now. - Monitor web and DB logs for SQLi probing — Watch for
sidvalues containing quotes, boolean payloads, time-delay functions, orUNIONpatterns, and correlate with application sessions. This is useful immediately because public PoC means opportunistic testing is possible even if large-scale exploitation interest is low. - Retire unsupported copies — No authoritative patched version was found, which makes this more of a software hygiene problem than a patch-cadence problem. If the app is still present, replace or decommission it inside the remediation window instead of betting on a future vendor fix.
- MFA alone does not fix SQL injection; it only makes the likely
PR:Lprerequisite harder to obtain. - Unauthenticated perimeter vulnerability scans are not enough if the vulnerable route sits behind login.
- Endpoint AV/EDR on the web server may see nothing if the attack stays purely in SQL and only manipulates application data.
Crowdsourced verification payload.
Run this on the target web host or against a checked-out copy of the application source. Invoke it with a single argument pointing at the app root, for example python3 verify_cve_2025_0203.py /var/www/html/student-management-system or py verify_cve_2025_0203.py C:\xampp\htdocs\student-management-system; it only needs read access to the files.
#!/usr/bin/env python3
# verify_cve_2025_0203.py
# Heuristic verifier for code-projects Student Management System 1.0 SQLi in /config/DbFunction.php showSubject1 sid
# Exit codes:
# 0 = PATCHED
# 1 = VULNERABLE
# 2 = UNKNOWN
import os
import re
import sys
from pathlib import Path
VULN_FILE = os.path.join('config', 'DbFunction.php')
RAW_SID_PATTERNS = [
re.compile(r"\$_(GET|POST|REQUEST)\s*\[\s*['\"]sid['\"]\s*\]", re.I),
re.compile(r"\$sid\b", re.I),
]
SQL_CONCAT_PATTERNS = [
re.compile(r"select.+where.+sid.+\.(?:\s*)\$sid", re.I | re.S),
re.compile(r"select.+where.+sid\s*=\s*['\"]?\s*\$sid", re.I | re.S),
re.compile(r"query\s*\(.*\$sid", re.I | re.S),
re.compile(r"mysqli_query\s*\(.*\$sid", re.I | re.S),
]
PREPARED_PATTERNS = [
re.compile(r"->prepare\s*\(", re.I),
re.compile(r"bind_param\s*\(", re.I),
re.compile(r"bindValue\s*\(", re.I),
re.compile(r"bindParam\s*\(", re.I),
re.compile(r"execute\s*\(", re.I),
]
FUNC_PATTERN = re.compile(r"function\s+showSubject1\s*\(", re.I)
def print_result(state: str, reason: str, code: int) -> None:
print(f"{state}: {reason}")
sys.exit(code)
def find_candidate(root: Path):
direct = root / VULN_FILE
if direct.is_file():
return direct
for path in root.rglob('DbFunction.php'):
try:
rel = path.relative_to(root).as_posix().lower()
except Exception:
rel = str(path).replace('\\', '/').lower()
if rel.endswith('config/dbfunction.php'):
return path
return None
def main():
if len(sys.argv) != 2:
print("Usage: verify_cve_2025_0203.py <application_root>")
sys.exit(2)
root = Path(sys.argv[1]).resolve()
if not root.exists() or not root.is_dir():
print_result("UNKNOWN", f"Path not found or not a directory: {root}", 2)
candidate = find_candidate(root)
if not candidate:
print_result("UNKNOWN", "Could not find config/DbFunction.php under the supplied path", 2)
try:
data = candidate.read_text(encoding='utf-8', errors='ignore')
except Exception as e:
print_result("UNKNOWN", f"Could not read {candidate}: {e}", 2)
has_func = bool(FUNC_PATTERN.search(data))
has_sid = any(p.search(data) for p in RAW_SID_PATTERNS)
has_sql_concat = any(p.search(data) for p in SQL_CONCAT_PATTERNS)
has_prepare = any(p.search(data) for p in PREPARED_PATTERNS)
if has_func and has_sid and has_sql_concat and not has_prepare:
print_result("VULNERABLE", f"Found likely unsafe showSubject1/sid SQL construction in {candidate}", 1)
if has_func and has_prepare and not has_sql_concat:
print_result("PATCHED", f"showSubject1 appears to use prepared statements or no obvious raw sid concatenation in {candidate}", 0)
if has_func:
print_result("UNKNOWN", f"showSubject1 exists in {candidate}, but the code pattern was inconclusive", 2)
print_result("UNKNOWN", f"{candidate} exists, but showSubject1 was not found; version/layout may differ", 2)
if __name__ == '__main__':
main()
If you remember one thing.
Sources
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.