Back to skill

Security audit

Data Structure Protocol (DSP)

Security checks for vulnerabilities and agentic risk

Overview

The skill has a coherent local code-graph purpose, but its bundled CLI can delete arbitrary directories if given an absolute or traversal-style UID.

Install only if you trust the projects and prompts that will supply DSP UIDs. Until the CLI validates UID format and confines all paths to .dsp, avoid running destructive commands such as remove-entity on unreviewed input and review or back up repository state before use.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/dsp-cli.py:419
Finding
Unvalidated UID Paths Allow Arbitrary Directory Deletion and Filesystem Access## Vulnerability Details **File Location**: `scripts/dsp-cli.py`, lines 161–175 and 419–455 **Vulnerability Type**: Path traversal and absolute-path injection **Risk Level**: High ### Vulnerable Code Path construction and entity validation at lines 161–175: ```python class Store: def __init__(self, root: Path): self.root = root.resolve() self.base = self.root / DSP_DIR # ── guards ── def ensure_init(self) -> None: if not self.base.is_dir(): _fail(f"directory {self.base} not found — run 'init' first") def entity_exists(self, uid: str) -> bool: return (self.base / uid).is_dir() def require_entity(self, uid: str) -> None: if not self.entity_exists(uid): _fail(f"entity {uid} does not exist") ``` Recursive deletion at lines 419–455: ```python def remove_entity(self, uid: str) -> None: self.s.ensure_init() self.s.require_entity(uid) all_uids = self.s.all_uids() for other in all_uids: if other == uid: continue imports = self.s.read_imports(other) had = any(u == uid or v == uid for u, v in imports) if had: new_lines = [ _format_import_line(u, v) for u, v in imports if u != uid and v != uid ] _write_lines(self.s.imports_path(other), new_lines) for imp_uid, imp_via in self.s.read_imports(uid): if imp_via: _safe_unlink(self.s.exports_dir(imp_via) / imp_uid / uid) else: _safe_unlink(self.s.exports_dir(imp_uid) / uid) for other in all_uids: if other == uid: continue shared = self.s.read_shared(other) if uid in shared: _remove_line_value(self. ...[truncated 3001 chars]
Remediation
## Remediation Suggestions 1. Validate every UID before using it in a path: ```python UID_RE = re.compile(r"^(?:obj|func)-[0-9a-f]{8}$") def validate_uid(uid: str) -> str: if not UID_RE.fullmatch(uid): _fail(f"invalid entity UID: {uid}") return uid ``` 2. Apply UID validation consistently to all entity-related parameters, including: - `uid` - `owner` - `exporter` - `shared_uid` - `importer` - `imported` - Parsed `via` values - TOC root identifiers 3. Centralize safe path construction and verify containment after resolution: ```python def entity_path(self, uid: str) -> Path: validate_uid(uid) candidate = (self.base / uid).resolve() try: candidate.relative_to(self.base.resolve()) except ValueError: _fail("entity path escapes the .dsp directory") return candidate ``` 4. Replace direct expressions such as `self.base / uid` with the centralized safe-path function. 5. Before recursive deletion, perform a second containment check and reject: - Absolute user-supplied path components - `.` and `..` traversal components - Directory separators inside identifiers - Symlinks or resolved paths outside `.dsp` - Attempts to delete `.dsp` itself or the project root 6. Validate identifiers read from existing `imports`, `shared`, TOC, and export-index files. Treat graph files as potentially untrusted project data rather than assuming their contents are safe. 7. Add regression tests covering absolute paths, traversal strings, malformed UIDs, symlink escapes, and valid entity deletion.
Vulnerability Patterns
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (9)

Lp3

Medium
Category
MCP Least Privilege
Confidence
86% confidence
Finding
The skill instructs the agent to read and modify repository state via `dsp-cli`, but the manifest declares no explicit tool scope such as `permissions` or `allowed-tools`. That mismatch weakens policy enforcement and reviewability, increasing the chance an agent invokes file read/write behavior without clear authorization boundaries.

Missing User Warnings

Medium
Confidence
84% confidence
Finding
The skill presents destructive commands like `remove-import`, `remove-shared`, and especially `remove-entity` with cascading cleanup but without requiring confirmation or warning about data loss. In an agent context, terse destructive instructions can lead to unintended graph deletion and repository state changes from routine maintenance actions.

Intent-Code Divergence

Medium
Confidence
96% confidence
Finding
The command reference and later workflow sections disagree about which CLI operations exist. Contradictory operational guidance is dangerous in an agent skill because the agent may infer capabilities that are not actually approved, or substitute alternate commands with side effects when the documented ones fail.

Description-Behavior Mismatch

Medium
Confidence
92% confidence
Finding
The workflow documentation advertises commands such as `get-recipients`, `get-path`, `update-import-why`, `detect-cycles`, and `get-orphans` that are not present in the earlier key command list. When documented capabilities exceed the manifest or canonical interface, agents may attempt unsupported or unintended operations, creating ambiguity that can mask unauthorized behavior or unsafe fallbacks.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The file documents destructive operations like `remove-shared` and especially `remove-entity` with cascading cleanup, but provides no warning, confirmation, backup, dry-run, or recovery guidance. In an agent skill context, this increases the chance that an LLM-driven tool invocation could delete large portions of `.dsp/` state unintentionally or based on ambiguous user input, causing integrity loss in project structure metadata.

Missing User Warnings

Medium
Confidence
84% confidence
Finding
The remove_shared operation removes import references from recipients and recursively deletes the shared export directory via _safe_rmtree. The code does not provide a dedicated warning, confirmation prompt, or descriptive runtime disclosure that this action modifies multiple entities and deletes on-disk metadata.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The remove_entity command performs irreversible filesystem deletions and cleanup of related references using _safe_rmtree and _safe_unlink, but the only user-visible output after execution is a generic "ok". While the CLI help says it will remove the entity and references, there is no explicit runtime warning, confirmation prompt, or stronger disclosure before destructive deletion occurs.

Missing User Warnings

Low
Confidence
77% confidence
Finding
The setup workflow tells the agent to run `dsp-cli init` and then bootstrap the project, which will create and write extensive metadata under `.dsp/`. The description explains what DSP is, but it does not clearly warn users that the skill will modify the repository by generating persistent tracking files.

Missing User Warnings

Low
Confidence
75% confidence
Finding
The remove_import operation rewrites import metadata and deletes reverse-link files with _safe_unlink, but there is no explicit user-facing warning beyond a generic success message. For a code file, file deletion operations should have some disclosure unless already clearly warned elsewhere.

Static analysis

No suspicious patterns detected.