Back to skill

Security audit

TurboQuant Memory

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its vector-compression purpose, but some documented workflows can execute local native SQLite extensions and modify or expose local memory database contents without strong warnings.

Review this skill before installing. Use it only on backup copies or disposable test databases until migration behavior is acceptable to you, avoid running validation with untrusted SQLITE_VEC_PATH or --vec-ext values, and do not run benchmarks against sensitive memory stores in shared terminals or CI logs.

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

Error
Location
scripts/validate.py:377
Finding

Untrusted SQLite Native Extension Loading Enables Arbitrary Code Execution

Content
View full analysis

Vulnerability Details

File Location: scripts/validate.py, lines 377-394
Vulnerability Type: Untrusted native library loading
Risk Level: High

Vulnerable Code

python
# Auto-detect sqlite-vec extension path
vec_ext_paths = [
    args.vec_ext,
    os.environ.get("SQLITE_VEC_PATH"),
    os.path.expanduser("~/.npm-global/lib/node_modules/openclaw/node_modules/sqlite-vec-darwin-arm64/vec0.dylib"),
    os.path.expanduser("~/.npm-global/lib/node_modules/openclaw/node_modules/sqlite-vec-linux-x64/vec0.so"),
]

try:
    conn = sqlite3.connect(args.db)

    # Try to load sqlite-vec extension for vec0 table support
    for ext_path in vec_ext_paths:
        if ext_path and os.path.exists(ext_path):
            try:
                conn.enable_load_extension(True)
                conn.load_extension(ext_path.replace('.dylib', '').replace('.so', ''))
                print(f"📦 Loaded sqlite-vec from {ext_path}")
                break
            except Exception as e:
                print(f"⚠️  Could not load sqlite-vec from {ext_path}: {e}")

Technical Analysis

The validation script enables SQLite extension loading and executes a native shared library selected from either the --vec-ext command-line argument or the SQLITE_VEC_PATH environment variable. The file is loaded without verifying its cryptographic digest, publisher, ownership, permissions, resolved path, or expected installation directory.

SQLite extensions are native executable modules. Loading one invokes its initialization entry point inside the current Python process. Consequently, control over the extension path is equivalent to control over native code executed with the privileges of the user running the validation script.

Loading sqlite-vec is relevant to reading vec0 tables, but implicitly trusting an environment variable is not necessary for the Skill's core quantization functionality and violates least-priv ...[truncated 1494 chars]

Remediation
View remediation

Remediation Suggestions

  1. Remove automatic native extension loading from environment-controlled paths.
  2. Require an explicit opt-in flag before enabling extension loading. Do not treat SQLITE_VEC_PATH as sufficient authorization.
  3. Resolve the extension path with Path.resolve() and require it to reside under a documented, trusted installation directory.
  4. Reject symlinks and files writable by untrusted users. Verify file ownership and permissions before loading.
  5. Validate the extension against a pinned SHA-256 digest or trusted digital signature.
  6. Avoid stripping suffixes with string replacement. Pass a validated canonical path in the form expected by the platform and SQLite API.
  7. Restrict the accepted extension to the expected sqlite-vec package and version.
  8. Immediately call conn.enable_load_extension(False) in a finally block after the load attempt.
  9. If possible, open or export the vectors through a trusted helper rather than loading arbitrary native modules into the main process.
  10. Document that native extension loading executes code with the invoking user's privileges.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/validate.py:43
Finding

Unvalidated SQL Identifier Interpolation Permits Query Manipulation

Content
View full analysis

Vulnerability Details

File Location: scripts/validate.py, lines 43-50 and 64-70; related occurrences in scripts/memory_quantize.py, including lines 41, 49, 70-72, 87-90, and 102-104
Vulnerability Type: SQL injection through dynamic table and column identifiers
Risk Level: Medium

Vulnerable Code

python
def _detect_dimension(self) -> Optional[int]:
    """Detect embedding dimension from first non-null row."""
    try:
        cursor = self.conn.execute(
            f"SELECT {self.embedding_col} FROM {self.table_name} "
            f"WHERE {self.embedding_col} IS NOT NULL LIMIT 1"
        )
python
def read_embeddings(self, limit: Optional[int] = None) -> np.ndarray:
    """Read all embeddings as numpy array."""
    if self.dim is None:
        raise ValueError("Could not detect embedding dimension")

    limit_clause = f"LIMIT {limit}" if limit else ""
    cursor = self.conn.execute(
        f"SELECT {self.embedding_col} FROM {self.table_name} "
        f"WHERE {self.embedding_col} IS NOT NULL {limit_clause}"
    )

Related constructions in the migration script include:

python
cursor = conn.execute(f"PRAGMA table_info({table_name})")
python
cursor = self.conn.execute(
    f"SELECT rowid, {self.embedding_col} FROM {self.table_name} "
    f"WHERE {self.embedding_col} IS NOT NULL "
    f"LIMIT {limit} OFFSET {offset}"
)

Technical Analysis

Table and column names are interpolated directly into SQL statements. In validate.py, these values can originate from the --table and --embedding-col command-line arguments. In auto-detection paths, table names can originate from metadata in the opened SQLite database.

SQLite parameter placeholders cannot bind identifiers, so identifiers must be independently validated and quoted. The current implementation does neither. A crafted identifier can introduce SQL syntax that changes the selected ...[truncated 2172 chars]

Remediation
View remediation

Remediation Suggestions

  1. Resolve requested table names against an authoritative list obtained from sqlite_master or PRAGMA table_list.
  2. Resolve column names against PRAGMA table_info for the validated table and reject columns not present in that schema.
  3. Apply a strict identifier policy where feasible, such as permitting only letters, digits, and underscores with a non-digit initial character.
  4. Quote validated SQLite identifiers by replacing each embedded double quote with two double quotes and enclosing the result in double quotes.
  5. Centralize identifier validation and quoting in one helper rather than repeating f-string construction.
  6. Continue using bound parameters for all data values. If limits and offsets ever become non-integer inputs, bind or strictly range-check them.
  7. For auto-detected vec0 tables, verify both the table declaration and required column schema before issuing data queries.
  8. Open databases read-only during validation and benchmarking where writes are unnecessary, for example by using an SQLite read-only URI.
  9. Add tests using identifiers containing quotes, whitespace, comments, parentheses, and SQL keywords to confirm that they are rejected or safely quoted.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • 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
Findings (10)

Tp4

High
Category
MCP Tool Poisoning
Confidence
89% confidence
Finding

A second documented mismatch is that the skill claims broad generic compression/search functionality, while the referenced workflows are specialized around local SQLite-backed memory stores, validation routines, and diagnostic output. In agent environments, capability understatement increases the risk of unintended database access, extension loading, or misuse against sensitive local memory stores.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

A second documented mismatch is that the skill claims broad generic compression/search functionality, while the referenced workflows are specialized around local SQLite-backed memory stores, validation routines, and diagnostic output. In agent environments, capability understatement increases the risk of unintended database access, extension loading, or misuse against sensitive local memory stores.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
86% confidence
Finding

The skill documentation advertises commands that can inspect environment-dependent paths and write changes to local databases, but it declares no explicit tool/permission scope. In an agent setting, this can lead to overbroad execution because the runtime may allow file/database modification without the user being clearly warned about required capabilities.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The documented --migrate command can modify the specified memory database, but the quick-start instructions do not warn that it is state-changing or potentially destructive. In practice, users or agents may run it on production memory stores assuming it is a safe optimization step, causing corruption, irreversible schema/data changes, or service disruption.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The migrate function opens the user-supplied database and proceeds to create and populate a quantized_embeddings table using INSERT OR REPLACE, which modifies persistent user data. Although the module docstring mentions a migrate mode, the execution path itself provides no confirmation prompt or explicit warning before writing to the database.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The benchmark path prints example memory text pulled from the database, which exposes raw stored content even though the tool's primary purpose is vector compression and search benchmarking. In environments where the database contains sensitive notes, prompts, or user data, simply running a benchmark can leak private content to terminal logs, CI output, or shared consoles.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The SRHTSketch docstring states that the sketch "stores sign bits only (m/8 bytes)", implying a 1-bit-per-dimension representation. However, both sketch and sketch_batch return scaled floating-point projected values, and the actual sign-bit conversion happens later in TurboQuantProd.quantize. This is an active documentation contradiction about what the class itself does.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The script enables extension loading and then loads a SQLite extension from either a user-supplied CLI path, an environment variable, or hardcoded filesystem locations. SQLite extensions are native code modules, so this creates a direct arbitrary code execution path if an attacker can influence the path or environment, which is far broader than a validation utility that otherwise only needs local database reads and NumPy processing.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The code loads a SQLite extension from a path controlled by --vec-ext or SQLITE_VEC_PATH without any trust validation or strong user warning. Because load_extension executes external native code in-process, a malicious shared library can fully compromise the host running the validator, making this a real code-execution risk rather than a mere configuration issue.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

The test section is labeled "SRHTRotate near-isometry", while SRHTRotate is only a backward-compatible alias for BlockwiseHadamardRotate and explicitly ignores output_dim. The surrounding module/class docs also say lossy SRHT subsampling was replaced with fully invertible blockwise rotation, so the test commentary no longer matches the implemented behavior.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.