← Back to Feed CACHED · 2026-05-17 09:42:19 · cache_key CVE-2025-29912
CVE-2025-0198 · CWE-74 · Disclosed 2025-01-03

A vulnerability

ASSESSED — NOISGATE V0.5
Vendor
Reassessed
Verdict:
01 · The Real Story

This is a bad lock on a back-office closet, not an open front door

CVE-2025-0198 is an SQL injection in code-projects Point of Sales and Inventory Management System 1.0, specifically in /user/search_result.php via the id parameter. The vulnerable code path sits under the product's user area, and the CNA/NVD scoring already reflects PR:L, meaning the attacker needs at least low-privileged authenticated access before they can send the injected request.

The vendor's MEDIUM 6.3 is already a bit generous for enterprise prioritization, and reality pushes it lower. Yes, there is a public PoC, but the friction stack is substantial: authenticated access, a niche and lightly maintained educational PHP app, unclear internet-facing population, no KEV listing, and a very low EPSS. That makes this a real defect with local blast radius inside the application database, not a broad internet-scale emergency.

"Real bug, weak exploit economics: authenticated SQLi in a niche demo POS app is a cleanup item, not a fire drill."
02 · The Attack Path

4 steps from start to impact.

STEP 01

Get a valid low-privilege session

The attacker first needs credentials or an already established session for the POS application. In practice this means credential reuse, default/test credentials, insider misuse, or abuse after initial access. Tooling here is mundane: browser login, Burp Suite, or stolen PHP session cookies.
Conditions required:
  • Application is deployed and reachable
  • Attacker has valid low-privileged credentials or a reusable session cookie
  • Login flow is functioning
Where this breaks in practice:
  • This is authenticated remote, not unauthenticated internet RCE
  • Many real deployments of this project are lab, demo, or small-business instances rather than enterprise-standard internet services
  • If the app is internal-only, the attacker is already post-compromise or on VPN
Detection/coverage: External scanners without credentials will usually miss this. IAM logs, reverse-proxy auth logs, and unusual logins into a niche app are the best early signal.
STEP 02

Hit the injectable search endpoint

With a live session, the attacker requests /user/search_result.php?id=... and injects SQL metacharacters into id. The published PoC shows a simple boolean-based payload, and common tooling like sqlmap or Burp Repeater can automate parameter probing quickly.
Conditions required:
  • /user/search_result.php is present in the deployed build
  • The authenticated user can reach that endpoint
  • Input reaches a SQL query unsafely
Where this breaks in practice:
  • A WAF, reverse proxy rules, or ModSecurity CRS can block obvious quote/boolean payloads
  • Route-level authorization may limit which users can reach the page
  • Customized forks may have renamed or removed the endpoint
Detection/coverage: Web logs should show suspicious requests to search_result.php with quotes, tautologies, comment markers, or time-based payloads. Authenticated DAST has good coverage; unauthenticated scanning does not.
STEP 03

Enumerate and dump application data

Once injection is confirmed, sqlmap can enumerate schema objects and extract rows the application's database account can read. Impact is usually disclosure or tampering inside the POS database: users, products, customers, transactions, or supplier records.
Conditions required:
  • Database errors, boolean changes, or time-based responses are observable
  • App database account has useful read/write privileges
Where this breaks in practice:
  • The CNA marked technical impact as partial, not full system compromise
  • No evidence in the published material shows OS command execution or direct RCE
  • Least-privilege DB accounts can cap damage to only the app schema
Detection/coverage: Database auditing, slow-query logs, and web requests with classic SQLi sequences can catch this. Some EDRs will only see it indirectly through mysqld/httpd query volume, not as a clean exploit signature.
STEP 04

Abuse data for fraud or follow-on access

The practical endgame is business abuse, not instant domain takeover: dump customer and inventory data, alter sales records, or harvest application credentials for lateral movement inside the same small environment. Attackers may also chain this with other weak PHP-era admin flaws if the deployment is similarly neglected.
Conditions required:
  • Stolen data is valuable enough to the attacker
  • The instance contains real production records rather than demo data
Where this breaks in practice:
  • Blast radius is mostly confined to the POS app and its database
  • Many instances are likely throwaway labs or low-value edge deployments
  • There is no current evidence of broad campaign use
Detection/coverage: Look for abnormal export volume, mass reads, modified sales/inventory rows, and unusual authenticated access followed by repeated search endpoint hits.
03 · Intelligence Metadata

The supporting signals.

In-the-wild statusNo confirmed active exploitation in CISA KEV. CISA ADP enrichment in OpenCVE marks exploitation status as poc, not observed campaign activity.
Public PoCYes. Researcher *masamune* published a GitHub Gist showing a crafted GET request against /POS_inventory/user/search_result.php?id=....
EPSS0.00077 from the user-supplied intel, which is extremely low. Third-party tracking pages also place it in a low percentile band, reinforcing weak near-term exploit demand.
KEV statusNot listed in the CISA Known Exploited Vulnerabilities Catalog as of this assessment.
CVSS meaningCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:L means network-reachable but requires low privileges and only scores low CIA impact. That PR:L is the decisive real-world brake.
Affected versionsPoint of Sales and Inventory Management System 1.0 is the only version explicitly listed by the CNA/NVD/OSV record.
Fixed versionNo confirmed vendor-fixed release found. I found no authoritative patched version, advisory update, or distro backport.
Exposure realityThis is a niche code-projects PHP sample app with poor fingerprintability and no reliable Shodan/Censys population data located during this review. That usually means exposure exists, but not at the scale of mainstream enterprise software.
Disclosure timelineDisclosed 2025-01-03. VulDB/OpenCVE timeline shows advisory disclosure and public record creation on the same date.
Reportermasamune (VulDB User) is credited in the CNA/OpenCVE record.
04 · The Call

noisgate verdict.

Final Verdict
DOWNGRADED to LOW (3.6/10)

The decisive factor is authenticated access: this bug starts after the attacker already has a valid session, which makes it post-initial-access in many real environments. Add the niche deployment footprint, no KEV, and tiny EPSS, and this lands as low-priority patch debt rather than a top-of-queue incident driver.

HIGH Authenticated-access requirement materially lowers enterprise urgency
MEDIUM Blast radius is mostly constrained to the application database
MEDIUM Internet exposure population is likely small but not directly measurable from reliable census data

Why this verdict

  • Start at 6.3, then subtract for attacker position: PR:L means the exploit chain begins with authenticated remote access, not cold-start internet compromise.
  • Subtract again for exposure population: this is a niche, educational PHP POS app with unclear enterprise footprint, so the reachable population is far narrower than a mainstream edge product.
  • Subtract for threat reality: public PoC exists, but KEV is negative and EPSS is extremely low, which says attackers are not broadly prioritizing this bug.
  • Keep it above IGNORE because it is still SQLi: once logged in, an attacker can likely read or alter app data with low friction.

Why not higher?

There is no evidence of unauthenticated exploitation, no evidence of RCE, and no evidence of active campaigns. Requiring a valid session means modern controls like MFA, VPN gating, SSO, and basic network segmentation can remove most of the practical risk before the vulnerable code is ever reached.

Why not lower?

This is still a genuine SQL injection with a published PoC against a live endpoint. If you do expose this app externally or if an attacker already has credentials, data theft and record tampering inside the POS database are plausible and cheap.

05 · Compensating Control

What to do — in priority order.

  1. Pull it off the internet — If any instance is externally reachable, put it behind VPN, an internal reverse proxy, or an allowlist. For a LOW verdict there is no noisgate mitigation SLA; treat this as backlog hygiene, but do it promptly on any internet-facing instance because exposure matters more than the raw CVSS here.
  2. Gate access with strong auth — Enforce SSO, MFA where possible, and remove shared/default accounts so attackers cannot satisfy the PR:L prerequisite cheaply. For LOW, there is no formal mitigation SLA, but this is the highest-value control because authenticated access is the whole exploit hinge.
  3. Add a targeted WAF rule — Create parameter-specific blocking or normalization for /user/search_result.php and the id parameter, including quotes, comment markers, boolean tautologies, and time-delay payloads. This is a good stopgap when no confirmed vendor patch exists.
  4. Audit app database privileges — Reduce the web app's database account to the minimum read/write scope needed by the POS workflow. That will not fix the injection, but it can turn a full schema dump into a smaller disclosure event.
  5. Retire or replace the app — This project shows signs of being old, educational, and lightly maintained. Since no authoritative fixed version was found, the durable answer is replacement or internal-only containment rather than waiting for a mature patch stream.
What doesn't work
  • A generic perimeter AV product does not stop authenticated SQL injection over normal HTTP requests.
  • Patch prioritization based only on the word critical in the description will overreact; the vendor/CNA score and the real attack preconditions matter more here.
  • Credential rotation alone is insufficient if the app remains externally reachable with weak role separation and no request filtering.
06 · Verification

Crowdsourced verification payload.

Run this on the web server or a source checkout of the application, not from an auditor workstation. Invoke it with the application root path, for example python3 verify_cve_2025_0198.py /var/www/html/PISP or py verify_cve_2025_0198.py C:\xampp\htdocs\PISP; it only needs read access to the application files.

noisgate-verify.py
PYTHONREAD-ONLYSAFE
#!/usr/bin/env python3
# verify_cve_2025_0198.py
# Detect likely vulnerable code-projects Point of Sales and Inventory Management System 1.0 SQLi
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN

import os
import re
import sys

TARGET_REL = os.path.join('user', 'search_result.php')

SQL_PATTERNS = [
    re.compile(r"select\s+.*from", re.I | re.S),
    re.compile(r"mysql_query\s*\(", re.I),
    re.compile(r"mysqli_query\s*\(", re.I),
    re.compile(r"->query\s*\(", re.I),
    re.compile(r"prepare\s*\(", re.I),
]

ID_PATTERNS = [
    re.compile(r"\$_GET\s*\[\s*['\"]id['\"]\s*\]", re.I),
    re.compile(r"\$_REQUEST\s*\[\s*['\"]id['\"]\s*\]", re.I),
]

SAFE_PATTERNS = [
    re.compile(r"prepare\s*\(", re.I),
    re.compile(r"bind_param\s*\(", re.I),
    re.compile(r"intval\s*\(\s*\$_(?:GET|REQUEST)\s*\[\s*['\"]id['\"]\s*\]\s*\)", re.I),
    re.compile(r"\(int\)\s*\$_(?:GET|REQUEST)\s*\[\s*['\"]id['\"]\s*\]", re.I),
    re.compile(r"filter_input\s*\(\s*INPUT_GET\s*,\s*['\"]id['\"]\s*,\s*FILTER_VALIDATE_INT", re.I),
]


def print_result(state, msg, code):
    print(f"{state}: {msg}")
    sys.exit(code)


def main():
    if len(sys.argv) != 2:
        print("Usage: python3 verify_cve_2025_0198.py <app_root>")
        sys.exit(2)

    root = sys.argv[1]
    target = os.path.join(root, TARGET_REL)

    if not os.path.exists(root):
        print_result("UNKNOWN", f"Application root not found: {root}", 2)

    if not os.path.isfile(target):
        print_result("UNKNOWN", f"Target file not found: {target}", 2)

    try:
        with open(target, 'r', encoding='utf-8', errors='ignore') as fh:
            data = fh.read()
    except Exception as e:
        print_result("UNKNOWN", f"Could not read {target}: {e}", 2)

    has_id_source = any(p.search(data) for p in ID_PATTERNS)
    has_sql = any(p.search(data) for p in SQL_PATTERNS)
    has_safe = any(p.search(data) for p in SAFE_PATTERNS)

    concatenates_id = False
    if has_id_source:
        concatenates_id = bool(re.search(r"(id\s*=\s*\$_(?:GET|REQUEST)\s*\[\s*['\"]id['\"]\s*\])", data, re.I)) or \
                         bool(re.search(r"\.(\s*\$id\s*)", data)) or \
                         bool(re.search(r"where\s+.*id.*(\$id|\$_GET\s*\[\s*['\"]id['\"]\s*\])", data, re.I | re.S))

    if has_id_source and has_sql and not has_safe and concatenates_id:
        print_result("VULNERABLE", f"{target} appears to use request parameter 'id' in SQL without clear parameterization or integer validation", 1)

    if has_id_source and has_safe:
        print_result("PATCHED", f"{target} contains signs of integer validation or prepared statements for 'id'", 0)

    print_result("UNKNOWN", f"{target} exists but the script could not conclusively prove vulnerable or patched logic", 2)


if __name__ == '__main__':
    main()
07 · Bottom Line

If you remember one thing.

TL;DR
Monday morning, do not let this displace genuinely exposed unauthenticated bugs. First, identify whether you even run this niche POS app; if yes, confirm whether any instance is internet-facing and, if so, move it behind VPN or an allowlist as immediate hygiene. Because the reassessed verdict is LOW, there is no noisgate mitigation SLA and noisgate remediation SLA says treat it as backlog hygiene rather than an emergency; if you keep the app, document exposure, add request filtering, and schedule replacement or source-level remediation in normal backlog. If you find an external production instance with real customer data, tighten access the same day even though the overall bucket stays LOW.

Sources

  1. NVD CVE-2025-0198
  2. OpenCVE record for CVE-2025-0198
  3. GitHub Gist PoC by masamune
  4. code-projects product page
  5. CISA Known Exploited Vulnerabilities Catalog
  6. FIRST EPSS overview
  7. OSV record for CVE-2025-0198
  8. INCIBE-CERT summary
Peer Review

What defenders are saying.

Submit a review attribution: handle + country only
0 flags selected · stored anonymously
Validation Results

Crowdsourced verification outputs.

Results submitted by users who ran the verification payload against their environment.