BACK TO SEARCH
gulesakeena-svg/remote-mcp-servercritical

A remote mcp server

This MCP server provides a remote expense tracking system with CRUD operations for expenses, budgets, recurring expenses, and savings goals. It includ...

purpose: This MCP server provides a remote expense trackingthreat: network exposed
Python · 0 · May 21, 2026 · May 21, 2026 · GITHUB ↗
RISK SCORE
0/ 100 risk
high findings+75
medium findings+30
capped at100
VULNERABILITY ANALYSIS · 5 findings in 5 blocks3 HIGH · 2 MEDIUM
HIGH1 finding
main.py:544
544@mcp.tool()
545async def export_data_csv(path: str, start_date: Optional[str] = None, end_date: Optional[str] = None) -> Dict[str, Any]:
546    """Export expenses to a CSV file path. Overwrites if exists."""
547    ...
548    with open(path, "w", newline="", encoding="utf-8") as f:
549        writer = csv.writer(f)
550        writer.writerow(["id", "date", "amount", "category", "subcategory", "note"])
551        writer.writerows(rows)
552    return {"status": "ok", "exported_rows": len(rows), "path": path}
main.py:544

// Network-exposed MCP server; any client can call this tool.

EXPLAINThe export_data_csv tool accepts an arbitrary file path and writes CSV data to it without any validation or sanitization. An attacker can overwrite any file the server process has write access to, including configuration files, application code, or system files.
IMPACTAn attacker could overwrite critical files, potentially leading to code execution, denial of service, or data corruption. For example, overwriting a Python file that gets imported could lead to arbitrary code execution.
FIXRestrict the output path to a dedicated export directory (e.g., a subdirectory of TEMP_DIR). Validate that the resolved path is within the allowed directory. Use os.path.realpath to prevent path traversal.
HIGH1 finding
main.py:564
564@mcp.tool()
565async def import_data_csv(path: str) -> Dict[str, Any]:
566    """Import CSV into expenses table. Expects columns: date, amount, category, subcategory, note (id optional)."""
567    added = 0
568    try:
569        async with aiosqlite.connect(DB_PATH) as c:
570            with open(path, "r", encoding="utf-8") as f:
571                reader = csv.DictReader(f)
572                for row in reader:
573                    ...
574        return {"status": "ok", "imported_rows": added, "path": path}
575    except Exception as e:
576        return {"status": "error", "message": str(e)}
main.py:564

// Network-exposed MCP server; any client can call this tool.

EXPLAINThe import_data_csv tool accepts an arbitrary file path and reads its contents. An attacker can read any file the server process has access to, including sensitive files like /etc/passwd, SSH keys, or application secrets. The error message may also leak information about the file's existence or content.
IMPACTAn attacker could read sensitive files, leading to credential theft, information disclosure, or further system compromise.
FIXRestrict the input path to a dedicated import directory. Validate that the resolved path is within the allowed directory. Use os.path.realpath to prevent path traversal.
HIGH1 finding
main.py:544
544@mcp.tool()
545async def export_data_csv(path: str, ...):
546    ...
547    with open(path, "w", ...) as f:
548        ...
549
550@mcp.tool()
551async def import_data_csv(path: str) -> Dict[str, Any]:
552    ...
553    with open(path, "r", ...) as f:
554        ...
main.py:544main.py:564

// Network-exposed MCP server; any client can call this tool.

EXPLAINBoth export and import tools accept a user-supplied path without any validation. An attacker can use path traversal sequences like '../' to write or read files outside the intended directory, potentially accessing or overwriting sensitive system files.
IMPACTCombined with the arbitrary file write/read, an attacker can traverse directories to access or modify files anywhere on the filesystem.
FIXResolve the path using os.path.realpath and ensure it starts with the allowed base directory. Reject paths containing '..' or symbolic links that escape the base.
MEDIUM1 finding
main.py:666
666if __name__ == "__main__":
667    mcp.run(transport="http", host="0.0.0.0", port=8000)
main.py:666

// Network-exposed MCP server; no authentication required.

EXPLAINThe MCP server listens on all network interfaces (0.0.0.0) on port 8000 with no authentication mechanism. This exposes all CRUD operations to anyone who can reach the server, allowing unauthorized access to financial data and file system operations.
IMPACTAny attacker on the network can add, modify, delete expenses, read/write arbitrary files, and access sensitive financial data without any authentication.
FIXBind to localhost (127.0.0.1) if remote access is not required, or implement authentication (e.g., API key, OAuth) before exposing to the network.
MEDIUM1 finding
main.py:104
104@mcp.tool()
105async def add_expense(date: str, amount: float, category: str, subcategory: str = "", note: str = "") -> Dict[str, Any]:
106    date = parse_date(date)
107    try:
108        async with aiosqlite.connect(DB_PATH) as c:
109            cur = await c.execute(
110                "INSERT INTO expenses(date, amount, category, subcategory, note) VALUES (?,?,?,?,?)",
111                (date, float(amount), category, subcategory or "", note or "")
112            )
main.py:104

// Network-exposed MCP server; any client can call this tool.

EXPLAINThe category, subcategory, and note fields are accepted as arbitrary strings without any validation. While parameterized queries prevent SQL injection, there is no length restriction, character filtering, or validation against allowed categories. This could allow storing excessively long strings or unexpected data that might cause issues in reports or exports.
IMPACTAn attacker could insert very long strings causing denial of service in reports, or inject special characters that break CSV exports (e.g., formulas in Excel).
FIXValidate category against a whitelist of allowed categories. Limit string lengths. Sanitize or escape special characters for CSV export.
5/21/2026
Findings are produced by automated LLM analysis and may include false positives or miss issues. Verify independently before acting.