Back to skill

Security audit

Highgo Db

Security checks for vulnerabilities and agentic risk

Overview

This skill is a database helper, but it needs Review because it handles real database credentials unsafely and can load arbitrary local driver code.

Install only if you are comfortable reviewing a database tool that can execute write-capable SQL. Use a least-privileged, preferably non-production HighGo account, avoid putting passwords in command lines, and do not use --driver except with a trusted, integrity-verified local driver directory.

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/execute_query.py:7
Finding
Caller-Controlled Driver Path Enables Arbitrary Python Code Execution## Vulnerability Details **File Location**: `scripts/execute_query.py:7-35` **Vulnerability Type**: Unsafe dynamic module loading **Risk Level**: High ### Vulnerable Code ```python def execute_query(dsn, sql, driver_path=None): # If no driver_path provided, look in the skill's assets/driver/psycopg2 if driver_path is None: script_dir = os.path.dirname(os.path.abspath(__file__)) driver_path = os.path.join(script_dir, "..", "assets", "driver", "psycopg2") if not os.path.exists(driver_path): return {"status": "error", "message": "Driver not found at {}".format(driver_path)} # Manual temporary directory for Python 2.7 compatibility tmp_dir = tempfile.mkdtemp() try: target_path = os.path.join(tmp_dir, "psycopg2") if not os.path.exists(target_path): os.symlink(os.path.abspath(driver_path), target_path) # Add the driver path to LD_LIBRARY_PATH for the .so libraries env = os.environ.copy() driver_abs_path = os.path.abspath(driver_path) if "LD_LIBRARY_PATH" in env: os.environ["LD_LIBRARY_PATH"] = "{}:{}".format( driver_abs_path, env['LD_LIBRARY_PATH']) else: os.environ["LD_LIBRARY_PATH"] = driver_abs_path # Add the temp directory to sys.path sys.path.insert(0, tmp_dir) try: import psycopg2 from psycopg2 import extras ``` The externally selectable path is exposed at `scripts/execute_query.py:66`: ```python parser.add_argument("--driver", required=False, help="Path to psycopg2 directory (optional, uses built-in if omitted)") ``` ### Technical Analysis The `--driver` argument accepts any existing filesystem path. The script creates a symbolic link from that path to a temporary package named `psycopg2`, places the temporary directory at the beg ...[truncated 2121 chars]
Remediation
## Remediation Suggestions 1. Remove the `--driver` option if external driver substitution is not strictly required. 2. Package and import one pinned, reviewed driver from a fixed Skill-owned directory. 3. If external drivers are required, allow only paths beneath an administrator-configured trusted root. 4. Resolve paths with `realpath()` and reject paths, parent components, or files containing symbolic links. 5. Reject driver directories writable by untrusted users and validate file ownership and permissions. 6. Verify every driver file against a signed manifest or pinned cryptographic hashes before importing it. 7. Do not add caller-controlled directories to `LD_LIBRARY_PATH`; use fixed, integrity-verified native-library locations. 8. Execute unavoidable third-party drivers in an isolated, least-privileged process with restricted filesystem and network access. 9. Avoid retaining untrusted entries in global `sys.path` or process environment state.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/execute_query.py:64
Finding
Database Passwords Are Exposed Through Command-Line DSN Arguments## Vulnerability Details **File Location**: `scripts/execute_query.py:64-72`; documented usage at `SKILL.md:33-35` and `README.md:46-48` **Vulnerability Type**: Sensitive information exposure through process arguments **Risk Level**: Medium ### Vulnerable Code ```python parser = argparse.ArgumentParser( description="Execute SQL on HighGo DB using built-in psycopg2") parser.add_argument("--dsn", required=True, help="Connection DSN") parser.add_argument("--sql", required=True, help="SQL query or path to SQL file") parser.add_argument("--driver", required=False, help="Path to psycopg2 directory (optional, uses built-in if omitted)") args = parser.parse_args() sql_content = args.sql if os.path.exists(args.sql): with open(args.sql, "r") as f: sql_content = f.read() result = execute_query(args.dsn, sql_content, args.driver) ``` `SKILL.md:33-35` instructs users to include a password directly in the command: ```bash python2 highgo-db/scripts/execute_query.py \ --dsn "host=10.238.18.128 port=5866 dbname=ficc user=fic password='PASSWORD' options='-c search_path=system'" \ --sql "SELECT count(*) FROM sys_user;" ``` `README.md:46-48` documents the same pattern: ```bash python2 highgo-db/scripts/execute_query.py \ --dsn "host=[IP] port=[PORT] dbname=[DB] user=[USER] password='[PASS]' options='-c search_path=system'" \ --sql "SELECT count(*) FROM sys_user;" ``` ### Technical Analysis The prescribed interface embeds the database password in a command-line argument. Command-line arguments can be exposed through shell history, process inspection facilities, terminal-session recording, CI/CD logs, Agent execution telemetry, debugging output, and monitoring systems. Shell quoting controls how the shell parses the argument but does not prevent the resulting DSN from appearing in the target process's argument vector. The script provides no prote ...[truncated 1342 chars]
Remediation
## Remediation Suggestions 1. Remove passwords from command-line DSN examples and explicitly warn users not to place secrets in process arguments. 2. Support a permission-restricted PostgreSQL password file or connection-service file. 3. Alternatively, read the password from protected standard input using a non-echoing prompt. 4. Integrate with an approved secret manager for automated environments. 5. Allow a DSN without a password and obtain the secret separately at runtime. 6. Ensure errors, logs, telemetry, and returned JSON redact passwords and complete credential-bearing DSNs. 7. Apply restrictive permissions to all credential files and reject files that are accessible to other users. 8. Rotate any credentials previously entered through logged command lines. 9. Use a dedicated least-privileged database account so credential compromise has limited impact.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (15)

Env Variable Harvesting

High
Category
Data Exfiltration
Content
os.symlink(os.path.abspath(driver_path), target_path)
        
        # Add the driver path to LD_LIBRARY_PATH for the .so libraries
        env = os.environ.copy()
        driver_abs_path = os.path.abspath(driver_path)
        if "LD_LIBRARY_PATH" in env:
            os.environ["LD_LIBRARY_PATH"] = "{}:{}".format(driver_abs_path, env['LD_LIBRARY_PATH'])
Confidence
60% confidence
Finding
Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The README includes an example command that passes a full DSN with username and password directly on the command line and runs a live SQL query against a real database. This is risky because shell history, process listings, logs, and screenshots can expose credentials, and users may copy the example into production-like environments without understanding the exposure.

Lp3

Medium
Category
MCP Least Privilege
Confidence
82% confidence
Finding
The skill advertises code-like capabilities that can access environment data and read files, but it does not declare any explicit tool scope or permission boundaries. This creates ambiguity about what the skill is allowed to access, increasing the risk of unintended secret exposure or local file disclosure when the skill is invoked in an agent environment.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The documentation includes an example DSN with inline username and password, normalizing a practice that can expose credentials through shell history, process listings, logs, and copied transcripts. In this skill's context, the risk is heightened because it is specifically designed for direct database access, so leaked credentials could immediately enable unauthorized access to a HighGo database.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The logging connection/cursor classes log every executed query by default, and `self.query` may include fully rendered SQL text with parameter values. This can expose secrets and sensitive data such as credentials, tokens, personal data, or business data to files or application logs, especially because the default `filter()` performs no redaction.

Description-Behavior Mismatch

Medium
Confidence
91% confidence
Finding
Although the skill description emphasizes a built-in HighGo psycopg2 driver, the code accepts an arbitrary external driver path and then imports code from that path. In a skill context, this expands trust from bundled assets to attacker-controlled local content, enabling arbitrary code execution through a malicious Python package or native library loaded as psycopg2.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The manifest frames the skill as providing a custom psycopg2-based connection to HighGo DB, which suggests connectivity support rather than unrestricted database mutation. The code accepts arbitrary SQL, allows multiple statements, and always commits, enabling INSERT/UPDATE/DELETE/DDL behavior beyond a simple connection utility.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
This code executes arbitrary SQL provided via CLI and then commits the transaction, which can modify or destroy database data. Although the script name and argument names imply query execution, there is no confirmation prompt, warning print, or explanatory comment/docstring disclosing that supplied SQL will be executed and committed against the target database.

Natural-Language Policy Violations

Low
Confidence
92% confidence
Finding
The file presents all operational instructions in a single forced language and does not provide an alternative language option, opt-in, or justification for the locale restriction. Under the stated policy, forcing a specific language without user choice is a natural-language policy concern.

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Content
if not isinstance(other, Range):
            return NotImplemented
        for attr in ('_lower', '_upper', '_bounds'):
            self_value = getattr(self, attr)
            other_value = getattr(other, attr)
            if self_value == other_value:
                pass
Confidence
50% confidence
Finding
Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Content
return NotImplemented
        for attr in ('_lower', '_upper', '_bounds'):
            self_value = getattr(self, attr)
            other_value = getattr(other, attr)
            if self_value == other_value:
                pass
            elif self_value is None:
Confidence
50% confidence
Finding
Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Content
return self.__gt__(other)

    def __getstate__(self):
        return {slot: getattr(self, slot)
            for slot in self.__slots__ if hasattr(self, slot)}

    def __setstate__(self, state):
Confidence
50% confidence
Finding
Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Natural-Language Policy Violations

Low
Confidence
96% confidence
Finding
This markdown file presents all user-facing instructions in Chinese and does not indicate that the content is region-specific or provide any language/locale opt-in. Under the policy rule for natural-language violations, forcing a specific language without user choice is a reportable issue.

Missing User Warnings

Low
Confidence
78% confidence
Finding
The script accepts a DSN from the command line and uses it to connect to the database, which may include embedded credentials or other sensitive connection details. There is no warning in code comments or CLI help that sensitive credentials may be supplied and used by this script.

Context-Inappropriate Capability

Low
Confidence
83% confidence
Finding
If --sql points to an existing path, the program opens and reads that file, turning the skill into a local file reader in addition to a database connectivity helper. Local file ingestion is not mentioned in the manifest and is not necessary to the narrowly stated purpose of supplying a built-in database driver.

Static analysis

No suspicious patterns detected.