T09 · Insecure Skill Coding Practices
- Location
scripts/pg_copilot.py:623- Finding
SQL Injection Through Unquoted Database Identifiers
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
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.
scripts/pg_copilot.py:623SQL Injection Through Unquoted Database Identifiers
scripts/pg_copilot.py:27Database Passwords and LLM API Keys Are Stored Insecurely
scripts/pg_copilot.py:531Synchronization Initialization Unconditionally Deletes Existing Queues and Logs
scripts/pg_copilot.py:53Arbitrary Outbound Endpoints Permit SSRF and Sensitive Metadata Disclosure
scripts/pg_copilot.py:210EXPLAIN ANALYZE Executes Unvalidated User-Supplied Statements
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.
headers={'Content-Type': 'application/json'},
method='POST'
)
urllib.request.urlopen(req, timeout=10)
except Exception as e:
print(f"告警发送失败: {e}")
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.
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
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.
Referenced artifact was not completely inspected
python scripts/pg_copilot.py config-llm <api_url> <api_key> [model]
Referenced artifact was not completely inspected
python scripts/pg_copilot.py config-llm <api_url> <api_key> [model]
Referenced artifact was not completely inspected
python scripts/pg_copilot.py config-llm <api_url> <api_key> [model]
Referenced artifact was not completely inspected
python scripts/pg_copilot.py config-llm <api_url> <api_key> [model]
Referenced artifact was not completely inspected
python scripts/pg_copilot.py config-llm <api_url> <api_key> [model]
Referenced artifact was not completely inspected
python scripts/pg_copilot.py config-llm <api_url> <api_key> [model]
Referenced artifact was not completely inspected
python scripts/pg_copilot.py config-llm <api_url> <api_key> [model]
Referenced artifact was not completely inspected
python scripts/pg_copilot.py config-llm <api_url> <api_key> [model]
Referenced artifact was not completely inspected
python scripts/pg_copilot.py config-llm <api_url> <api_key> [model]
Referenced artifact was not completely inspected
python scripts/pg_copilot.py config-llm <api_url> <api_key> [model]
Referenced artifact was not completely inspected
python scripts/pg_copilot.py config-llm <api_url> <api_key> [model]
Referenced artifact was not completely inspected
python scripts/pg_copilot.py config-llm <api_url> <api_key> [model]
Referenced artifact was not completely inspected
python scripts/pg_copilot.py config-llm <api_url> <api_key> [model]
Referenced artifact was not completely inspected
python scripts/pg_copilot.py config-llm <api_url> <api_key> [model]
Referenced artifact was not completely inspected
python scripts/pg_copilot.py config-llm <api_url> <api_key> [model]
os.system() and os exec-family calls run shell commands with the process's full privileges, enabling arbitrary command execution.
# Windows 编码设置
if sys.platform == 'win32':
os.system('chcp 65001 >nul')
import codecs
sys.stdout = codecs.getwriter('utf-8')(sys.stdout.buffer, 'strict')
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.
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.
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.
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.
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.
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.
No suspicious patterns detected.