This is a cash-register backdoor that only opens after someone already has a store badge
CVE-2025-0200 is an SQL injection flaw in code-projects Point of Sales and Inventory Management System 1.0, specifically /user/search_num.php. The CNA/NVD description says the vulnerable argument is search, while the public PoC uses the name POST field with a valid PHPSESSID; either way, the issue is the same: user-controlled input is fed into SQL without safe parameterization. The product page describes a login-driven PHP/XAMPP app with user, supplier, and admin roles, so this is not a clean unauthenticated edge bug.
Vendor MEDIUM 6.3 is a fair technical baseline, but it is still too hot for patch triage at enterprise scale. The real-world brakes are strong: the bug needs authenticated access, hits a niche training/sample-code PHP app that is commonly run on localhost/XAMPP, has only partial CIA impact, and there is no evidence here of broad internet exploitation or KEV status. Public PoC code keeps it from being ignorable, but this is post-auth app abuse, not a fleet emergency.
4 steps from start to impact.
Get a valid low-privilege session
Burp Suite to capture requests after login. The product documentation explicitly describes a login system and role-based use by user, supplier, and admin accounts, which makes this a post-auth application flaw rather than a pre-auth perimeter issue.- Reachability to the PHP app over HTTP/HTTPS
- A valid user/customer/supplier account or another way to obtain one
- The target is actually running the vulnerable
1.0codebase
- Authenticated access is required, which implies prior compromise, weak registration controls, credential reuse, or insider access
- This app appears to be commonly deployed as XAMPP/WAMP sample code, often not internet-exposed
- SSO/MFA/front-door controls can prevent this step entirely if the app is federated or access-restricted
Replay the vulnerable search request
Burp Repeater or a raw HTTP client, the attacker sends the public PoC request to /user/search_num.php with an injected search value such as the Masamune gist payload. This abuses unsafe SQL construction inside the search feature and turns a normal product lookup into a database query primitive.- Authenticated session cookie such as
PHPSESSID - Access to the
/user/search_num.phpendpoint - No local code hardening or WAF rule blocking obvious SQLi strings
- The endpoint may only be reachable after app navigation and session setup
- Basic WAF rules or mod_security-style signatures may catch trivial boolean-based payloads
- Some operators may have locally modified the sample code
' or 1=1--. App logs may show unusual POST bodies to /user/search_num.php.Turn the bug into data extraction
sqlmap or manual boolean/time-based probing to enumerate tables and pull application data. Because the vulnerable feature is a search workflow, exploitation is most likely to land in the app's own MySQL data rather than directly delivering code execution.- The backend database account has read access to useful tables
- Responses are distinguishable enough for boolean-, error-, or time-based extraction
- DB permissions may be limited to the application schema only
- Blind extraction is slower and noisier than error-based SQLi
- Rate limits, query timeouts, and WAF anomaly scoring can break automation
sqlmap-style request cadence, repeated UNION/boolean probes, and DB slow-query spikes are good signals.Abuse stays mostly inside the app blast radius
- Interesting data exists in the schema
- Credentials stored in the app are weakly protected or reused elsewhere
- No evidence in the cited material that this bug yields OS command execution
- Password hashes may be non-plaintext and not reusable
- Lateral movement requires separate weaknesses after the DB compromise
The supporting signals.
| In-the-wild status | No KEV listing and no cited campaign reporting in the sources reviewed. CISA ADP's SSVC enrichment marks Exploitation: poc, Automatable: no, Technical Impact: partial. |
|---|---|
| Public exploit / PoC | Yes. Researcher Masamune published a GitHub Gist with a working authenticated POST example against /user/search_num.php. |
| EPSS | 0.00086 from the prompt, which is extremely low in practical prioritization terms. The cited primary sources here do not expose a precise percentile for this CVE. |
| KEV status | Not listed in CISA's Known Exploited Vulnerabilities Catalog. |
| CVSS vector meaning | CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:L means remote and easy to hit, but requires privileges and only scores low impact across confidentiality, integrity, and availability. |
| Affected versions | Authoritative records list Point of Sales and Inventory Management System 1.0 as affected. |
| Fixed version / backports | No public patched version or distro backport was identified in the cited references. Treat this as no vendor patch clearly published rather than assuming a fixed build exists. |
| Exposure / scanning reality | No trustworthy product-specific GreyNoise/Shodan/Censys exposure telemetry surfaced in the reviewed sources. *Inference:* exposure is probably limited because the vendor instructions center on XAMPP/WAMP localhost deployment and the project reads like sample or student code, not a mainstream enterprise package. |
| Disclosure timeline | The CVE record shows disclosure/publication on 2025-01-03; some third-party pages display 2025-01-04 depending on indexing/timezone. NVD shows last modification on 2025-02-25. |
| Reporter | Credited reporter is masamune (VulDB User). |
noisgate verdict.
The decisive factor is authenticated access required against a niche PHP sample app that is probably not broadly internet-exposed. This is a real SQLi, but it is mostly a post-initial-access or mis-exposed-lab problem with a narrow blast radius, not a fleet-wide enterprise fire drill.
Why this verdict
- Start at vendor 6.3 MEDIUM: technically fair for remote SQLi, but that baseline assumes the target is meaningfully exposed and reachable
- Downgrade for attacker position:
PR:Lmeans the attacker needs a valid session first; that implies prior access, weak account controls, or insider status before the SQLi even matters - Downgrade for exposure population: this is a small PHP/XAMPP source-code project, not a common enterprise platform, so the reachable population is likely tiny compared with products that justify aggressive internet-facing patch SLAs
- Downgrade for impact ceiling: available scoring and CISA ADP both point to partial impact and no automation; there is no evidence here of pre-auth takeover or direct RCE
- Slight uplift for exploitability evidence: there is a public PoC gist, so defenders should not dismiss it as purely theoretical if they actually run this app
Why not higher?
To score higher, this would need one of the usual amplifiers: unauthenticated reachability, strong evidence of internet exposure at scale, active exploitation, or code execution. Instead, the chain begins with a login requirement and appears to end in application-database abuse, which sharply narrows both attacker population and business blast radius.
Why not lower?
It is still a genuine SQL injection with a public PoC, not a paper cut. If an organization really does expose this app and allows broad user access, a low-privileged account can likely read or tamper with application data, so IGNORE would be too complacent.
What to do — in priority order.
- Remove public exposure — If this app is reachable from the internet, move it behind VPN, IP allowlisting, or an internal reverse proxy. For a LOW verdict there is no noisgate mitigation SLA; treat this as backlog hygiene, but do it promptly if the app is externally exposed because exposure is the main amplifier.
- Require strong authentication — Reduce the chance that a commodity attacker can satisfy the
PR:Lprerequisite. Use unique local accounts at minimum, and if this app matters operationally, front it with SSO/MFA; LOW has no formal mitigation SLA, so this is risk reduction rather than an emergency control. - Add a WAF SQLi rule set — Basic SQLi signatures can block the simple public PoC and slow down
sqlmap, especially on legacy PHP apps you cannot quickly fix. This is not a substitute for code remediation, but it buys coverage while the issue sits in backlog hygiene. - Constrain DB privileges — Ensure the PHP application's DB account has only the minimum rights needed for the app schema and nothing broader. That limits the blast radius if exploitation occurs and is especially useful where no vendor-fixed version is clearly available.
- Monitor authenticated search endpoints — Alert on SQLi markers, abnormal POSTs to
/user/search_num.php, andsqlmap-like probing patterns. With a LOW verdict there is no SLA-driven mitigation window, so detection is your main short-term safety net if the app must stay online.
- Endpoint AV/EDR on the web server does not reliably stop SQLi against PHP code, because the attack lives in normal web and database traffic.
- Changing only passwords does not fix the vulnerable query path; it merely makes Step 1 harder.
- Banner hiding or obscuring the app name does not matter once an attacker has a session and can reach the vulnerable endpoint.
Crowdsourced verification payload.
Run this on the target web server or on a workstation that has filesystem access to the deployed app directory. Invoke it as python3 verify_cve_2025_0200.py /var/www/html/POS_inventory or py verify_cve_2025_0200.py C:\xampp\htdocs\POS_inventory; no admin rights are required unless the files are permission-restricted.
#!/usr/bin/env python3
# verify_cve_2025_0200.py
# Heuristic verifier for CVE-2025-0200 in code-projects Point of Sales and Inventory Management System 1.0
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN
import os
import re
import sys
TARGET_REL = os.path.join('user', 'search_num.php')
def println(msg):
sys.stdout.write(msg + '\n')
def main():
if len(sys.argv) != 2:
println('UNKNOWN')
sys.exit(2)
base = sys.argv[1]
target = os.path.join(base, TARGET_REL)
if not os.path.isfile(target):
println('UNKNOWN')
sys.exit(2)
try:
with open(target, 'r', encoding='utf-8', errors='ignore') as fh:
data = fh.read()
except Exception:
println('UNKNOWN')
sys.exit(2)
lower = data.lower()
# Signals of parameterized queries / safer handling
patched_signals = [
'->prepare(',
'mysqli_prepare(',
'bind_param(',
'bindparam(',
'bindvalue(',
'execute(['
]
# Signals of direct use of user input in a SQL string
vuln_input_signals = [
"$_post['name']",
'$_post["name"]',
"$_post['search']",
'$_post["search"]',
'$search',
'$name'
]
sql_signals = ['select ', ' from ', ' where ', ' like ', 'mysqli_query(', 'query(']
has_patched = any(s in lower for s in patched_signals)
has_input = any(s in lower for s in vuln_input_signals)
has_sql = any(s in lower for s in sql_signals)
# Look for likely concatenation/interpolation into SQL
concat_patterns = [
r"select.+\$search",
r"select.+\$name",
r"like\s*['\"]?%?\s*\.\s*\$search",
r"like\s*['\"]?%?\s*\.\s*\$name",
r"mysqli_query\s*\(.+select",
r"query\s*\(.+select"
]
has_concat_pattern = any(re.search(p, lower, re.DOTALL) for p in concat_patterns)
if has_patched and not has_concat_pattern:
println('PATCHED')
sys.exit(0)
if has_sql and (has_input or has_concat_pattern) and not has_patched:
println('VULNERABLE')
sys.exit(1)
println('UNKNOWN')
sys.exit(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.