Back to skill

Security audit

pg-copilot

Security checks for vulnerabilities and agentic risk

Overview

This PostgreSQL helper is mostly purpose-aligned, but it has high-impact database and credential risks that users should review carefully before installing.

Review this skill before installing, especially for production databases. Use least-privilege database accounts, avoid command-line secrets, rotate any credentials previously stored with it, restrict LLM and webhook destinations, and do not run sync-init or sync-watch on important databases until destructive behavior, SQL identifier quoting, confirmations, and secret storage are fixed.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/pg_copilot.py:623
Finding

SQL Injection Through Unquoted Database Identifiers

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/pg_copilot.py:27
Finding

Database Passwords and LLM API Keys Are Stored Insecurely

Content
View full analysis
= 4: config = load_config() if 'llm' not in config: config['llm'] = {} config['llm']['api_url'] = sys.argv[2] config['llm']['api_key'] = sys.argv[3] config['llm']['model'] = sys.argv[4] if len(sys.argv) > 4 else 'gpt-3.5-turbo' save_config(config) ``` ### Technical Analysis Base64 is a transport encoding, not encryption. It offers no confidentiality and can be reversed without a key. Any user or process that can read `_sync_config` can recover synchronization passwords immediately. The primary database password and LLM API key are stored in `~/.pg-copilot/config.json` as ordinary JSON values. ...[truncated 1605 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/pg_copilot.py:531
Finding

Synchronization Initialization Unconditionally Deletes Existing Queues and Logs

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/pg_copilot.py:53
Finding

Arbitrary Outbound Endpoints Permit SSRF and Sensitive Metadata Disclosure

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/pg_copilot.py:210
Finding

EXPLAIN ANALYZE Executes Unvalidated User-Supplied Statements

Content
View full analysis
= 3: for line in explain_query(' '.join(sys.argv[2:])): print(line) ``` ### Technical Analysis PostgreSQL `EXPLAIN ANALYZE` does not merely estimate a plan. It executes the supplied statement and records runtime statistics. The `explain_query` path does not call `is_dangerous`, enforce a single statement, limit input to `SELECT`, set the transaction to read-only, or use a restricted database role. Consequently, a statement submitted for performance analysis may modify data or invoke functions with side effects. Even a syntactically read-oriented query can invoke volatile functions, consume excessive resources, acquire locks, or trigger expensive full-table processing. The separate `execute_query` function contains limited dangerous-operation checks and defaults to read-only behavior, but those controls are entirely bypassed by `explain_query`. ### Attack Path 1. An attacker or untrusted caller invokes the `explain` command with a modifying SQL statement or a query that calls a side-effecting function. 2. The CLI concatenates the supplied arguments into a SQL string. 3. `explain_query` prefixes the statement with `EXPLAIN (ANALYZE, ...)`. 4. PostgreSQL executes the underlying statement using the configured database credentials. 5. Side effects occur before the execution plan is returned. An attacker can also submit a deliberately expensi ...[truncated 702 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (38)

Tainted flow: 'req' from os.environ.get (line 258, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

The webhook sender can transmit messages to an arbitrary URL supplied through configuration, and those messages may include internal table names, record IDs, and error details. In a database administration skill that already handles replication and operational metadata, this creates a real exfiltration and SSRF-style risk if an attacker can influence the webhook URL or the alert content.

Content

Scanner excerpt · scripts/pg_copilot.py (reported line 67)May include surrounding context.

python
headers={'Content-Type': 'application/json'},
            method='POST'
        )
        urllib.request.urlopen(req, timeout=10)
    except Exception as e:
        print(f"告警发送失败: {e}")

Tainted flow: 'req' from os.environ.get (line 258, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
95% confidence
Finding

The code sends prompts, SQL text, and optional schema details to an arbitrary external LLM endpoint configured via file or environment variables. In this skill context, those prompts can contain sensitive database structure and query information, so the outbound request is a meaningful data exfiltration channel, not a harmless network call.

Content

Scanner excerpt · scripts/pg_copilot.py (reported line 265)May include surrounding context.

python
method='POST'
        )
        
        with urllib.request.urlopen(req, timeout=30) as response:
            result = json.loads(response.read().decode('utf-8'))
            return result['choices'][0]['message']['content'], None

Missing User Warnings

High
Category
Not specified by scanner
Confidence
95% confidence
Finding

The documentation promotes SQL execution and real-time synchronization as core features but does not prominently warn about data modification, replication side effects, trigger creation, or production outages. In this context, users may run invasive operations against live databases without understanding that writes, schema changes, and cross-database sync can be hard to reverse.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 98)May include surrounding context.

md
python scripts/pg_copilot.py config-llm <api_url> <api_key> [model]

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 101)May include surrounding context.

md
python scripts/pg_copilot.py config-llm <api_url> <api_key> [model]

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 203)May include surrounding context.

md
python scripts/pg_copilot.py config-llm <api_url> <api_key> [model]

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 211)May include surrounding context.

md
python scripts/pg_copilot.py config-llm <api_url> <api_key> [model]

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 247)May include surrounding context.

md
python scripts/pg_copilot.py config-llm <api_url> <api_key> [model]

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 293)May include surrounding context.

md
python scripts/pg_copilot.py config-llm <api_url> <api_key> [model]

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 296)May include surrounding context.

md
python scripts/pg_copilot.py config-llm <api_url> <api_key> [model]

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 297)May include surrounding context.

md
python scripts/pg_copilot.py config-llm <api_url> <api_key> [model]

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 298)May include surrounding context.

md
python scripts/pg_copilot.py config-llm <api_url> <api_key> [model]

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 299)May include surrounding context.

md
python scripts/pg_copilot.py config-llm <api_url> <api_key> [model]

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 300)May include surrounding context.

md
python scripts/pg_copilot.py config-llm <api_url> <api_key> [model]

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 303)May include surrounding context.

md
python scripts/pg_copilot.py config-llm <api_url> <api_key> [model]

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 304)May include surrounding context.

md
python scripts/pg_copilot.py config-llm <api_url> <api_key> [model]

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 305)May include surrounding context.

md
python scripts/pg_copilot.py config-llm <api_url> <api_key> [model]

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 306)May include surrounding context.

md
python scripts/pg_copilot.py config-llm <api_url> <api_key> [model]

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Confidence
85% confidence
Finding

os.system() and os exec-family calls run shell commands with the process's full privileges, enabling arbitrary command execution.

Content

Scanner excerpt · scripts/pg_copilot.py (reported line 17)May include surrounding context.

python
# Windows 编码设置
if sys.platform == 'win32':
    os.system('chcp 65001 >nul')
    import codecs
    sys.stdout = codecs.getwriter('utf-8')(sys.stdout.buffer, 'strict')

Missing User Warnings

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

Database connection passwords are written into a local JSON config file, and elsewhere in the program they may be stored in trivially reversible form. On multi-user systems or compromised hosts, this exposes direct database credentials and can lead to unauthorized access to production data.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The SQL explanation path sends raw SQL and optional schema information to an external LLM service without a user-facing warning or consent gate. In this context, queries and schema often reveal sensitive data models, tenant identifiers, and business logic, making this a significant confidentiality issue.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

sync_init unconditionally drops _sync_changes and _sync_log before recreating them, destroying prior sync state and audit history without confirmation. In an admin-oriented database tool, this can cause operational outages, irrecoverable loss of replication backlog, and loss of forensic records if run accidentally or by a low-context operator.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill advertises capabilities that imply shell, network, file, and environment access, but it does not declare any explicit tool scope or permission boundaries. In a database administration skill that can execute SQL and configure synchronization, missing scope declarations increase the risk of overbroad access, accidental destructive actions, and secret exposure through unrestricted tooling.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The manifest description says the skill can handle “PostgreSQL 所有需求” (“all PostgreSQL needs”), which is extremely broad and overlaps many ordinary database-help requests. This lacks clear trigger boundaries or exclusions, increasing the risk of unintended invocation for generic PostgreSQL-related conversations.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The credential-handling guidance asks users to pass database passwords directly as CLI arguments without any warning about shell history, process-list exposure, logging, or secret storage practices. This is especially dangerous for production database credentials because command-line secrets can be exposed to other local users, terminal logs, CI output, and support captures.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.