Back to skill

Security audit

databricks-helper

Security checks for vulnerabilities and agentic risk

Overview

This Databricks helper is mostly purpose-aligned, but it handles powerful workspace credentials and operations with weak scoping and safety controls.

Install only if you trust the publisher and can use a least-privilege Databricks token. Set DATABRICKS_HOST only to your HTTPS Databricks workspace, avoid running the installer in an environment containing secrets, require human confirmation before run/retry/cancel actions, and do not rely on the SQL denylist as a security boundary; enforce read-only access in Databricks permissions instead.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/databricks_helper.py:52
Finding

Bearer Token Can Be Transmitted to an Arbitrary or Plaintext Endpoint

Content
View full analysis
tuple[str, str]: host = os.environ.get("DATABRICKS_HOST", "").rstrip("/") token = os.environ.get("DATABRICKS_TOKEN", "") if not host or not token: print("ERROR: DATABRICKS_HOST and DATABRICKS_TOKEN must be set.") print("") print("Setup:") print(" export DATABRICKS_HOST=https://adb-xxxx.azuredatabricks.net") print(" export DATABRICKS_TOKEN=dapiXXXXXXXXXXXXXXXX") sys.exit(1) return host, token def build_url(host: str, api_version: str, path: str, params: Optional[Dict[str, str]] = None) -> str: url = f"{host}/api/{api_version}/{path}" if params: safe_params = {k: str(v) for k, v in params.items() if v is not None} query = urlencode(safe_params, doseq=True) url = f"{url}?{query}" return url def api_get(host: str, token: str, path: str, params: Optional[Dict[str, str]] = None, api_version: str = "2.1") -> Dict: url = build_url(host, api_version, path, params) req = urllib.request.Request(url, headers={"Authorization": f"Bearer {token}"}) try: with urllib.request.urlopen(req) as resp: return json.loads(resp.read()) except urllib.error.HTTPError as e: body = e.read().decode() print(f"HTTP {e.code}: {body}") sys.exit(1) def api_post(host: str, token: str, path: str, payload: Dict, api_version: str = "2.1") -> Dict: url = build_url(host, api_version, path) data = json.dumps(payload).encode() req = urllib.request.Request( url, data=data, headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"} ) try: with urllib.request.urlopen(req) as resp: body = resp.read() ...[truncated 2475 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/databricks_helper.py:430
Finding

Blacklist-Based SQL Validation Does Not Reliably Enforce Read-Only Execution

Content
View full analysis
bool: return os.environ.get("DATABRICKS_ALLOW_WRITE_SQL", "").lower() in {"1", "true", "yes", "on"} def is_sql_safe(query: str) -> bool: """Best-effort check that a statement is read-only.""" stripped = re.sub(r"(--.*?$)|(/\*.*?\*/)", "", query, flags=re.MULTILINE | re.DOTALL).strip() if not stripped: return False lowered = stripped.lower() forbidden = [ "insert", "update", "delete", "merge", "create", "alter", "drop", "truncate", "comment", "grant", "revoke", "replace", "set", "attach", "detach", "vacuum", "optimize", "use", "call", "refresh", "repair table" ] for keyword in forbidden: if re.search(rf"\b{keyword}\b", lowered): return False return True def apply_sql_limit(query: str, limit: Optional[int]) -> str: if not limit or limit <= 0: return query clean = query.strip().rstrip(";") lowered = clean.lower().lstrip() if lowered.startswith("select") or lowered.startswith("with"): return f"SELECT * FROM ({clean}) LIMIT {limit}" return query def execute_sql(host: str, token: str, query: str, warehouse_id: Optional[str], limit: int, timeout: int) -> None: if not warehouse_id: print("SQL warehouse is required. Set DATABRICKS_SQL_WAREHOUSE_ID or pass --warehouse.") sys.exit(1) if not allow_write_sql() and not is_sql_safe(query): print("Blocked query that appears to modify data. Set DATABRICKS_ALLOW_WRITE_SQL=true to override.") sys.exit(1) limited_query = apply_sql_limit(query, limit) wait = max(5, min(timeout, 120)) payload = { "statement": limited_query, "warehouse_id": warehouse_id, "disposition": "INLINE", ...[truncated 2692 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
SKILL.md:40
Finding

Installation Instructions Execute Mutable Unpinned Upstream Packages

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (11)

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

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/databricks_helper.py (reported line 82)May include surrounding context.

python
url = build_url(host, api_version, path, params)
    req = urllib.request.Request(url, headers={"Authorization": f"Bearer {token}"})
    try:
        with urllib.request.urlopen(req) as resp:
            return json.loads(resp.read())
    except urllib.error.HTTPError as e:
        body = e.read().decode()

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

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/databricks_helper.py (reported line 99)May include surrounding context.

python
url = build_url(host, api_version, path, params)
    req = urllib.request.Request(url, headers={"Authorization": f"Bearer {token}"})
    try:
        with urllib.request.urlopen(req) as resp:
            return json.loads(resp.read())
    except urllib.error.HTTPError as e:
        body = e.read().decode()

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

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

md
Environment:
    DATABRICKS_HOST              — e.g. https://adb-1234567890.12.azuredatabricks.net
    DATABRICKS_TOKEN             — personal access token
    DATABRICKS_SQL_WAREHOUSE_ID  — (for SQL/preview) default warehouse id
    DATABRICKS_ALLOW_WRITE_SQL   — set to true only if write SQL is allowed
    DATABRICKS_MAX_ROWS          — default max rows returned for SQL (default 200)

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

Scanner excerpt · scripts/databricks_helper.py (reported line 25)May include surrounding context.

python
Environment:
    DATABRICKS_HOST              — e.g. https://adb-1234567890.12.azuredatabricks.net
    DATABRICKS_TOKEN             — personal access token
    DATABRICKS_SQL_WAREHOUSE_ID  — (for SQL/preview) default warehouse id
    DATABRICKS_ALLOW_WRITE_SQL   — set to true only if write SQL is allowed
    DATABRICKS_MAX_ROWS          — default max rows returned for SQL (default 200)

Rp1

Medium
Category
MCP Rug Pull
Confidence
91% confidence
Finding

The install command uses npx clawhub@latest install databricks-helper, which pulls the latest package version at execution time rather than a pinned, reviewed release. This creates a supply-chain risk: a compromised upstream package or malicious new release could execute arbitrary code on the user's machine during installation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The README advertises operationally sensitive actions such as retrying and canceling Databricks runs without clearly warning about their production impact, authorization expectations, or need for confirmation. In this context, an AI agent or user could invoke these actions against real workloads, causing job interruption, duplicate processing, or disruption of production data pipelines.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

Several trigger phrases are broad enough that normal conversational requests could unintentionally activate a skill capable of inspecting jobs, querying logs, running SQL, or initiating operational actions in Databricks. In a skill with both read and write capabilities, accidental invocation increases the chance of unintended data access or job execution.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

Phrases like 'what's running in databricks', 'any failures in databricks', or generic operational wording can overlap with ordinary assistant requests and may invoke a privileged workspace-control skill more often than intended. Because the skill can cancel, retry, and trigger runs, ambiguous activation meaningfully raises operational and data-exposure risk.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
96% confidence
Finding

The installation command uses npx clawhub@latest, which fetches and executes the newest published package at install time without pinning to a specific trusted version. This creates a supply-chain risk: if the package is compromised or a breaking/malicious release is published, users of the skill may execute attacker-controlled code during installation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The run-details command prints logs, errors, and notebook output directly to stdout, which can expose secrets, credentials, personal data, or proprietary query results to users, calling agents, chat transcripts, or other downstream logging systems. In an agent skill context, this is more dangerous because tool output is often automatically surfaced or retained outside the original Databricks trust boundary.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The docstring for is_sql_safe says it is a 'Best-effort check that a statement is read-only,' and the CLI help for run-sql says 'Run a read-only SQL query.' However, execute_sql explicitly permits non-read-only statements when DATABRICKS_ALLOW_WRITE_SQL is enabled, so the documentation overstates the read-only guarantee.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.