Security Model
August 16, 2026 · View on GitHub
dsh-shield is two layers that share one vocabulary.
DSH SHIELD
│
┌─────────────┴─────────────┐
│ │
↓ ↓
PREFLIGHT SECURITY RUNTIME SECURITY
│ │
├─ Package Scanner ├─ Tool Gate
├─ Source Scanner ├─ MCP Gate
├─ Dependency Scanner ├─ Egress Guard
├─ Script Scanner ├─ Approval (official ask)
├─ Permission Inferencer ├─ Sensitive Data
├─ Risk Engine ├─ Injection Signals
└─ Trust Manifest └─ Audit Log
Shared: policy engine, risk model, finding model, trust manifest, security events, secret detector, redaction.
Decisions
| Decision | Meaning |
|---|---|
| ALLOW | Execute immediately |
| ASK | Official PreToolDecision.ask → ctx.approval.request. Missing approval denies. |
| DENY | Do not execute. Re-asserted by ctx.tools.guard() so later hooks cannot restore ALLOW. |
Risk engine
Deterministic. No LLM.
score = severityWeight[severity] * confidence * phaseWeight[phase]
severityWeight: info 0, low 1, medium 3, high 7, critical 12
phaseWeight: install 1.4, runtime 1.0, unknown 1.1
critical if any finding is critical with confidence ≥ 0.7
else high if any high finding with confidence ≥ 0.8, or max score ≥ 8
else medium if max score ≥ 4
else low if max score ≥ 1.5
else info
Incomplete scans never become an all-clear. Completeness is a separate
field: complete | partial | failed.
Policy profiles
| permissive | balanced (default) | strict | enterprise | |
|---|---|---|---|---|
| local read | allow | allow | allow | allow |
| local write | allow | ask | ask | ask |
| destructive | ask | deny | deny | deny |
| external write | ask | ask | deny | deny |
| secret egress | deny | deny | deny | deny |
| unknown MCP read | allow | ask | ask | deny |
| unknown MCP write | ask | ask | deny | deny |
| unknown tool | allow | ask | ask | deny |
Profiles are different defaults, not aliases.
Invalid policy documents fail closed for high-risk decisions.
Secret handling
Detectors are regex + entropy heuristics. Matches are stored as
redacted previews (sk-abc...xyz or [REDACTED]). Audit logs must
not contain the raw value. Tests assert this with
assertNoRawSecret.
Prompt injection
Detection + behavioral policy. We tag untrusted results
(UNTRUSTED_WEB / UNTRUSTED_MCP) and raise the next dangerous
call. We do not delete the original text. We do not claim
prevention.
Local first
Scan, policy, and audit stay on disk. Source is never uploaded for "cloud analysis." There is no LLM in the security boundary.