Skip to content

coding-standards-mcp Template Escape via get_style_guide #68

Description

@wing3e

coding-standards-mcp Template Escape via get_style_guide

1) CNA / Submission Type

  • Submission type: Report a vulnerability (CVE ID request)
  • Reporter role: Independent security researcher
  • Report date: April 14, 2026

2) Reporter Contact (fill before submit)

  • Reporter name: Winegee
  • Reporter email: Winegee@zju.edu.cn
  • Permission to share contact with vendor: Yes

3) Vendor / Product Identification

  • Vendor: ggerve
  • Product: coding-standards-mcp
  • Repository: https://github.com/ggerve/coding-standards-mcp.git
  • Reviewed local source path: python-batch-04/datasets/ggerve-coding-standards-mcp
  • Confirmed affected tools: get_style_guide, get_best_practices
  • Reviewed source file: server.py

4) Vulnerability Type

  • CWE: CWE-22 / CWE-73 (Path Traversal / External Control of File Name or Path)
  • Short title: The language argument is interpolated into a template filename and opened from templates/ without canonicalization, allowing traversal to read matching files outside the template directory.

5) Affected Versions

  • Confirmed affected: c21ab2754684329eab4feb72427dc9acfe61e52f
  • Suspected affected range: revisions containing the same read_template() implementation in server.py
  • Fixed version: Not available at time of report (April 14, 2026)

6) Vulnerability Description

The server is supposed to serve Markdown templates from its bundled templates directory. Instead, both exported tools construct filenames from untrusted language input and pass them into read_template():

  • get_style_guide(language) builds f"{language}_style_guide.md"
  • get_best_practices(language) builds f"{language}_best_practices.md"

read_template() then does os.path.join(os.path.dirname(__file__), "templates", filename) and opens the resulting path directly. Because neither the input nor the resolved path is validated, traversal strings such as ../../../../tmp/secret escape templates/ and read files like /tmp/secret_style_guide.md.

7) Technical Root Cause

  1. server.py:64-70
    • The exposed tools derive a filename from untrusted language input.
  2. server.py:23-25
    • read_template() joins that filename under templates/ and immediately executes with open(template_path, "r") as f:.
  3. Audit conclusion
    • This is a real path traversal, but the reachable file set is constrained by the suffixes the tool appends (_style_guide.md and _best_practices.md).

8) Attack Prerequisites

  • The attacker can call get_style_guide or get_best_practices.
  • A readable target file exists on disk with one of the expected suffixes.

9) Proof of Concept / Reproduction Guidance

  1. Create a readable file outside the repository, for example /tmp/secret_style_guide.md.
  2. Invoke the MCP tool with a traversal payload:
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "get_style_guide",
    "arguments": {
      "language": "../../../../tmp/secret"
    }
  }
}
  1. Expected result
  • The returned text is the content of /tmp/secret_style_guide.md, not a bundled template from templates/.

10) Security Impact

  • Confidentiality: Medium. The primitive is limited to files whose names match the expected suffix pattern.
  • Integrity: None directly from the confirmed primitive.
  • Availability: None or negligible.
  • Scope: Unchanged.

11) CVSS v3.1 Suggestion

  • Suggested vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N
  • Suggested base score: 5.3 (Medium)

12) Workarounds / Mitigations

  • Restrict language to a fixed allowlist such as java, python, and react.
  • Resolve the final path and enforce that it stays inside the templates directory.
  • Reject path separators and traversal tokens in template selectors.

13) Recommended Fix

  • Replace free-form language input with an enum or map of known template names.
  • If free-form input must remain, validate with a strict regex and then verify the resolved path is under templates/.
  • Add regression tests for payloads containing /, \\, and ...

14) References

15) Credits

  • Discoverer: Winegee
  • Discovery method: Static analysis (CodeQL) plus local source-code audit

16) Additional Notes for Form Mapping

  • Audit verdict: Confirmed vulnerability.
  • Total reviewed SARIF results for this repository/rule group: 1
  • Dynamic exploit replay status: not completed in this pass.
  • The practical limitation is filename suffix control, not full arbitrary pathname control.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions