Back to skill

Security audit

SQL Query Generator

Security checks for vulnerabilities and agentic risk

Overview

This skill is a coherent SQL helper, but its strong security claims are not matched by the implementation and it can persist sensitive query/user data in logs.

Review generated SQL manually before running it, especially UPDATE, DELETE, DROP, ALTER, migration, or backup statements. Do not pass untrusted text into raw condition/join/having arguments. Disable or tightly configure audit logging unless you have a retention and access-control plan, because logs may contain user identifiers and sensitive query details.

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

T09 · Insecure Skill Coding Practices

Error
Location
sql_query_generator.py:498
Finding

Unvalidated SQL Fragments Permit SQL Injection

Content
View full analysis

Vulnerability Details

File Location: sql_query_generator.py:498-511
Vulnerability Type: SQL injection through unvalidated query fragments
Risk Level: High

Vulnerable Code:

python
query += f"{join_type} JOIN\n    {join_table} ON {join['on']}\n"

if where_conditions:
    query += "WHERE\n    " + "\n    AND ".join(where_conditions) + "\n"

if group_by:
    validated_group_by = [
        self.validator.validate_identifier(col, security_level=self.security_level)
        for col in group_by
    ]
    query += "GROUP BY\n    " + ",\n    ".join(validated_group_by) + "\n"

if having:
    query += f"HAVING\n    {having}\n"

Technical Analysis

Although table names, column names, and ordering directions receive allowlist validation, the following caller-supplied SQL fragments are inserted directly into the generated query:

  • join['on']
  • Elements of where_conditions
  • having

These inputs are neither parsed into structured expressions nor checked against a strict grammar. They are also not converted into placeholders with separately returned parameter values. Consequently, an attacker who can influence any of these arguments can append arbitrary SQL syntax.

The documented claim that parameterization is mandatory does not mitigate this issue because the generator accepts complete predicate strings rather than enforcing parameterized predicate construction.

Attack Path

  1. An application accepts reporting, filtering, or join criteria from an untrusted user.
  2. The application passes attacker-controlled content to where_conditions, joins[*]['on'], or having.
  3. The attacker supplies a fragment such as 1 = 1; DROP TABLE users--, subject to the capabilities of the database driver.
  4. generate_select_query() concatenates the fragment into the SQL output without validation.
  5. The application executes the generated query using a database connection.
  6. The inject ...[truncated 760 chars]
Remediation
View remediation

Remediation Suggestions

  1. Replace raw SQL fragment arguments with a structured expression model containing separately validated fields:
    • Column identifier
    • Operator selected from a fixed allowlist
    • Bound value
    • Boolean connector selected from AND or OR
  2. Return parameter values separately from generated SQL and require database-driver binding.
  3. Validate every JOIN operand as an identifier and permit only explicitly supported comparison operators.
  4. Build HAVING expressions from validated aggregate functions, identifiers, operators, and placeholders.
  5. Reject semicolons, SQL comments, stacked statements, and malformed expressions as defense in depth. Pattern rejection must not replace structural parsing and parameterization.
  6. Consider using database-driver identifier composition APIs or a mature SQL abstract syntax tree/query-builder library.
  7. Add tests proving that attacker-controlled JOIN, WHERE, and HAVING fragments cannot introduce additional clauses or statements.

T09 · Insecure Skill Coding Practices

Warning
Location
sql_query_generator.py:309
Finding

Default Audit Logging Can Persist Sensitive Query and Event Data

Content
View full analysis

Vulnerability Details

File Location: sql_query_generator.py:309-348
Vulnerability Type: Plaintext sensitive-data exposure through audit logs
Risk Level: Medium

Vulnerable Code:

python
class SecurityAuditLogger:
    """Log all database operations for security auditing"""

    def __init__(self, log_file: str = 'sql_audit.log',
                 enable_console: bool = True):
        self.logger = logging.getLogger('sql_audit')
        self.logger.setLevel(logging.INFO)

        file_handler = logging.FileHandler(log_file)
        file_handler.setFormatter(logging.Formatter(
            '%(asctime)s - %(levelname)s - %(message)s'
        ))
        self.logger.addHandler(file_handler)

        if enable_console:
            console_handler = logging.StreamHandler()
            console_handler.setFormatter(logging.Formatter(
                '%(asctime)s - %(levelname)s - %(message)s'
            ))
            self.logger.addHandler(console_handler)

    def log_query(self, query: str, params: tuple, user_id: str,
                  ip_address: str, result_count: Optional[int] = None):
        """Log query execution"""
        log_entry = {
            'timestamp': datetime.utcnow().isoformat(),
            'user_id': user_id,
            'ip_address': ip_address,
            'query': SQLInputValidator.sanitize_for_logging(query),
            'param_count': len(params) if params else 0,
            'result_count': result_count
        }
        self.logger.info(json.dumps(log_entry))

    def log_security_event(self, event_type: str, details: Dict[str, Any],
                          severity: str = 'WARNING', user_id: Optional[str] = None):
        """Log security events"""
        log_entry = {
            'timestamp': datetime.utcnow().isoformat(),
            'event_type': event_type,
            'severity': severity,
            'user_id': user_id,
     
...[truncated 2304 chars]
Remediation
View remediation

Remediation Suggestions

  1. Disable audit logging by default and require explicit opt-in.
  2. Log a query fingerprint, operation type, timing, and outcome instead of complete SQL.
  3. Never log bound parameter values, database connection strings, authentication material, or authorization headers.
  4. Recursively sanitize all security-event dictionaries before serialization.
  5. Use an allowlist of safe metadata fields rather than relying exclusively on sensitive-pattern detection.
  6. Create log files with restrictive permissions, such as owner read/write only, and document required ownership.
  7. Add rotation, retention, deletion, and access-review controls.
  8. Make console logging separately configurable and disabled by default.
  9. Prevent duplicate handlers when multiple generator instances are created.
  10. Add tests for alternate secret formats, nested event structures, email addresses, connection strings, and multiline values.

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:582
Finding

Skill Instructions Recommend Unsanitized Audit Logging

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:582-611 and duplicate content in skill.md:582-611
Vulnerability Type: Insecure logging guidance in agent-consumed Skill instructions
Risk Level: Medium

Vulnerable Code:

python
class SecurityAuditLogger:
    """Log all database operations for security auditing"""

    def __init__(self, log_file: str = '/var/log/sql_audit.log'):
        self.logger = logging.getLogger('sql_audit')
        handler = logging.FileHandler(log_file)
        handler.setFormatter(logging.Formatter(
            '%(asctime)s - %(levelname)s - %(message)s'
        ))
        self.logger.addHandler(handler)
        self.logger.setLevel(logging.INFO)

    def log_query(self, query: str, params: tuple, user_id: str,
                  ip_address: str, result_count: int = None):
        """Log query execution"""
        log_entry = {
            'timestamp': datetime.utcnow().isoformat(),
            'user_id': user_id,
            'ip_address': ip_address,
            'query': query,
            'param_count': len(params),
            'result_count': result_count
        }
        self.logger.info(json.dumps(log_entry))

    def log_security_event(self, event_type: str, details: Dict[str, Any],
                          severity: str = 'WARNING'):
        """Log security events"""
        log_entry = {
            'timestamp': datetime.utcnow().isoformat(),
            'event_type': event_type,
            'severity': severity,
            'details': details
        }

Technical Analysis

SKILL.md is intended to be consumed as operational guidance by an AI agent. Its audit-logging example records full SQL queries and arbitrary event details without sanitization. The same unsafe guidance appears in the duplicate lowercase skill.md.

SQL text may contain PII, credentials, authentication tokens, or business-sensitive literals. Arbitra ...[truncated 1447 chars]

Remediation
View remediation

Remediation Suggestions

  1. Replace the example in both SKILL.md and skill.md with a metadata-only logging design.
  2. Record a non-reversible query fingerprint rather than full SQL.
  3. Apply recursive, allowlist-based filtering to security-event metadata.
  4. Explicitly prohibit logging query parameters, connection strings, passwords, tokens, API keys, and authorization headers.
  5. Include restrictive file permissions, rotation, retention limits, and access-control requirements.
  6. Make audit logging opt-in and explain its privacy and compliance implications.
  7. Keep the uppercase and lowercase Skill documents synchronized to prevent agents from receiving inconsistent security guidance.
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (13)

Anti-Refusal Statement

High
Category
Anti-Refusal
Confidence
80% confidence
Finding

Skill instructs the agent to omit warnings, disclaimers, or ethical commentary. Stripping safety caveats hides risk from the user and is a common jailbreak preamble.

Content

Scanner excerpt · security_tests.py (reported line 186)May include surrounding context.

python
warnings = generator.validate_query_security(secure_query)
    
    if not warnings:
        print("✓ Secure query - No warnings")
    else:
        print(f"Warnings: {warnings}")

Anti-Refusal Statement

High
Category
Anti-Refusal
Confidence
80% confidence
Finding

Skill instructs the agent to omit warnings, disclaimers, or ethical commentary. Stripping safety caveats hides risk from the user and is a common jailbreak preamble.

Content

Scanner excerpt · security_tests.py (reported line 207)May include surrounding context.

python
warnings = generator.validate_query_security(secure_query)
    
    if not warnings:
        print("✓ Secure query - No warnings")
    else:
        print(f"Warnings: {warnings}")

Intent-Code Divergence

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The generator validates identifiers for tables and some columns, but it directly interpolates join['on'], where_conditions, and having into the SQL string without parsing, parameterization, or safe construction. In a skill explicitly advertised as generating secure SQL, this is especially dangerous because callers may trust these APIs and pass attacker-controlled fragments, leading to SQL injection or unsafe query generation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The README explicitly promotes complete audit logging including query history, user IDs, IP addresses, and execution results, but does not pair that guidance with retention limits, minimization guidance, access controls, or notice/consent considerations. In a SQL-generation skill, this can lead adopters to collect and persist sensitive operational and personal data by default, increasing privacy, compliance, and secondary breach risk if logs are exposed.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
86% confidence
Finding

The skill documents network-capable behavior such as cloning from GitHub and installing database drivers, but it does not declare any tool scope or permission boundaries. For an agent skill, this mismatch can cause operators to underestimate what the skill may induce an agent to do, increasing the chance of unintended network access or package retrieval.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill advertises support for INSERT/UPDATE/DELETE and DDL including CREATE, ALTER, and DROP, but the description does not prominently warn that it can generate destructive or irreversible SQL. In an agent setting, this omission is risky because users may treat generated statements as routine safe output and execute harmful changes without adequate review or environment safeguards.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill is presented as a SQL query generator, but it also includes code to establish live PostgreSQL connections and execute session-altering commands. This expands the effective capability from passive generation to active database interaction, which is dangerous because an agent or user may invoke real connections and change database state under the assumption the skill is read-only or advisory.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

Direct database connection creation is beyond the minimally necessary scope for a query generator and creates a path for unintended real-environment access. In agent contexts, this can turn a content-generation skill into one capable of interacting with production databases, increasing the risk of credential misuse, unauthorized queries, and state changes.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill includes filesystem-based audit logging despite being described primarily as a query-generation skill. Writing logs to local paths introduces additional side effects and data-handling risk, including leakage of query structure, user identifiers, IP addresses, and metadata to disk where retention and access controls may be weak or undefined.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The skill explicitly advertises generation of INSERT/UPDATE/DELETE and DDL such as CREATE, ALTER, and DROP without adjacent guardrails requiring confirmation, environment scoping, rollback guidance, or prominent destructive-action warnings. In an AI-agent context, this increases the chance that an agent will produce or encourage execution of irreversible or high-impact SQL against production systems, causing data loss or schema damage.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The surrounding security guidance repeatedly states that all dynamic SQL components must be safely handled, yet this builder constructs SELECT {columns} FROM {table} and column predicates via f-strings. While identifier validation reduces risk and dynamic identifiers cannot usually be bound as parameters, the documentation presents a stricter guarantee than the code actually enforces, creating an intent/code mismatch in a security-sensitive section.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The module docstring advertises specific security features including 'Prepared statement pooling' and 'Connection security'. However, the file only generates and analyzes SQL strings; it contains no database connection management, prepared statement cache/pool implementation, or transport/security handling for connections, so the documentation materially overstates what the code does.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The audit logger records user identifiers, IP addresses, query text, and result metadata to file and optionally console, but the code provides no consent, retention, minimization, or access-control safeguards. This can expose sensitive operational or personal data through logs, especially because SQL text may still contain business-sensitive information even after partial sanitization.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.