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

Content
View full analysis

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
View 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)

Undeclared Tool Scope

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.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.