dsh-reprolab Security Model
August 16, 2026 · View on GitHub
Applies to DSH 0.1.0-rc.6. Design authority: design spec §10; repository rules
AGENTS.md§9.
Threat model
ReproLab runs inside a developer's repository, spawns test processes and writes evidence files. The realistic adversaries are: malicious/erroneous repository content (paths, symlinks, patches), a hostile model-supplied test command, and accidental credential leakage into evidence. ReproLab does not defend against a malicious host process or a compromised filesystem.
Guarantees and mechanisms
| # | Requirement (spec §10) | Mechanism | Verified by |
|---|---|---|---|
| 1 | Resolve real paths before boundary checks | assertPathInsideRepo: lexical containment + realpath of the deepest existing ancestor | realpath boundary checks |
| 2 | No writes outside allowed boundaries via symlinks | same realpath check on every declared path, included file and cleanup target | realpath checks on every declared path |
| 3 | argv arrays only | GitClient/CommandRunner consume SubprocessSpawnSpec.argv (never shell-interpreted); shell metacharacters pass through as data | argv pass-through verified with shell metacharacters |
| 4 | Scrubbed child environment | official scrubbedParentEnv (strips KEY/PASSWORD/SECRET/TOKEN and all DSH_*); explicit env merges after the scrub | scrubbed base verified with a DSH_-prefixed sentinel |
| 5 | Output redaction | deterministic Redactor (Authorization/Bearer, token/secret/password/cookie assignments, PEM blocks, JWT, ghp_/AKIA, high-entropy strings, forwarded env literals); applied to in-memory tail, spill file and report env | pattern suite + credential-shaped fixture run |
| 6 | Default: no upload, no telemetry, no network | no network code exists; pnpm audit is the only registry access and happens at build time, not runtime | code audit (no network code path) |
| 7 | No dependency auto-install | the plugin never installs packages; test commands are declared argv arrays | design + code |
| 8 | External side effects disclosed, not silently performed | network: boolean disclosure flag on command specs; no tool writes outside runDir | README side-effect list |
| 9 | Never modify the user's branch | no reset --hard, no checkout/clean on the user tree; worktrees are detached and owned; ownership markers in the gitdir | HEAD/branch/status unchanged after runs |
| 10 | Explicit, ownership-checked cleanup | triple check (managed dir + runId basename, git worktree registration, gitdir marker) before worktree remove | tampered-marker refusal verified |
State and lock integrity
state.jsonis a versioned envelope with a SHA-256 integrity hash over the canonical payload; readers reject any tampering (STATE_CORRUPTED).- Every write goes through the per-repository write lock; locks record repo path, runId, pid, hostname, startedAt and a unique lockId. An expired lock is stolen only when the owner process is confirmed dead; a cross-host lock is never broken blindly (
LOCK_OWNER_UNVERIFIABLE). - Revision is strictly monotonic; a write below the persisted revision is rejected (
REVISION_REGRESSION).
Data written and its sensitivity
| Path | Content | Sensitivity handling |
|---|---|---|
runs/<run-id>/state.json | state + evidence fields + command declarations | integrity-signed; env values in commands may include caller-provided entries |
runs/<run-id>/test.patch / fix.patch / baseline.patch | diffs of the repository | local only; never uploaded |
runs/<run-id>/report.json / report.md | redacted evidence model | env values with secret-shaped keys redacted |
logs/ equivalent (spill files) | full command output | rewritten through the same redactor |
| worktree gitdir marker | runId | no secrets |
What is NOT protected (documented limitations)
- Env values under ordinary (non-secret-shaped) keys are recorded verbatim in
state.jsoncommands and redacted only from output text — callers must not forward secrets under innocuous names. - The runtime-artifact allowlist (
__pycache__,.pyc, …) means a malicious repo could hide changes inside those names; they are excluded from change detection by design (test-runner artifacts), not treated as evidence. - Redaction is heuristic pattern matching, not information-flow tracking; a secret in an unanticipated shape may pass through.
- The plugin trusts the repository's own git objects; a malicious
.gitdirectory is out of scope.
Supply chain
Production dependencies (4): @deepseek-ai/dsh-brand, @deepseek-ai/dsh-subprocess, @deepseek-ai/dsh-tools (all pinned to the host line 0.1.0-rc.6), @deepseek-ai/schemastery (MIT). pnpm audit --prod reports no known vulnerabilities; the lockfile passes pnpm's supply-chain policies on every install. Build scripts of transitive packages (node-pty, terminal primitive only) are explicitly denied (pnpm-workspace.yaml).