A read-only record server is not read-only by default, and five ways a mirror's own configuration could subvert a read
A Model Context Protocol server giving AI agents version-stamped, read-only access to engineering project records, and the configuration attacks found in security review after it met its acceptance criteria.
Keywords: Model Context Protocol; AI agents; git; software security; provenance; read-only access
Abstract
AI agents working on engineering projects repeatedly need exact facts from the project record: specification text, measured values and thresholds, input citations and the status of changes. We built a Model Context Protocol server that answers such queries from read-only git mirrors, with every repository-derived answer stamped with the repository version, paths and line ranges read, and with repository text marked as untrusted. The server exposes 25 tools and passed all 37 of its pre-specified acceptance criteria, including refusal of every write attempt and rejection of 720 path-escape tool calls; the slowest tool's 95th-percentile latency is 184 ms. Three subsequent security reviews nevertheless found 5 ways in which a mirror's own git configuration, which the acceptance criteria did not vary, could make a read execute a program, alter returned text, reach hidden data or misreport history. Each was fixed by fixing the relevant setting in the server's single git wrapper, with a regression test that fails on the unfixed code. Read-only access enforced at the file system does not make reads through git side-effect free; repository configuration must be treated as untrusted input.
1. Introduction
Agents assisting with engineering work need the same facts repeatedly. Searching a working copy returns whatever happens to be checked out, which may be stale or modified. The Model Context Protocol [1] provides a standard interface through which an agent can call tools that return structured answers, which makes it possible to serve project facts from a controlled source with explicit provenance.
This report describes such a server, the acceptance criteria it met, and a class of vulnerability that those criteria did not cover: configuration carried inside the git repositories it reads [2].
2. Methods
2.1 Design
The server runs locally over standard input and output; no network listener is opened. It answers from read-only git mirrors of the project repositories. Every answer derived from a repository records the mirror, the repository version, the paths and line ranges read, and the time of the last mirror refresh. Text copied from a repository is returned in fields marked untrusted, so that an agent does not treat file contents as instructions.
The server exposes 25 tools, 2 resources and 2 prompts: generic reads, logs and searches; readers for specification sections, change entries, acceptance tables, inputs and phase reports; checks for style, claim boundaries and energy basis; and steam-property and unit-conversion helpers verified against published standards [3].
2.2 Acceptance criteria
A total of 37 criteria were specified before the server was built, covering write refusal, path-escape rejection, unsafe git read paths, version stamping, untrusted-text marking, secret scanning and latency. Latency was measured over 31 calls per tool in each of two runs, taking the worse run.
2.3 Security reviews
Three review rounds, each starting from the previous candidate, built small fixture repositories with hostile git configurations and ran the server's own tools against them.
3. Results
3.1 Acceptance criteria
All 37 criteria were met. The operating system refused 2 of 2 write attempts on a mirror; 720 tool calls built from 90 path-escape cases, covering traversal, encoded traversal, absolute paths and symbolic links, were rejected (0 accepted); 69 reads through object alternates, replace references and text-conversion drivers were neutralized; 23 repository responses carried a version stamp with 0 mismatches; and all 31 responses marked repository text as untrusted. A secret scan found 615 candidate strings, each confirmed to be a public identifier, leaving 0 findings. The steam-property helpers agree with the standard across 72 properties to 2.8 × 10-9. Every tool's 95th-percentile latency is well below the limit (Figure 1).
The claim-boundary checker, which flags sentences presenting a modeled result as a national savings figure, detects 38 of 40 seeded violations on its test corpus and flags 0 of 40 compliant sentences. It is labelled as a screen and does not certify compliance.
3.2 Configuration attacks
The reviews found 5 configuration attacks (Table 1). The most serious combined a signature-verification setting with a program path, so that an ordinary history read executed that program. The subtlest exploited git's trust in a commit-graph file to describe parent relationships: a crafted file made the server's log tool omit a real entry from the history, contrary to the object store. None of these affected output on the real mirrors, which carry no such settings. Each was closed by fixing the setting in the single wrapper through which the server calls git, with a regression test that fails on the unfixed code; 11 tests were added in the first round and 5 in the second.
Table 1. Mirror-configuration attacks found in review, all fixed.
| Finding | What the configuration could do | Observed before the fix |
|---|---|---|
| F1 | A signature-checking setting could make a history read execute a program | History reads ran a planted program; a sentinel file appeared |
| F2 | Grep, log and encoding settings could reshape search and history output | Search returned column-prefixed text |
| N1 | Colour settings could insert terminal escape codes into search text | Returned text carried escape codes |
| N2 | Submodule recursion could reach a hidden object store | Search returned a file from the hidden store |
| C1 | A crafted commit-graph file could rewrite the history a log read returns | A log omitted a real commit |
4. Discussion
Read-only access was enforced at the file system, and the acceptance criteria confirmed it. A read through git, however, is a program executed under configuration that the repository itself can supply, and the criteria never varied that configuration. The reviews found what the specification had not anticipated. Tools that give AI agents access to a project record should treat the record's own configuration as untrusted input rather than as environment, and acceptance testing should be complemented by reviews that explore new attack surfaces.
5. Limitations
- Only standard input and output were built and tested; no network exposure was evaluated.
- Mirrors become stale between refreshes; answers report the refresh time, and mirrors must be refreshed on a schedule.
- The claim-boundary check is a screen: on its test corpus it missed 2 of 40 seeded violations and flagged none of 40 compliant sentences, and its error rates on other text are unknown.
- Support for the final, larger version of the model's input module requires a parser revision that has not yet been independently reviewed.
6. Conclusions
A read-only record server for AI agents met all 37 acceptance criteria, yet security review found 5 ways a repository's own git configuration could subvert a read. All were fixed. Repository configuration should be treated as untrusted input in any tool that reads through git.
References
- Anthropic. Model Context Protocol Specification. 2025.
- Git Project. git-config: Get and set repository or global options. Git Reference Manual.
- International Association for the Properties of Water and Steam. Revised Release on the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam, IAPWS R7-97(2012). 2012.