Back to skill

Security audit

postgres mcp

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent PostgreSQL admin helper, but it needs review because its setup and examples can expose database credentials, run mutable third-party components, and enable write or admin database actions.

Install only after reviewing the setup path. Use a pinned and verified postgres-mcp image or package, keep database passwords out of command arguments and shared config files, use a dedicated least-privilege role, prefer read-only mode for production, and require explicit confirmation before writes, session termination, or recurring health checks.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (2)

T08 · Insecure Dependencies

Warning
Location
reference/setup-postgres-mcp/setup-postgres-mcp.md:74
Finding
Mutable and Unpinned Third-Party Components Can Change After Review<![CDATA[ ## Vulnerability Details **File Location**: `reference/setup-postgres-mcp/setup-postgres-mcp.md`, lines 74–137 **Additional Locations**: `reference/setup-postgres-mcp/setup-postgres-mcp.md`, lines 106–116 and 134–137 **Vulnerability Type**: Unpinned third-party dependencies and mutable container images **Risk Level**: Medium ### Vulnerable Code ```bash docker run -i --rm \ ghcr.io/crystaldba/postgres-mcp:latest \ "postgresql://user:pass@host:5432/dbname" ``` ```bash docker run -d -p 8000:8000 \ ghcr.io/crystaldba/postgres-mcp:latest \ --transport sse \ --port 8000 \ "postgresql://user:pass@host:5432/dbname" ``` ```bash brew install uv ``` ```bash pip install uv ``` ```bash pipx install uv ``` ```bash # From PyPI uv pip install postgres-mcp # Or from source git clone https://github.com/crystaldba/postgres-mcp.git cd postgres-mcp uv pip install -e . uv sync ``` ```bash pipx install postgres-mcp postgres-mcp "postgresql://user:pass@host:5432/dbname" ``` ### Technical Analysis The setup instructions install and execute third-party components without pinning them to immutable, reviewed versions: - The `latest` container tag is mutable and can point to a different image at any time. - PyPI installations do not specify package versions or verify package hashes. - The Git repository is cloned without checking out a reviewed commit or signed release. - The `uv` installer itself is installed without a version constraint. Consequently, the code ultimately executed by users can differ from the code that existed when this Skill was audited. This creates a supply-chain trust gap. If an upstream package, release process, repository, registry account, or maintainer account is compromised, a modified component could execute with access to the supplied database connection string and network connectivity. This finding does not establish that the current upstream project is malicious. The vulnerability is the absence of immutable dependency sel ...[truncated 1495 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace mutable container tags with reviewed immutable digests: ```bash docker run -i --rm \ ghcr.io/crystaldba/postgres-mcp@sha256:<reviewed-digest> \ "${DATABASE_URL}" ``` 2. Pin exact Python package versions and use hash verification: ```text postgres-mcp==<reviewed-version> --hash=sha256:<reviewed-hash> uv==<reviewed-version> --hash=sha256:<reviewed-hash> ``` Install with a locked requirements file and require hashes. 3. For source installations, check out a specific reviewed commit or signed tag: ```bash git clone https://github.com/crystaldba/postgres-mcp.git cd postgres-mcp git checkout --detach <reviewed-commit> git verify-commit <reviewed-commit> ``` 4. Publish the expected package versions, image digests, checksums, and signing identities in the setup guide. 5. Use signature or provenance verification where supported, such as Sigstore/Cosign for container images and trusted package-index verification for Python packages. 6. Run the service with a dedicated least-privilege database role, preferably read-only unless write access is explicitly required. 7. Re-review and intentionally update all pinned artifacts through a controlled dependency-update process. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
reference/setup-postgres-mcp/setup-postgres-mcp.md:74
Finding
Database Credentials Are Exposed Through Process Arguments and Plaintext Client Configuration<![CDATA[ ## Vulnerability Details **File Location**: `reference/setup-postgres-mcp/setup-postgres-mcp.md`, lines 74–193 **Additional Locations**: `reference/setup-postgres-mcp/setup-postgres-mcp.md`, lines 221–236 **Vulnerability Type**: Plaintext sensitive data in command arguments and persistent configuration **Risk Level**: Medium ### Vulnerable Code ```bash docker run -i --rm \ ghcr.io/crystaldba/postgres-mcp:latest \ "postgresql://user:pass@host:5432/dbname" ``` ```bash uv run postgres-mcp "postgresql://user:pass@host:5432/dbname" ``` ```bash postgres-mcp "postgresql://user:pass@host:5432/dbname" ``` ```json { "mcpServers": { "postgres": { "command": "docker", "args": [ "run", "-i", "--rm", "ghcr.io/crystaldba/postgres-mcp:latest", "postgresql://user:pass@host.docker.internal:5432/dbname" ] } } } ``` ```json { "mcpServers": { "postgres": { "command": "uv", "args": [ "run", "postgres-mcp", "postgresql://user:pass@localhost:5432/dbname" ] } } } ``` ```json { "mcpServers": { "postgres": { "command": "docker", "args": [ "run", "-i", "--rm", "ghcr.io/crystaldba/postgres-mcp:latest", "postgresql://user:pass@host.docker.internal:5432/dbname" ] } } } ``` ### Technical Analysis The guide instructs users to substitute real PostgreSQL credentials directly into command-line arguments and persistent JSON client configuration. Command-line secrets may be exposed through: - Process inspection utilities and process-management APIs. - Shell history. - Terminal session logging. - Diagnostic tools, crash reports, and command auditing. - Container runtime metadata. Plaintext configuration secrets may be exposed through: - Other local users or processes with read access. - Editor history, synchronization, and backup systems. - Accidental source-control commits, especi ...[truncated 1497 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not place passwords directly in command-line arguments. 2. Prefer a dedicated secret-management mechanism supported by the deployment environment, such as: - An operating-system credential store. - Docker or orchestration-platform secrets. - A permission-restricted PostgreSQL password file. - A secrets manager that injects credentials at runtime. - A protected environment file excluded from source control. 3. If `DATABASE_URL` must be used, inject it at runtime rather than embedding it in MCP JSON: ```bash export DATABASE_URL="$(secure-secret-command)" postgres-mcp ``` Ensure that the implementation supports reading the URL without placing its value back into the process argument list. 4. For Docker, mount a read-only secret file or use a runtime secret facility instead of supplying the URI as an argument. 5. Restrict configuration and secret-file permissions to the owning account, for example: ```bash chmod 600 <secret-or-config-file> ``` 6. Add relevant MCP configuration and environment files to `.gitignore`, and provide placeholder-only configuration templates. 7. Use a dedicated PostgreSQL role with the minimum required permissions. Default to read-only access and explicitly grant write privileges only when needed. 8. Rotate credentials immediately if a real connection URI has appeared in shell history, logs, source control, backups, or shared configuration. 9. Redact connection strings from diagnostics, logs, screenshots, examples, and support bundles. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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
Findings (20)

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The README advertises SQL execution capability, including a 'safe SQL execution' feature, but does not clearly warn that SQL execution can still modify or destroy data if misconfigured, used outside read-only mode, or granted broad privileges. In a database administration skill, this omission increases the chance that users invoke powerful operations without understanding the risk of destructive queries against production systems.

Natural-Language Policy Violations

Medium
Confidence
88% confidence
Finding
The skill metadata and instructions require Chinese output by default without checking the user's language preference. While not a direct code-execution risk, forcing a language can degrade user comprehension of sensitive database actions, confirmations, or destructive SQL previews, which weakens informed consent and can contribute to operator error.

Vague Triggers

Medium
Confidence
95% confidence
Finding
The activation rule is very broad: it triggers on essentially any PostgreSQL- or database-optimization-related mention. That can cause the agent to invoke this skill in contexts where the user did not explicitly request database access, increasing the chance of unintended data exposure or execution of sensitive database actions through the MCP toolchain.

Natural-Language Policy Violations

Medium
Confidence
84% confidence
Finding
The entire skill description and user-facing examples are written exclusively in Chinese, with no indication that language selection is optional or that the skill is intended only for a Chinese-speaking environment. This can violate language or locale policy when the skill effectively imposes a specific language without user opt-in.

Vague Triggers

Medium
Confidence
95% confidence
Finding
The activation text says to use this skill whenever the user mentions SQL execution or data modification tasks, which is broad enough to trigger a powerful database-execution capability in loosely related contexts. Overly broad routing increases the chance of invoking a high-risk skill unnecessarily, expanding exposure to unintended query execution or unsafe operational guidance.

Intent-Code Divergence

Medium
Confidence
95% confidence
Finding
The document states that write operations require user confirmation, but later examples normalize immediate execution of a batch update without a confirmation step. This inconsistency can cause an agent or operator to skip an important safeguard, increasing the risk of accidental destructive or large-scale data modification.

Context-Inappropriate Capability

Medium
Confidence
91% confidence
Finding
The skill explicitly documents `pg_cancel_backend(pid)` and `pg_terminate_backend(pid)`, which can affect other active database sessions rather than only the caller's own query. In an execution-oriented skill, exposing these commands without clear authorization, scope restriction, or strong confirmation can enable denial-of-service against legitimate workloads or administrative interference.

Natural-Language Policy Violations

Medium
Confidence
72% confidence
Finding
The skill content is written entirely in Chinese and does not indicate that the language is configurable or user-selected. If organizational policy requires respecting user locale preferences, this can amount to an implicit language constraint without opt-in.

Vague Triggers

Medium
Confidence
90% confidence
Finding
The activation guidance says to use the skill whenever the user asks about database health, performance monitoring, connection counts, cache hit rate, or optimization advice. This covers a wide range of common PostgreSQL support questions and does not define exclusions or negative examples, making invocation boundaries ambiguous.

Context-Inappropriate Capability

Medium
Confidence
93% confidence
Finding
The documentation states the assistant can 'set up a scheduled task' for daily health checks, but the skill is presented as a PostgreSQL health-check tool and does not establish clear authorization, capability limits, or user-consent requirements for creating persistence. This can mislead an agent into taking side-effectful actions outside the expected scope of database inspection, increasing the risk of unauthorized recurring automation.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The scheduling example suggests creating a recurring daily task without warning the user that this establishes persistent automated behavior. In agent contexts, omission of a consent warning can cause users to unintentionally authorize repeated execution, which may consume resources, expose data repeatedly, or violate operational expectations.

Vague Triggers

Medium
Confidence
93% confidence
Finding
The trigger description includes broad phrases such as '慢查询、索引优化、性能调优、查询太慢、需要加索引时使用', which are common user intents and can cause the skill to activate in situations where the user did not explicitly request this specific capability. Because this skill can analyze workload data and potentially proceed toward SQL/index operations, over-broad invocation increases the risk of unintended database-facing actions or disclosure of query metadata.

Vague Triggers

Medium
Confidence
95% confidence
Finding
The skill advertises activation on broad, natural-language prompts like '查询为什么慢' and general database optimization requests without tight scoping or confirmation requirements. In an agentic environment, this can cause the skill to trigger in contexts where the user did not explicitly request query-plan analysis, leading to unintended database inspection or execution of EXPLAIN ANALYZE against production systems.

Vague Triggers

Medium
Confidence
90% confidence
Finding
The activation guidance is broad enough to trigger on generic PostgreSQL, database optimization, indexing, performance, and health-check requests, which can cause this skill to engage outside narrowly scoped schema-query tasks. In a skill that can generate and support execution of SQL against real databases, over-broad activation increases the chance of inappropriate tool use, unintended disclosure of schema metadata, or risky SQL assistance in contexts where a more constrained skill or extra confirmation should be used.

Vague Triggers

Medium
Confidence
89% confidence
Finding
The activation text is broad enough to trigger on many general PostgreSQL support conversations, including setup, optimization, and connection failures. Over-broad activation is risky because it can cause the skill to surface operational commands and credential-bearing examples in contexts where they were not specifically requested.

Rp1

Medium
Category
MCP Rug Pull
Confidence
89% confidence
Finding
The Docker example uses `ghcr.io/crystaldba/postgres-mcp:latest`, which is not immutable and can resolve to different image contents over time. Users following this guidance may run a modified or compromised image without noticing, increasing supply-chain exposure for a tool that receives database credentials.

Rp1

Medium
Category
MCP Rug Pull
Confidence
89% confidence
Finding
The SSE Docker deployment also relies on the mutable `latest` image tag, so the runtime artifact is not reproducible or integrity-stable. Because this service handles database connection strings and may be network exposed on port 8000, an unexpected image change could have direct security consequences.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The skill includes plaintext connection-string examples with embedded credentials and operational commands such as `kill <PID>` without an explicit warning about secret exposure, shell history leakage, config-file persistence, or terminating the wrong process. In a database administration context, this increases the chance of credential disclosure or accidental service disruption by users copying commands verbatim.

Natural-Language Policy Violations

Low
Confidence
88% confidence
Finding
The primary descriptive text is presented in Chinese, which may indicate the skill is intended to operate in a fixed language or locale. The file does not mention any user language choice, opt-in, or region-specific justification, so this can be a natural-language policy concern under the language/locale rule.

Rp1

Low
Category
MCP Rug Pull
Confidence
94% confidence
Finding
The skill instructs users to install `postgres-mcp` from PyPI without pinning a specific version or verifying integrity. This creates supply-chain risk because future package updates or a compromised release could change behavior unexpectedly and be pulled into the user's environment automatically.

Static analysis

No suspicious patterns detected.