Security
August 14, 2026 ยท View on GitHub
Trust Model
The DSRH Bundle is trusted profile configuration. The official MCP client starts the configured Python executable outside a model shell call, so Harness shell sandboxing does not automatically confine Python filesystem or network access. DSRH applies independent workspace and network policy inside the sidecar. Harness remains the authority for Agent filesystem and command execution.
Filesystem
Every user-supplied local path resolves against DSRH_WORKSPACE_ROOT, follows symlinks to its final target, and must remain within the canonical root. Existing inputs require real files or directories. Prospective outputs canonicalize every existing path component before creation, including symlinked artifact roots, while still allowing new nested directories. Tests cover .., absolute escape, and symlink escape across manifest, metrics, paper, and citation paths.
PDF size defaults to 100 MiB. Downloads stream into a bounded buffer. PyMuPDF parses born-digital documents without OCR or embedded-script execution. Malformed, encrypted, oversized, and scan-only documents produce explicit domain states.
Network
The sidecar builds provider URLs itself. Metadata endpoints are fixed to Crossref, OpenAlex, and arXiv; PDF download hosts are fixed to arxiv.org and export.arxiv.org over HTTPS. Redirects are disabled, metadata responses are limited to 5 MiB, timeouts and bounded retries apply, and HTTP 429 remains a structured failure. DSRH does not scrape Google Scholar, follow DOI redirects to publishers, or fetch arbitrary claim-support full text.
Commands
No MCP tool accepts or executes an arbitrary command. The native command renderer returns {command, executed:false}. Experiment execution must cross the existing Harness shell pipeline, including tools/pre-execute, monotonic guards, sandbox, approval, and job ownership. DSRH never uses os.system, never calls subprocess.Popen for training, and never exposes delete, process-kill, Git push, or shell tools.
The toy E2E test uses Python subprocess.run with a fixed repository-owned argv vector solely to exercise fixture metric collection; this code is outside dsrh_mcp, is not packaged, and accepts no model output.
Data and Credentials
Logs go to stderr and contain error types rather than request headers or secrets. DSRH does not read model credentials and does not inline DEEPSEEK_API_KEY. Citation cache files may contain public scholarly metadata. Reports and experiment provenance can contain project-sensitive information; repository owners decide what to commit.
Threat Review
| Threat | Control |
|---|---|
| Path or symlink escape | Canonical containment checks before reads and writes |
| Command injection | No MCP execution; typed argv rendered for later Harness-controlled execution |
| Malicious or large PDF | Size bound, native parser error mapping, no OCR, no active content execution |
| Malformed BibTeX/YAML/JSON | Bounded parsers, Pydantic validation, structured domain errors |
| SSRF and redirects | Fixed provider/host allowlists and redirects disabled |
| Unbounded downloads | Streaming byte cap and timeout |
| Provider 429/timeout | Structured visible status and bounded retry |
| Credential logging | No auth/header/token logging |
| Plugin boot side effects | Runtime registers effects only; sidecar store opens lazily after MCP calls |
| Arbitrary subprocess | No production subprocess call in the Python package |
| Failed experiment suppression | Aggregator reports requested, successful, failed, and missing runs |