Back to skill

Security audit

Memory Graph

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent SQLite knowledge-graph memory tool, but it persistently writes to a hard-coded, user-specific path on import instead of the documented local database path.

Review this skill before installing. It appears intended to maintain a local knowledge graph, but it should be changed to use a clearly documented, configurable, skill-owned database path and to initialize only when explicitly invoked. Treat stored graph contents as persistent memory and avoid storing sensitive personal, credential, or private project data unless you are comfortable with that location and retention behavior.

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 (2)

T09 · Insecure Skill Coding Practices

Warning
Location
graph_store.py:9
Finding

Hard-Coded Cross-Workspace Database Path with Import-Time Filesystem Modification

Content
View full analysis

Vulnerability Details

File Location: graph_store.py, lines 9-15 and 214
Vulnerability Type: Hard-coded storage path and unexpected import-time side effect
Risk Level: Medium

python
GRAPH_DIR = r"C:\Users\37845\.qclaw\workspace\knowledge"
DB_PATH = os.path.join(GRAPH_DIR, "graph.db")

def _get_conn():
    os.makedirs(GRAPH_DIR, exist_ok=True)
    conn = sqlite3.connect(DB_PATH)
    conn.execute("PRAGMA journal_mode=WAL")
python
# 初始化
init_db()

Technical Analysis

The database location is hard-coded to a specific user's workspace rather than being supplied by the caller, derived from an approved application data directory, or resolved relative to the current workspace. This conflicts with the documented knowledge/graph.db location and can cause data to be written across project or workspace boundaries.

In addition, init_db() is called at module scope. Importing the module therefore invokes _get_conn(), creates the configured directory, opens or creates the database, enables WAL mode, and initializes its schema without an explicit initialization request from the caller.

On Windows, the code can modify another workspace when executed by an account that can access the configured path. On POSIX systems, the Windows-style path can be interpreted as an unintended relative path, creating files in an unexpected location. These operations remain limited to the privileges of the process running the module; the code does not independently elevate privileges.

Attack Path

  1. An application or agent imports graph_store.py to access its graph API.
  2. The module-level init_db() call executes automatically.
  3. init_db() calls _get_conn().
  4. _get_conn() creates the hard-coded directory and opens or creates graph.db.
  5. SQLite schema and WAL-related files are written to that location.
  6. If the path is shared with another project or user workspace accessible to the pr ...[truncated 660 chars]
Remediation
View remediation

Remediation Suggestions

  • Remove the module-level init_db() invocation and require explicit initialization by the application.
  • Accept the database path through a constructor, function argument, environment variable, or trusted configuration source.
  • Use a safe default under a Skill-owned application data directory rather than a user-specific absolute path.
  • Resolve and normalize the configured path before use, then verify that it remains within an approved workspace or data root.
  • Reject paths that escape the approved root through absolute paths, symbolic links, or traversal components when untrusted callers can influence configuration.
  • Apply restrictive filesystem permissions to the database directory and files.
  • Document the exact storage location and import behavior.
  • Add tests confirming that importing the module creates no files and that initialization cannot write outside the configured data root.

T09 · Insecure Skill Coding Practices

Note
Location
graph_store.py:73
Finding

Dangling Graph Relations Allowed by Missing Foreign-Key Enforcement and Incomplete ID Validation

Content
View full analysis

Vulnerability Details

File Location: graph_store.py, lines 14 and 73-88
Vulnerability Type: Insufficient referential-integrity validation
Risk Level: Low

python
def _get_conn():
    os.makedirs(GRAPH_DIR, exist_ok=True)
    conn = sqlite3.connect(DB_PATH)
    conn.execute("PRAGMA journal_mode=WAL")
    conn.row_factory = sqlite3.Row
    return conn
python
def add_relation(source: str, rel: str, target: str, weight: float = 1.0, meta: dict = None) -> str:
    """添加或更新边,返回 edge_id。source/target 支持 entity_id 或 name#type 格式。"""
    # 解析 source/target:如果包含 # 视为 name#type,否则视为 entity_id
    src_id = source if len(source) == 16 else _resolve_id(source)
    tgt_id = target if len(target) == 16 else _resolve_id(target)
    if not src_id or not tgt_id:
        return None  # 解析失败,不存在对应实体
    eid = _edge_id(src_id, rel, tgt_id)
    now = int(datetime.now().timestamp())
    meta_json = json.dumps(meta or {}, ensure_ascii=False)
    with _get_conn() as conn:
        conn.execute("""
            INSERT INTO edges (id, source, rel, target, weight, meta, updated_at)
            VALUES (?, ?, ?, ?, ?, ?, ?)
            ON CONFLICT(id) DO UPDATE SET

Technical Analysis

add_relation() treats every 16-character string as an existing entity identifier and bypasses _resolve_id(). It consequently does not verify that either endpoint exists in the nodes table.

Although the schema declares foreign keys for edges.source and edges.target, SQLite does not enforce foreign-key constraints unless PRAGMA foreign_keys=ON is enabled for each connection. _get_conn() does not enable this setting. A caller can therefore insert an edge whose source or target references no node.

This is primarily a data-integrity vulnerability. Parameterized SQL is used, so the affected code does not introduce SQL injection.

Attack Path

  1. A caller supplies arbitrary 16-character values as ` ...[truncated 949 chars]
Remediation
View remediation

Remediation Suggestions

  • Execute PRAGMA foreign_keys=ON immediately after opening every SQLite connection.
  • Verify the setting with PRAGMA foreign_keys during initialization or testing.
  • Resolve and validate both relation endpoints regardless of whether their values are 16 characters long.
  • Query nodes to confirm that both identifiers exist before inserting an edge.
  • Raise a clear validation exception instead of silently returning None when endpoint resolution fails.
  • Consider performing endpoint validation and relation insertion in one transaction to avoid time-of-check/time-of-use inconsistencies.
  • Add tests proving that nonexistent source and target identifiers are rejected and that foreign-key violations cannot be committed.
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • 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
Findings (5)

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The trigger phrases are broad and lack explicit scope constraints, exclusions, or confirmation requirements, which can cause the skill to activate on incidental user text rather than deliberate invocation. In a memory/knowledge-graph skill, unintended activation can persistently store or relate user content in SQLite, creating privacy, integrity, and context-poisoning risks across future agent behavior.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The manifest description is written entirely in Chinese, which imposes a specific language on users without any opt-in or indication that the skill is intentionally limited to a Chinese-speaking context. Under the language/locale policy, natural-language metadata should not force a locale unless the constraint is explicit and justified.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

The top-level docstring is written entirely in Chinese and presents the skill's interface and purpose only in that language. This can constitute a language-policy issue because the file imposes a specific locale for human-readable operational guidance without any opt-in or alternative language.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

The module exposes an extra stats() capability beyond the documented atomic operations and returns the underlying database path. While not directly enabling code execution or SQL injection, this unnecessarily broadens the interface and leaks implementation details that can aid environment mapping and follow-on attacks. In a memory/knowledge-store skill, revealing internal storage paths is not needed for normal graph operations.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

stats() discloses the local filesystem path of the SQLite database, exposing host-specific implementation details. Even though the path disclosure alone is low severity, it can help an attacker understand the runtime environment, target local files, or chain with other weaknesses in a larger agent system.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.