Back to skill

Security audit

SQL Connector

Security checks for vulnerabilities and agentic risk

Overview

This SQL connector appears purpose-built for database access, but its broad write ability and unsafe credential/configuration handling need review before installation.

Install only if you intend to let agents access the configured SQL Server, and use a least-privileged database account rather than admin or production-wide credentials. Store .env securely, do not paste or print its contents, avoid the documented grep SQL_ diagnostic, and review the .env loading and write retry behavior before using this with sensitive or non-idempotent database operations.

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

T09 · Insecure Skill Coding Practices

Warning
Location
GETTING_STARTED.md:395
Finding

Credential Troubleshooting Command Exposes SQL Passwords

Content
View full analysis
_PASSWORD` - SQL authentication usernames - Internal and cloud database endpoints Consequently, following this instruction can print plaintext database passwords directly to the terminal. In an agent-operated environment, command output may also be copied into the agent context, execution logs, support tickets, chat transcripts, or diagnostic reports. The server-only command at line 162 is narrower and does not expose passwords, but the unrestricted command at line 395 exceeds what is necessary to verify whether required variables exist. ### Attack Path 1. A database connection fails or appears unavailable. 2. An operator or agent follows the documented troubleshooting procedure. 3. The command `grep SQL_ ~/.openclaw/workspace/.env` reads every SQL configuration entry. 4. Plaintext SQL passwords and usernames are printed to standard output. 5. Terminal capture, agent logging, command transcripts, or copied diagnostic output retains the secrets. 6. A party with access to that output authenticates to the configured SQL Server using the exposed account. ### Impact Assessment An attacker obtaining the output can acquire the privileges assigned to the exposed SQL account. Depending on database-side permissions, this may permit: - Reading confidential tables and records - Inserting or modifying application data - Deleting records - Executing stored procedures - Accessing other schemas available to the SQL principal The impact is limited by the ...[truncated 174 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
sql_connector.py:41
Finding

Untrusted Ancestor Environment File Can Override Database Configuration

Content
View full analysis
str | None: p = _pathlib.Path(os.path.abspath(__file__)).parent for _ in range(5): c = p / '.env' if c.exists(): return str(c) p = p.parent return None # NOTE: .env is loaded lazily inside get_connector() to avoid # side-effects at import time (clawhub security scan recommendation). # Module-level env vars (os.getenv) are still read at import for _BACKENDS, # but load_dotenv is deferred to first connector instantiation. _env_loaded = False def _ensure_env_loaded() -> None: """Load .env once, lazily, on first connector creation.""" global _env_loaded if not _env_loaded: _env = _find_env() if _env: load_dotenv(_env, override=True) _env_loaded = True ``` ### Technical Analysis The connector searches the module directory and up to four ancestor directories for the first file named `.env`. It does not require an explicitly trusted path and does not validate file ownership, permissions, or whether the discovered file belongs to the intended OpenClaw workspace. The call to `load_dotenv(..., override=True)` then replaces SQL settings already present in the process environment. This defeats the normal expectation that securely injected process variables take precedence over local files. If an attacker or another tenant can create or modify a `.env` file in a searched directory, they can supply an attacker-controlled: - SQL server hostname or IP address - Port - Database name - Username and password - Default backend selection The connector will subsequently send SQL authentication material, query text, query parameters, an ...[truncated 2048 chars]
Remediation
View remediation
None: global _env_loaded if not _env_loaded and env_path: path = _pathlib.Path(env_path).resolve(strict=True) load_dotenv(path, override=False) _env_loaded = True ``` 2. If automatic discovery is necessary, restrict it to one documented workspace root rather than walking arbitrary ancestors. 3. Change `override=True` to `override=False` so process-level secrets supplied by the deployment environment retain precedence. 4. Validate the selected file before loading it: - Confirm it is a regular file and not a symlink. - Confirm expected ownership. - Reject group- or world-writable files. - Reject paths outside the trusted workspace. 5. Allow deployments to disable `.env` loading entirely. 6. Consider validating database destinations against an application allowlist, particularly for production agents. 7. Add tests covering: - A malicious `.env` in an ancestor directory - Existing process variables that must not be overwritten - Symlinked and insecurely permissioned configuration files ]]>

T09 · Insecure Skill Coding Practices

Error
Location
sql_connector.py:210
Finding

Automatic Retry of Non-Idempotent Writes Can Duplicate Database Operations

Content
View full analysis
bool: """ Run INSERT / UPDATE / DELETE with parameterised binding. Returns True on success, False on failure after retries. """ for attempt in range(self.MAX_RETRIES): try: with self._connect() as conn: with conn.cursor() as cur: cur.execute(sql, params) conn.commit() return True except Exception as exc: _log.warning("execute attempt %d/%d: %s", attempt + 1, self.MAX_RETRIES, exc) if attempt < self.MAX_RETRIES - 1: time.sleep(self.RETRY_DELAY) _log.error("execute failed after %d attempts", self.MAX_RETRIES) return False ``` ### Technical Analysis The method retries every exception without distinguishing between: - Transient connection failures - SQL syntax errors - Authentication or permission failures - Constraint violations - Deadlocks and transaction errors - Failures occurring after the server committed the transaction but before the client received confirmation The last case creates an ambiguous commit condition. A SQL Server can successfully commit an INSERT, UPDATE, DELETE, or stored-procedure call and then lose the connection before the client observes success. The connector catches the resulting exception and repeats the entire operation on a new connection. Because the API accepts arbitrary SQL, the connector cannot assume writes are idempotent. Repeating operations such as inserting a record, incrementing a balance, advancing a task, or invoking a side-effecting stored procedure can produce duplicate or inconsistent state. The implementation also contradicts the documentation, which claims query errors are not retried an ...[truncated 1630 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
requirements.txt:1
Finding

Unbounded Dependency Versions Create Supply-Chain and Reproducibility Risk

Content
View full analysis
=2.2.0 python-dotenv>=1.0.0 ``` ### Technical Analysis Both runtime dependencies use open-ended minimum-version constraints. Package resolution can therefore install any future release, including a new major version, without source review or compatibility validation. These libraries execute inside the Skill's Python process. `pymssql` receives database endpoints and SQL credentials, while `python-dotenv` reads credential-bearing configuration files and modifies the process environment. A compromised or unexpectedly incompatible future release would consequently run in a security-sensitive position. The project does not include a lock file, hash-pinned requirements, or an upper version boundary. The resulting installation is not reproducible and can change even when the Skill source remains unchanged. No evidence indicates that the currently named packages are typosquatted or malicious. The finding concerns unsafe dependency resolution rather than a confirmed malicious dependency. ### Attack Path 1. A user installs or rebuilds the Skill at a later date. 2. The package manager resolves the newest releases satisfying the open-ended `>=` constraints. 3. A compromised, malicious, or incompatible future release is selected automatically. 4. Package code executes during installation, import, environment loading, or database connection. 5. Because the dependencies process database credentials and application data, compromised dependency code could access those resources with the privileges of the Skill process. ### Impact Assessment The maximum impact is bounded by the operating-system privileges of the Python process and the permissions of the configured SQL account. A compromised dependency could potentially: - Read process environment variables and d ...[truncated 386 chars]
Remediation
View remediation
\ --hash=sha256: python-dotenv== \ --hash=sha256: ``` 3. Install with hash verification: ```bash pip install --require-hashes -r requirements.txt ``` 4. Use an automated dependency-update process that runs tests and performs security review before changing pinned versions. 5. Scan dependencies and transitive dependencies with an established vulnerability scanner. 6. Fetch packages only from an explicitly trusted package index and retain reviewed build artifacts for production deployments. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (50)

Credential Access

High
Category
Privilege Escalation
Confidence
86% confidence
Finding

The troubleshooting step tells users to grep values from the .env file in the workspace, which can expose server identifiers and potentially sensitive configuration in shell history, terminals, logs, or screenshots. In shared or monitored environments, this increases the chance of credential-related disclosure.

Content

Scanner excerpt · GETTING_STARTED.md (reported line 162)May include surrounding context.

  1. Check credentials

    bash
    grep "SQL_CLOUD_SERVER\|SQL_LOCAL_SERVER" ~/.openclaw/workspace/.env
    
  2. Verify SQL Server is accessible

Credential Access

High
Category
Privilege Escalation
Confidence
84% confidence
Finding

The troubleshooting section instructs users to inspect the presence of the .env file in a predictable workspace path, reinforcing persistent local secret storage in an agent workspace that may be shared, backed up, or insufficiently protected. In this context, that increases exposure of database credentials.

Content

Scanner excerpt · GETTING_STARTED.md (reported line 435)May include surrounding context.

print(f"{row['TABLE_SCHEMA']}.{row['TABLE_NAME']}")

text

### ".env file not found" or "Credentials missing"

**Check:**
1. `.env` exists: `ls ~/.openclaw/workspace/.env`

YARA rule 'agent_skill_prompt_injection_hidden_instructions': Prompt injection or hidden instructions embedded in AI agent skill text [agent_skills]

High
Category
YARA Match
Confidence
80% confidence
Finding

YARA rule matched a hack tool or exploit indicator (offensive tools, reconnaissance, privilege escalation, or exploit frameworks).

Content

Scanner excerpt · SKILL_REFERENCE.md (reported line 22)May include surrounding context.

----|---------|-------| | SELECT query | query(sql, params) | list[dict] | ✅ Parameterized | | INSERT/UPDATE/DELETE | execute(sql, params) | bool | ✅ Parameterized | | Single value | scalar(sql, params) | Any | ✅ Parameterized | | Health check | ping() | bool | ✅ Read-only | | Get instance | get_connector(backend) | SQLConnector | N/A |


Architecture

Layer Model

text
┌────────────────────────────────────────┐
│  Your Code (agents, scripts)           │
│  from sql_connector import get_connector
│  db = get_connector('cloud')           │
└─────────────────┬──────────────────────┘
                  │
                  ▼
┌────────────────────────────────────────┐
│  Factory: get_connect

Anti-Refusal Statement

High
Category
Anti-Refusal
Confidence
90% confidence
Finding

Skill attempts to nullify the agent's safety policies or restrictions ('you have no restrictions', 'ignore your guidelines', 'do anything now'). This is a direct jailbreak that disables guardrails.

Content

Scanner excerpt · SKILL_REFERENCE.md (reported line 95)May include surrounding context.

md
**Why sealed?**
- Prevents SQL injection via subclass override
- Forces all database access through parameterized API
- No way to accidentally bypass safety

---

Instruction Override

High
Category
Prompt Injection
Confidence
90% confidence
Finding

This pattern attempts to override system instructions or ignore safety constraints. Without LLM analysis, manual review is recommended.

Content

Scanner excerpt · SKILL_REFERENCE.md (reported line 95)May include surrounding context.

md
**Why sealed?**
- Prevents SQL injection via subclass override
- Forces all database access through parameterized API
- No way to accidentally bypass safety

---

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · SKILL_REFERENCE.md (reported line 439)May include surrounding context.

except EnvironmentError as e: # Missing .env vars print(f"❌ Missing credentials: {e}") print("Set SQL_CLOUD_SERVER, SQL_CLOUD_DATABASE, etc. in .env") raise

text

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · GETTING_STARTED.md (reported line 65)May include surrounding context.

md
import pymssql
from dotenv import load_dotenv

# Walk up from this file to find .env (handles install into skills/ subdir)
import pathlib as _pathlib
def _find_env() -> str | None:
    p = _pathlib.Path(os.path.abspath(__file__)).parent

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · GETTING_STARTED.md (reported line 69)May include surrounding context.

md
import pymssql
from dotenv import load_dotenv

# Walk up from this file to find .env (handles install into skills/ subdir)
import pathlib as _pathlib
def _find_env() -> str | None:
    p = _pathlib.Path(os.path.abspath(__file__)).parent

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · GETTING_STARTED.md (reported line 145)May include surrounding context.

md
import pymssql
from dotenv import load_dotenv

# Walk up from this file to find .env (handles install into skills/ subdir)
import pathlib as _pathlib
def _find_env() -> str | None:
    p = _pathlib.Path(os.path.abspath(__file__)).parent

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · GETTING_STARTED.md (reported line 154)May include surrounding context.

md
import pymssql
from dotenv import load_dotenv

# Walk up from this file to find .env (handles install into skills/ subdir)
import pathlib as _pathlib
def _find_env() -> str | None:
    p = _pathlib.Path(os.path.abspath(__file__)).parent

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · GETTING_STARTED.md (reported line 191)May include surrounding context.

md
import pymssql
from dotenv import load_dotenv

# Walk up from this file to find .env (handles install into skills/ subdir)
import pathlib as _pathlib
def _find_env() -> str | None:
    p = _pathlib.Path(os.path.abspath(__file__)).parent

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · README.md (reported line 69)May include surrounding context.

md
import pymssql
from dotenv import load_dotenv

# Walk up from this file to find .env (handles install into skills/ subdir)
import pathlib as _pathlib
def _find_env() -> str | None:
    p = _pathlib.Path(os.path.abspath(__file__)).parent

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · README.md (reported line 199)May include surrounding context.

md
import pymssql
from dotenv import load_dotenv

# Walk up from this file to find .env (handles install into skills/ subdir)
import pathlib as _pathlib
def _find_env() -> str | None:
    p = _pathlib.Path(os.path.abspath(__file__)).parent

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · SKILL_REFERENCE.md (reported line 169)May include surrounding context.

md
import pymssql
from dotenv import load_dotenv

# Walk up from this file to find .env (handles install into skills/ subdir)
import pathlib as _pathlib
def _find_env() -> str | None:
    p = _pathlib.Path(os.path.abspath(__file__)).parent

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · SKILL_REFERENCE.md (reported line 190)May include surrounding context.

md
import pymssql
from dotenv import load_dotenv

# Walk up from this file to find .env (handles install into skills/ subdir)
import pathlib as _pathlib
def _find_env() -> str | None:
    p = _pathlib.Path(os.path.abspath(__file__)).parent

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · SKILL_REFERENCE.md (reported line 191)May include surrounding context.

md
import pymssql
from dotenv import load_dotenv

# Walk up from this file to find .env (handles install into skills/ subdir)
import pathlib as _pathlib
def _find_env() -> str | None:
    p = _pathlib.Path(os.path.abspath(__file__)).parent

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · SKILL_REFERENCE.md (reported line 201)May include surrounding context.

md
import pymssql
from dotenv import load_dotenv

# Walk up from this file to find .env (handles install into skills/ subdir)
import pathlib as _pathlib
def _find_env() -> str | None:
    p = _pathlib.Path(os.path.abspath(__file__)).parent

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · SKILL_REFERENCE.md (reported line 437)May include surrounding context.

md
import pymssql
from dotenv import load_dotenv

# Walk up from this file to find .env (handles install into skills/ subdir)
import pathlib as _pathlib
def _find_env() -> str | None:
    p = _pathlib.Path(os.path.abspath(__file__)).parent

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · sql_connector.py (reported line 41)May include surrounding context.

python
import pymssql
from dotenv import load_dotenv

# Walk up from this file to find .env (handles install into skills/ subdir)
import pathlib as _pathlib
def _find_env() -> str | None:
    p = _pathlib.Path(os.path.abspath(__file__)).parent

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · sql_connector.py (reported line 52)May include surrounding context.

python
import pymssql
from dotenv import load_dotenv

# Walk up from this file to find .env (handles install into skills/ subdir)
import pathlib as _pathlib
def _find_env() -> str | None:
    p = _pathlib.Path(os.path.abspath(__file__)).parent

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · sql_connector.py (reported line 59)May include surrounding context.

python
import pymssql
from dotenv import load_dotenv

# Walk up from this file to find .env (handles install into skills/ subdir)
import pathlib as _pathlib
def _find_env() -> str | None:
    p = _pathlib.Path(os.path.abspath(__file__)).parent

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · sql_connector.py (reported line 75)May include surrounding context.

python
import pymssql
from dotenv import load_dotenv

# Walk up from this file to find .env (handles install into skills/ subdir)
import pathlib as _pathlib
def _find_env() -> str | None:
    p = _pathlib.Path(os.path.abspath(__file__)).parent

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · sql_connector.py (reported line 99)May include surrounding context.

python
import pymssql
from dotenv import load_dotenv

# Walk up from this file to find .env (handles install into skills/ subdir)
import pathlib as _pathlib
def _find_env() -> str | None:
    p = _pathlib.Path(os.path.abspath(__file__)).parent

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · sql_connector.py (reported line 114)May include surrounding context.

python
import pymssql
from dotenv import load_dotenv

# Walk up from this file to find .env (handles install into skills/ subdir)
import pathlib as _pathlib
def _find_env() -> str | None:
    p = _pathlib.Path(os.path.abspath(__file__)).parent

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · sql_connector.py (reported line 117)May include surrounding context.

python
import pymssql
from dotenv import load_dotenv

# Walk up from this file to find .env (handles install into skills/ subdir)
import pathlib as _pathlib
def _find_env() -> str | None:
    p = _pathlib.Path(os.path.abspath(__file__)).parent

Static analysis

No suspicious patterns detected.