Back to skill

Security audit

Gtm System

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches a GTM tracking tool, but it includes under-disclosed production CRM access and an embedded Exa API key that users should review before installing.

Install only after reviewing and disabling or fixing the sensitive integrations: remove and rotate the embedded Exa key, require explicit user-provided credentials, document all third-party API destinations, and gate HubSpot production sync behind clear configuration and confirmation. Treat the local SQLite database as containing sensitive CRM/contact data if hubspot-sync is used.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/gtm.py:673
Finding

Hard-Coded Exa API Credential

Content
View full analysis
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/gtm.py:772
Finding

Undocumented Retrieval of a Production HubSpot Secret and Local Replication of CRM PII

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Output HandlingUnvalidated Output Injection, Cross-Context Output, Unbounded Output
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (23)

Tainted flow: 'req' from os.environ.get (line 509, 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/gtm.py (reported line 434)May include surrounding context.

python
try:
                req = urllib.request.Request(url, headers={'User-Agent': 'GTM-Tracker/1.0'})
                with urllib.request.urlopen(req, timeout=15) as response:
                    data = json.loads(response.read().decode())
            except (urllib.error.URLError, ConnectionResetError, ssl.SSLError) as e:
                print(f"  ⚠️ Algolia error for '{query[:40]}': {e}")

Tainted flow: 'req' from os.environ.get (line 509, 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/gtm.py (reported line 514)May include surrounding context.

python
try:
                req = urllib.request.Request(url, headers={'User-Agent': 'GTM-Tracker/1.0'})
                with urllib.request.urlopen(req, timeout=15) as response:
                    data = json.loads(response.read().decode())
            except (urllib.error.URLError, ConnectionResetError, ssl.SSLError) as e:
                print(f"  ⚠️ Algolia error for '{query[:40]}': {e}")

Tainted flow: 'req' from os.environ.get (line 509, 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/gtm.py (reported line 822)May include surrounding context.

python
try:
                req = urllib.request.Request(url, headers={'User-Agent': 'GTM-Tracker/1.0'})
                with urllib.request.urlopen(req, timeout=15) as response:
                    data = json.loads(response.read().decode())
            except (urllib.error.URLError, ConnectionResetError, ssl.SSLError) as e:
                print(f"  ⚠️ Algolia error for '{query[:40]}': {e}")

Tainted flow: 'req' from os.environ.get (line 509, 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/gtm.py (reported line 565)May include surrounding context.

python
headers={'User-Agent': 'GTM-Tracker/1.0'}
            )
            try:
                with urllib.request.urlopen(req, timeout=10) as response:
                    data = json.loads(response.read().decode())
            except (urllib.error.URLError, json.JSONDecodeError):
                continue

Tainted flow: 'req' from os.environ.get (line 509, 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/gtm.py (reported line 634)May include surrounding context.

python
headers={'User-Agent': 'GTM-Tracker/1.0'}
            )
            try:
                with urllib.request.urlopen(req, timeout=10) as response:
                    data = json.loads(response.read().decode())
            except (urllib.error.URLError, json.JSONDecodeError):
                continue

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

Critical
Category
Data Flow
Confidence
93% confidence
Finding

The Exa request includes an API key sourced from the environment or a hardcoded fallback and transmits it to an external service. While that is functionally expected, embedding a fallback secret and automatically using it increases the chance of unauthorized service use, secret leakage, and accidental billing exposure if the code is redistributed.

Content

Scanner excerpt · scripts/gtm.py (reported line 717)May include surrounding context.

python
)

            try:
                with urllib.request.urlopen(req, timeout=15) as response:
                    data = json.loads(response.read().decode())
            except (urllib.error.URLError, json.JSONDecodeError) as e:
                print(f"  ⚠️ Exa query failed: {e}")

Missing User Warnings

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

A hardcoded default Exa API key in source code is a real secret-management vulnerability. Anyone with access to the code can reuse the key, incur charges, access associated account resources, and the secret is difficult to rotate once propagated.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The skill describes collecting data from multiple external sources and sending notifications through Telegram, yet it does not warn users that business/contact information and crawled content may be transmitted to third parties or stored in logs/cache. This creates privacy and data-handling risk, especially if personally identifiable information, business intelligence, or sensitive opportunity data is pushed through Telegram or external crawlers without explicit disclosure and minimization.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The README explicitly encourages unconstrained natural-language Telegram interactions such as adding notes and finding opportunities, but provides no indication of command scoping, confirmation requirements, or input validation. In an agent-driven environment, broad NL triggers can cause unintended state changes, prompt-injection propagation from chat content, or execution of sensitive actions from ambiguous user input.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The document positively recommends developer-signal and telemetry platforms that deanonymize sign-ups, track docs visits, API usage, and related behavioral signals without any accompanying privacy, consent, retention, or legal-compliance cautions. In a GTM strategy context, this omission can directly normalize collection of personal or pseudonymous user data in ways that create privacy, compliance, and reputational risk.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The section recommends website visitor identification tools and frames them as beneficial for seeing which companies visit the site, but does not warn about the tracking implications or limits of such identification. This is dangerous because teams may deploy these tools without evaluating consent requirements, notice obligations, IP-based identification accuracy, or whether the resulting data could be used in intrusive outreach.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill explicitly instructs users to run crawler commands against external sources (HN, Reddit, GitHub) but provides no warning that these actions require network access and may transmit system-identifying information such as IP address, request headers, query terms, or tracked keywords to third-party services. In an agent-skill context, undisclosed network activity is risky because users may invoke the commands expecting only local GTM workflow operations, while the crawl feature reaches outside the trust boundary.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/gtm.py (reported line 510)May include surrounding context.

python
for query in pain_queries:
                encoded = urllib.parse.quote(query)
                req = urllib.request.Request(
                    f'https://api.search.brave.com/res/v1/web/search?q={encoded}&count=10&freshness=pm',
                    headers={'X-Subscription-Token': brave_key, 'Accept': 'application/json'}
                )
                try:

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/gtm.py (reported line 627)May include surrounding context.

python
try:
        for term in search_terms:
            req = urllib.request.Request(
                f'https://api.github.com/search/repositories?q={term}&sort=updated&per_page=20',
                headers={
                    'User-Agent': 'GTM-Tracker/1.0',
                    'Accept': 'application/vnd.github.v3+json'

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/gtm.py (reported line 705)May include surrounding context.

python
}).encode()

            req = urllib.request.Request(
                'https://api.exa.ai/search',
                data=payload,
                headers={
                    'Content-Type': 'application/json',

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The hubspot_sync routine retrieves a CRM access token, calls the HubSpot API, and pulls contact records including names, emails, companies, and engagement timestamps into the local database. While there are status prints during execution, there is no explicit warning in code comments, prompts, or surrounding documentation that this command processes potentially sensitive contact data from an external service and stores it locally.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/gtm.py (reported line 774)May include surrounding context.

python
# Get HubSpot API token
    try:
        result = subprocess.run(
            ['doppler', 'secrets', 'get', 'HUBSPOT_API_TOKEN', '--plain', '--project', 'openclaw-server', '--config', 'prd'],
            capture_output=True, text=True, timeout=10
        )

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/gtm.py (reported line 811)May include surrounding context.

python
thirty_days_ago = (datetime.now() - timedelta(days=30)).strftime('%Y-%m-%d')
        
        # HubSpot contacts API with engagement filter
        contacts_url = f"https://api.hubapi.com/crm/v3/objects/contacts?limit=100&properties=firstname,lastname,email,company,jobtitle,lastmodifieddate,hs_latest_open_date,hs_latest_click_date"
        
        req = urllib.request.Request(
            contacts_url,

Unbounded Output

Medium
Category
Output Handling
Confidence
80% confidence
Finding

Output size or generation rate is not bounded. Unbounded output enables denial-of-service through resource exhaustion, log flooding, or context-window stuffing.

Content

Scanner excerpt · scripts/gtm.py (reported line 1146)May include surrounding context.

python
high_items = [e for e in escalations if e['priority'] == 'HIGH']
        if high_items:
            output.append("**HIGH:**")
            for e in high_items[:3]:  # Limit to top 3 to avoid spam
                output.append(f"  • {e['message']}")
    
    conn.close()

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The webhook example ingests third-party signals and stores request data directly with no warning about sanitization, minimization, retention, or access controls for potentially user-related information. Although it is only illustrative documentation, it can encourage implementers to persist external behavioral data by default, increasing privacy and data-governance risk.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
82% confidence
Finding

This markdown file instructs users to identify companies, use LinkedIn Sales Navigator, gather contact details, and send personalized cold emails, which implies processing prospect personal/business data. It does not include any warning about privacy, consent, or compliance considerations for outreach and data handling.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

The document proposes a web page with a lead capture form, which would collect user information, but provides no disclosure about privacy, retention, or secure handling of submitted data. For a markdown skill description, this is a user-data-affecting behavior that should be explicitly warned about.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

The docstring for generate_daily_digest says it is suitable for sending via Telegram, which implies messaging-oriented behavior, but the implementation only builds a markdown-like string, prints it, and returns it. This is a documentation-to-code mismatch because no Telegram integration or delivery occurs.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.