Back to skill

Security audit

Posthog Analytics

Security checks for vulnerabilities and agentic risk

Overview

This skill mostly matches its PostHog dashboard purpose, but it can send your PostHog API key to an arbitrary configured host, so it needs careful review before use.

Install only if you are comfortable giving the skill a read/write PostHog personal API key. Before running it, keep POSTHOG_HOST set only to trusted PostHog endpoints or a self-hosted PostHog instance you control, prefer a least-privilege API key, and run it against version-controlled or backed-up config files because create rewrites the JSON config in place.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/posthog_sync.sh:6
Finding

Unvalidated API Host Can Receive the PostHog Personal API Key

Content
View full analysis

Vulnerability Details

File Location: scripts/posthog_sync.sh, lines 6–8 and 14–18
Vulnerability Type: Unrestricted credential-bearing API destination
Risk Level: High

bash
: "${POSTHOG_PERSONAL_API_KEY:?Set POSTHOG_PERSONAL_API_KEY}"
POSTHOG_HOST="${POSTHOG_HOST:-us.i.posthog.com}"
POSTHOG_UI_HOST="${POSTHOG_UI_HOST:-us.posthog.com}"
API_BASE="https://${POSTHOG_HOST}/api/projects/@current"

api() {
  local method="$1" endpoint="$2"; shift 2
  curl -sS -X "$method" "${API_BASE}${endpoint}" \
    -H "Authorization: Bearer ${POSTHOG_PERSONAL_API_KEY}" \
    -H "Content-Type: application/json" "$@"
}

Technical Analysis

The script constructs API_BASE directly from the environment-controlled POSTHOG_HOST value without validating it against trusted PostHog endpoints. The api function then includes POSTHOG_PERSONAL_API_KEY as a bearer token in every request sent to that destination.

Although HTTPS protects transport confidentiality, it does not establish that the selected server belongs to PostHog. An attacker-controlled host with a valid TLS certificate can receive the authorization header. This issue becomes exploitable when an attacker can influence the script's environment, such as through a wrapper script, CI/CD configuration, task configuration, shell profile, or agent-provided environment variables.

Attack Path

  1. The victim configures a valid read/write POSTHOG_PERSONAL_API_KEY.
  2. An attacker or compromised execution environment sets POSTHOG_HOST to an attacker-controlled HTTPS hostname.
  3. The victim or automation invokes any command that performs an API request, such as create, sync, update, or export.
  4. API_BASE is constructed using the attacker-controlled hostname.
  5. curl connects to that hostname and sends Authorization: Bearer ${POSTHOG_PERSONAL_API_KEY}.
  6. The attacker records the credential and can use it directly against the legitimate PostHog API, subject to the key's assigned permiss ...[truncated 567 chars]
Remediation
View remediation

Remediation Suggestions

  1. Validate POSTHOG_HOST before constructing API_BASE.
  2. For PostHog Cloud, allow only exact trusted API hosts:
    • us.i.posthog.com
    • eu.i.posthog.com
  3. Reject values containing schemes, paths, user information, ports, query strings, fragments, wildcard suffixes, or unapproved subdomains.
  4. If self-hosted PostHog must be supported, require an explicit opt-in configuration and maintain a deployment-specific allowlist rather than accepting arbitrary environment values.
  5. Separate cloud and custom-host modes so a custom destination cannot be selected accidentally.
  6. Use API keys with the minimum required scopes and rotate the key immediately if it may have been exposed.
  7. Add automated tests confirming that attacker-controlled, lookalike, malformed, and non-allowlisted hostnames are rejected before any credential-bearing request occurs.

Example hardening for cloud-only operation:

bash
POSTHOG_HOST="${POSTHOG_HOST:-us.i.posthog.com}"

case "$POSTHOG_HOST" in
  us.i.posthog.com|eu.i.posthog.com)
    ;;
  *)
    echo "Error: Untrusted POSTHOG_HOST: $POSTHOG_HOST" >&2
    exit 1
    ;;
esac

API_BASE="https://${POSTHOG_HOST}/api/projects/@current"
Vulnerability Patterns
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (4)

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

The code generally matches the core theme of PostHog API-driven dashboard automation: it creates dashboards, syncs missing insights, updates existing insights, and exports dashboard configuration. It also uses the PostHog API as described. However, the declared description overstates capabilities in two material ways. First, it claims dashboard CRUD, but the script does not implement full CRUD for dashboards: there is dashboard creation and export/read, but no dashboard deletion and no general dashboard update endpoint usage beyond insight updates. Second, it explicitly claims cohort management, but there is no cohort creation, update, deletion, or retrieval logic. These are substantive capability mismatches rather than minor implementation details.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill documents and relies on shell execution (curl, jq, bash) but does not declare any tool scope or allowed-tools boundary. This weakens least-privilege controls and can cause the runtime or user to grant broader shell access than necessary, increasing the blast radius if the script or surrounding workflow is modified or abused.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The create command modifies the user's local JSON file by adding dashboard_id and replacing the original file via mv. While the code comments note the update, there is no user-facing warning in help text or documentation that running create will alter the input file.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

The documentation states that the script automatically updates the user's config file with dashboard_id, but does not prominently warn about this write side effect before execution. Unexpected file modification can lead to accidental overwrites, dirty working trees, or corruption of user-managed configuration, especially in automation contexts.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.