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)MechanismVerified by
1Resolve real paths before boundary checksassertPathInsideRepo: lexical containment + realpath of the deepest existing ancestorrealpath boundary checks
2No writes outside allowed boundaries via symlinkssame realpath check on every declared path, included file and cleanup targetrealpath checks on every declared path
3argv arrays onlyGitClient/CommandRunner consume SubprocessSpawnSpec.argv (never shell-interpreted); shell metacharacters pass through as dataargv pass-through verified with shell metacharacters
4Scrubbed child environmentofficial scrubbedParentEnv (strips KEY/PASSWORD/SECRET/TOKEN and all DSH_*); explicit env merges after the scrubscrubbed base verified with a DSH_-prefixed sentinel
5Output redactiondeterministic 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 envpattern suite + credential-shaped fixture run
6Default: no upload, no telemetry, no networkno network code exists; pnpm audit is the only registry access and happens at build time, not runtimecode audit (no network code path)
7No dependency auto-installthe plugin never installs packages; test commands are declared argv arraysdesign + code
8External side effects disclosed, not silently performednetwork: boolean disclosure flag on command specs; no tool writes outside runDirREADME side-effect list
9Never modify the user's branchno reset --hard, no checkout/clean on the user tree; worktrees are detached and owned; ownership markers in the gitdirHEAD/branch/status unchanged after runs
10Explicit, ownership-checked cleanuptriple check (managed dir + runId basename, git worktree registration, gitdir marker) before worktree removetampered-marker refusal verified

State and lock integrity

  • state.json is 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

PathContentSensitivity handling
runs/<run-id>/state.jsonstate + evidence fields + command declarationsintegrity-signed; env values in commands may include caller-provided entries
runs/<run-id>/test.patch / fix.patch / baseline.patchdiffs of the repositorylocal only; never uploaded
runs/<run-id>/report.json / report.mdredacted evidence modelenv values with secret-shaped keys redacted
logs/ equivalent (spill files)full command outputrewritten through the same redactor
worktree gitdir markerrunIdno secrets

What is NOT protected (documented limitations)

  • Env values under ordinary (non-secret-shaped) keys are recorded verbatim in state.json commands 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 .git directory 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).