This is a sharp kitchen knife left in a back office, not a grenade in the lobby
CVE-2025-0208 is a SQL injection in code-projects Online Shoe Store 1.0, specifically summary.php via the tid parameter. The public write-up shows $_GET['tid'] flowing straight into a SQL query against the transaction table, which means a low-privileged user who can reach that page can likely read or alter application data; if the MySQL account is overprivileged, a deeper pivot is possible. The affected version range published by the CNA is only 1.0, and I could not find a vendor-fixed release or patch stream.
The vendor/CNA MEDIUM 6.3 is closer to reality than NVD's 9.8. The decisive issue is attacker position: the CNA scores this as PR:L, and the available exploit narrative lines up with an authenticated application flow rather than a clean unauthenticated edge exploit. Add the fact that this is a downloadable PHP project/demo app with uncertain enterprise footprint, no KEV listing, and a tiny EPSS, and this lands as LOW priority in a 10,000-host patch queue unless you knowingly run this app internet-facing.
4 steps from start to impact.
Get a valid session
PR:L, and the project page shows a normal login/sign-up flow, so the attacker likely needs to authenticate or at least reach a user-specific transaction summary path before the vulnerable parameter matters.- Application is deployed and reachable
- Attacker can register, authenticate, or steal a user session
- The vulnerable
summary.phpflow is exposed in that deployment
- This is not modeled as unauthenticated remote by the CNA
- Many scanners never complete sign-up/login/payment flows
- Some deployments may not expose real transaction history to ordinary users
Inject through tid
$_GET['tid'] assigned to $t_id and interpolated into a SQL statement without parameterization. Tools like sqlmap can probe summary.php?tid=... once provided the right session context, cookies, and request shape.- Attacker can send crafted requests to
/summary.php - Input reaches the database query unchanged
- WAF or app-layer filtering does not normalize/block payloads
- Request replay may need cookies, referer, and a valid transaction context
- Basic WAF signatures often catch commodity SQLi probes
- If
tidis server-side ownership-checked, horizontal reach may narrow
Enumerate or tamper with the database
sqlmap can automate enumeration and dumping if the DBMS and response behavior cooperate.- DB user has enough privileges for useful reads/writes
- Application error handling or response timing leaks enough signal
- The backend is a supported DBMS configuration
- Low-impact CVSS from the CNA implies partial rather than full compromise
- Least-privileged DB accounts can sharply limit what gets exposed
- Blind-only conditions make exploitation slower and noisier
Optional pivot to filesystem or code execution
sqlmap can reach OS-shell, but that is conditional, not baseline. That only becomes plausible if the database account has dangerous file/UDF privileges and the web stack permits writing or executing attacker-controlled content.- Overprivileged database account
- Writable webroot or DB-to-OS pivot path
- Server configuration allows execution of planted content
- Most real deployments fail here because DB users are not omnipotent
- This step is exactly why NVD's blanket
9.8looks overstated - EDR, AppArmor/SELinux, and locked-down filesystem permissions can break the chain
summary.php — Enforce authenticated access plus strict object ownership checks on transaction records so a logged-in user cannot request arbitrary tid values. For a LOW verdict there is no SLA; treat this as backlog hygiene and implement in the next normal application hardening cycle.tid — Add a targeted WAF or reverse-proxy rule for summary.php that only allows the expected transaction-ID format and rejects metacharacters, comments, stacked queries, and time-delay payloads. There is no noisgate mitigation SLA for LOW; deploy during routine rule maintenance unless the app is internet-facing, in which case move faster.tid. No vendor-fixed build was found, so plan to patch your maintained codebase in the next routine remediation cycle.- MFA for administrators does not solve this if ordinary user access or self-registration is enough to hit the vulnerable endpoint.
- EDR on the web server does not stop the initial database exploitation; it only helps if the attacker later pivots to filesystem or process execution.
- Network segmentation alone does not help if the storefront is intentionally internet-facing and the vulnerable request is handled by the app itself.
The supporting signals.
| In-the-wild status | No KEV listing found, and I found no public reporting of active campaigns tied to this CVE. CISA ADP metadata visible via OpenCVE marks exploitation as poc, Automatable: no, Technical Impact: partial. |
|---|---|
| Public PoC | Yes. A public GitHub gist by th4s1s dated 2025-01-02 shows the vulnerable code path and demonstrates sqlmap-style exploitation. |
| EPSS | User-supplied EPSS is 0.00096. Secondary trackers around this CVE place it in a low percentile band (~17-21%), which is consistent with weak attacker demand. |
| KEV status | Not listed in CISA's Known Exploited Vulnerabilities catalog. |
| CVSS disagreement | CNA/VulDB says 6.3 MEDIUM with PR:L; NVD shows 9.8 CRITICAL with PR:N. The public exploit narrative and project flow fit the CNA model much better than the NVD uplift. |
| Affected range | code-projects Online Shoe Store 1.0 only, vulnerable endpoint summary.php, parameter tid. |
| Fixed version | I found no vendor-fixed version and no formal patch advisory. For defenders, assume source remediation or compensating controls only unless you maintain a private fork. |
| Exposure reality | This is a downloadable PHP project, not a mainstream enterprise product. The download page shows 12,082 downloads, so installs exist, but I found no reliable Shodan/Censys-style fingerprint proving meaningful internet exposure at scale. |
| Disclosure | CNA timeline shows disclosure on 2025-01-03; NVD published on 2025-01-04. |
| Researcher / reporter | Reported as lio346 (VulDB User) in the CNA record. |
Sources.
Why this verdict
- Start from the CNA's 6.3, not NVD's 9.8 because the published exploit context and app flow support
PR:L, not a full unauthenticated edge compromise. - Authenticated or session-bound access is the governor: needing a valid user foothold implies either self-registration, stolen cookies, or prior access, which materially narrows who can reach exploit step one.
- The target population is narrow:
code-projectsapps are downloadable sample/demo PHP projects, not broadly deployed enterprise platforms, so the reachable blast radius across a 10,000-host estate is usually tiny. - Threat demand is weak: there is a public PoC, but there is no KEV listing, no campaign evidence I could find, and EPSS is extremely low.
- Impact is usually app-local: the realistic baseline is reading or tampering with this app's data; database-to-OS pivoting is conditional on extra misconfigurations and should not be baked into the base score.
Why not higher?
If this were clearly unauthenticated and broadly internet-exposed, SQL injection would deserve a much harder response. But the strongest available evidence points the other way: low-privileged access first, niche software, partial impact modeling, and no sign that attackers actually care.
Why not lower?
I am not calling this IGNORE because it is still a real SQL injection with public exploit guidance. If your org actually runs this app exposed to the internet, especially with open self-registration and a powerful DB account, the risk becomes immediately operational even if it does not justify front-of-queue treatment across the whole estate.
Crowdsourced verification payload.
Run this on the target host or on a build artifact checkout that contains the PHP source. Invoke it with python3 check_cve_2025_0208.py /var/www/html/onl-shoe or point it directly at summary.php; it only needs read access to the source files.
#!/usr/bin/env python3
# check_cve_2025_0208.py
# Detect likely vulnerable code patterns for CVE-2025-0208 in code-projects Online Shoe Store 1.0.
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN
import os
import re
import sys
from pathlib import Path
VULN_GET_RE = re.compile(r"\$_GET\s*\[\s*['\"]tid['\"]\s*\]")
VULN_ASSIGN_RE = re.compile(r"\$\w+\s*=\s*\$_GET\s*\[\s*['\"]tid['\"]\s*\]\s*;")
VULN_QUERY_RE = re.compile(r"transaction_id\s*=\s*'\s*\$\w+\s*'", re.IGNORECASE)
SAFE_CAST_RE = re.compile(r"(intval\s*\(|\(int\)\s*\$_GET\s*\[\s*['\"]tid['\"]\s*\])", re.IGNORECASE)
PREPARED_RE = re.compile(r"(prepare\s*\(|bind_param\s*\(|PDO\s*::\s*prepare)", re.IGNORECASE)
def read_text(p: Path):
try:
return p.read_text(encoding='utf-8', errors='ignore')
except Exception:
return None
def candidate_files(target: Path):
if target.is_file():
return [target]
found = []
for p in target.rglob('summary.php'):
found.append(p)
return found
def assess_file(p: Path):
text = read_text(p)
if text is None:
return 'UNKNOWN', f'{p}: unreadable'
has_get = bool(VULN_GET_RE.search(text))
has_assign = bool(VULN_ASSIGN_RE.search(text))
has_query = bool(VULN_QUERY_RE.search(text))
has_safe_cast = bool(SAFE_CAST_RE.search(text))
has_prepared = bool(PREPARED_RE.search(text))
if has_get and has_query and not has_safe_cast and not has_prepared:
return 'VULNERABLE', f'{p}: raw tid parameter appears interpolated into SQL query'
if has_prepared or has_safe_cast:
return 'PATCHED', f'{p}: found parameterization or strict integer casting for tid'
if has_get or has_assign or has_query:
return 'UNKNOWN', f'{p}: suspicious markers found, but pattern does not conclusively match CVE-2025-0208'
return 'UNKNOWN', f'{p}: summary.php present, but expected markers were not found'
def main():
if len(sys.argv) != 2:
print('UNKNOWN - usage: python3 check_cve_2025_0208.py <path-to-app-or-summary.php>')
sys.exit(2)
target = Path(sys.argv[1])
if not target.exists():
print(f'UNKNOWN - target does not exist: {target}')
sys.exit(2)
files = candidate_files(target)
if not files:
print('UNKNOWN - no summary.php file found under target path')
sys.exit(2)
saw_patched = False
saw_unknown = False
messages = []
for f in files:
verdict, msg = assess_file(f)
messages.append(msg)
if verdict == 'VULNERABLE':
print('VULNERABLE - ' + ' | '.join(messages))
sys.exit(1)
if verdict == 'PATCHED':
saw_patched = True
if verdict == 'UNKNOWN':
saw_unknown = True
if saw_patched and not saw_unknown:
print('PATCHED - ' + ' | '.join(messages))
sys.exit(0)
if saw_patched and saw_unknown:
print('UNKNOWN - mixed results: ' + ' | '.join(messages))
sys.exit(2)
print('UNKNOWN - ' + ' | '.join(messages))
sys.exit(2)
if __name__ == '__main__':
main()