Back to skill

Security audit

Ahc Automator

Security checks for vulnerabilities and agentic risk

Overview

The skill is purpose-built for AHC automation, but it can read local email, store API tokens insecurely, and automatically change business systems with weak safeguards.

Review before installing. Use only with approved AHC mailboxes and least-privilege ClickUp/Pipedrive tokens, avoid custom config files from untrusted sources, remove the hard-coded sample email behavior, and do not store API tokens in shell startup files.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/setup.py:173
Finding
API tokens are persisted in plaintext and unsafely interpolated into shell startup files<![CDATA[ ## Vulnerability Details **File Location**: `scripts/setup.py:173-213` **Additional Location**: `docs/README.md:61-69` **Vulnerability Type**: T09: Insecure Skill Coding Practices **Risk Level**: High ### Vulnerable Code ```python value = input(f" Digite {var['name']}: ").strip() if value: # Adicionar ao shell profile shell_commands.append(f'export {var["name"]}="{value}"') os.environ[var['name']] = value # Para esta sessão print(f" ✅ {var['name']} configurado") ``` ```python def save_to_shell_profile(self, commands): """Salvar comandos no profile do shell""" try: # Detectar shell shell = os.environ.get('SHELL', '/bin/bash') if 'zsh' in shell: profile_file = Path.home() / '.zshrc' else: profile_file = Path.home() / '.bash_profile' print(f"\n 📝 Adicionando ao {profile_file}") with open(profile_file, 'a') as f: f.write('\n# AHC-Automator Environment Variables\n') for cmd in commands: f.write(f'{cmd}\n') ``` The documentation recommends the same plaintext storage pattern: ```bash echo 'export CLICKUP_API_TOKEN="seu_token_clickup"' >> ~/.zshrc echo 'export PIPEDRIVE_API_TOKEN="seu_token_pipedrive"' >> ~/.zshrc source ~/.zshrc ``` ### Technical Analysis The setup process permanently stores ClickUp and Pipedrive API tokens in `.zshrc` or `.bash_profile`. These files are ordinary plaintext files and may be exposed through backups, support archives, shell configuration synchronization, local malware, accidental repository commits, or access by another process running as the same user. The entered value is also inserted directly into shell syntax without escaping. A value containing a double quote, newline, command substitution, or additional shell commands can break out of the intended `export` statement. The injected content executes whenever the user starts a shell or explicitly sources the profile. Fo ...[truncated 1586 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not write secrets into shell startup files by default. 2. Store tokens in an operating-system secret store such as macOS Keychain, or use a dedicated secrets manager. 3. If environment files must be supported: - Use a dedicated file rather than `.zshrc` or `.bash_profile`. - Create it with mode `0600`. - Never print its contents. - Clearly obtain explicit consent before permanent storage. 4. Avoid generating shell source code from user input. If unavoidable, serialize values using a robust shell-quoting function such as `shlex.quote()`. 5. Use `getpass.getpass()` instead of `input()` so tokens are not displayed on screen. 6. Check and enforce restrictive permissions before writing. 7. Update the README to recommend Keychain or another secure secret mechanism. 8. Rotate tokens previously stored in shell profiles and remove old plaintext entries. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/ahc_utils.py:57
Finding
Configuration-controlled API base URLs can redirect credentials and business data to arbitrary servers<![CDATA[ ## Vulnerability Details **File Location**: `scripts/ahc_utils.py:57-155` **Vulnerability Type**: T09: Insecure Skill Coding Practices **Risk Level**: High ### Vulnerable Code ```python class ClickUpClient: """Cliente ClickUp para operações de API""" def __init__(self, config): self.config = config self.api_token = self.config.get_env_or_config( 'CLICKUP_API_TOKEN', 'clickup', 'api_token' ) self.team_id = self.config.get('clickup', 'team_id') self.base_url = self.config.get( 'clickup', 'api_url', default='https://api.clickup.com/api/v2' ) if not self.api_token: raise Exception("ClickUp API token não encontrado") def _request(self, method, endpoint, data=None): """Fazer requisição para API ClickUp""" url = f"{self.base_url}/{endpoint}" headers = { 'Authorization': f'Bearer {self.api_token}', 'Content-Type': 'application/json' } if data and method in ['POST', 'PUT']: data = json.dumps(data).encode('utf-8') req = urllib.request.Request( url, data=data, headers=headers, method=method ) try: response = urllib.request.urlopen(req) result = json.loads(response.read().decode()) return {"success": True, "data": result} except Exception as e: return {"success": False, "error": str(e)} ``` ```python class PipedriveClient: """Cliente Pipedrive para operações de CRM""" def __init__(self, config): self.config = config self.api_token = self.config.get_env_or_config( 'PIPEDRIVE_API_TOKEN', 'pipedrive', 'api_token' ) self.base_url = self.config.get( 'pipedrive', 'api_url', default='https://api.pipedrive.com/v1' ) if not self.api_token: raise Exception("Pipedrive API token não ...[truncated 3267 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove configurable API origins unless custom deployments are a documented requirement. 2. Enforce exact HTTPS origins: - `https://api.clickup.com` - `https://api.pipedrive.com` 3. Parse URLs with `urllib.parse.urlsplit()` and reject: - Non-HTTPS schemes. - Embedded user information. - Unexpected ports. - Unapproved hostnames. - Loopback, private, link-local, and metadata-service addresses. 4. Prevent redirects to unapproved origins, especially when authorization headers are present. 5. Separate endpoint paths from trusted origins; do not permit full URLs in endpoint values. 6. Require an explicit, high-visibility opt-in before using any nonstandard API endpoint. 7. Add tests proving that malicious configuration files, HTTP URLs, redirects, and internal IP addresses are rejected. 8. Rotate tokens if the skill has been run with an untrusted configuration. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/ahc_utils.py:139
Finding
Pipedrive API token is exposed in request query strings<![CDATA[ ## Vulnerability Details **File Location**: `scripts/ahc_utils.py:139-155` **Vulnerability Type**: T09: Insecure Skill Coding Practices **Risk Level**: Medium ### Vulnerable Code ```python def _request(self, method, endpoint, data=None): """Fazer requisição para API Pipedrive""" url = f"{self.base_url}/{endpoint}" # Adicionar API token separator = '&' if '?' in url else '?' url = f"{url}{separator}api_token={self.api_token}" if data and method in ['POST', 'PUT']: data = json.dumps(data).encode('utf-8') req = urllib.request.Request(url, data=data, method=method) req.add_header('Content-Type', 'application/json') else: req = urllib.request.Request(url, method=method) try: response = urllib.request.urlopen(req) result = json.loads(response.read().decode()) return { "success": result.get('success', True), "data": result.get('data') } except Exception as e: return {"success": False, "error": str(e)} ``` ### Technical Analysis The Pipedrive token is appended to every URL as `api_token=<secret>`. Query strings are commonly captured by reverse proxies, web server access logs, monitoring platforms, network debugging tools, exception reporting systems, and security appliances. HTTPS protects the URL in transit from passive network observers, but it does not prevent the full request target from being recorded at either endpoint or by trusted infrastructure. The risk is amplified by the configurable base URL and by callers that include returned error details in logs. ### Attack Path 1. A legitimate workflow sends a Pipedrive request. 2. The full request target contains the API token in its query string. 3. A proxy, server, monitoring agent, debugging tool, or attacker-controlled configured endpoint records the URL. 4. An individual with access to those logs extracts the token. 5. The token is replayed directly against Pipedr ...[truncated 317 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Use Pipedrive's supported authorization-header mechanism instead of query-string authentication. 2. Keep tokens out of URLs, exception messages, application logs, and telemetry. 3. Add centralized secret-redaction logic for `api_token`, `Authorization`, and known token values. 4. Configure HTTP logging components to omit query strings where possible. 5. Use short-lived or narrowly scoped credentials if supported. 6. Rotate the current Pipedrive token after migrating the authentication method. 7. Add automated tests asserting that generated URLs never contain credential material. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/ahc_utils.py:243
Finding
Configuration-controlled email account names are injected into AppleScript source<![CDATA[ ## Vulnerability Details **File Location**: `scripts/ahc_utils.py:243-264` **Vulnerability Type**: T09: Insecure Skill Coding Practices **Risk Level**: High ### Vulnerable Code ```python # Usar AppleScript para acessar Apple Mail for account in accounts: script = f''' tell application "Mail" set recentEmails to {{}} repeat with theAccount in accounts if (name of theAccount) contains "{account}" then repeat with theMailbox in mailboxes of theAccount repeat with theMessage in messages of theMailbox set messageDate to date received of theMessage if messageDate > (current date) - (5 * minutes) then set end of recentEmails to {{subject:(subject of theMessage), sender:(sender of theMessage as string), content:(content of theMessage), date_received:messageDate}} end if end repeat end repeat end if end repeat return recentEmails end tell ''' result = subprocess.run( ['osascript', '-e', script], capture_output=True, text=True ) ``` ### Technical Analysis An account name read from configuration is directly inserted into AppleScript source between double quotes. No AppleScript escaping or parameter binding is used. A malicious account string can terminate the string literal and append arbitrary AppleScript statements. AppleScript supports `do shell script`, which permits local command execution. Although `subprocess.run()` correctly avoids `shell=True`, that protection is ineffective because the generated AppleScript itself is the injection target. Exploitation requires control over the configuration or another path that supplies the `accounts` collection. The scripts' `--config` option provides a practical route to using attacker-crafted account values. ### Attack Path 1. An attacke ...[truncated 950 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Never construct AppleScript by interpolating untrusted values into source text. 2. Pass account names as `osascript` arguments and read them from `argv` in an AppleScript `run` handler. 3. Alternatively, use a robust AppleScript string encoder that escapes quotes, backslashes, line breaks, and control characters. 4. Validate configured accounts against an explicit allowlist of expected email addresses. 5. Reject account values containing control characters or AppleScript metacharacters. 6. Treat custom configuration files as untrusted and validate them against a strict schema before use. 7. Add tests with quotes, newlines, `do shell script`, and other injection payloads. 8. Run email processing with the least macOS automation and filesystem privileges required. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/ahc_utils.py:274
Finding
Email parser always returns a hard-coded sample message, causing repeated unauthorized ClickUp writes<![CDATA[ ## Vulnerability Details **File Location**: `scripts/ahc_utils.py:274-282` **Execution Path**: `scripts/email_to_clickup_pipedrive.py:54-104` **Vulnerability Type**: T09: Insecure Skill Coding Practices **Risk Level**: High ### Vulnerable Code ```python # Retornar dados de exemplo para teste return [ { 'sender': 'ian@alanharpercomposites.com.br', 'subject': 'Nova tarefa ClickUp', 'body': 'Preciso adicionar tarefa para revisar lista de convidados', 'date_received': datetime.now() } ] ``` The production workflow processes every returned item and creates a task: ```python emails = self.email_parser.get_recent_emails( monitor_accounts, since_time ) for email in emails: self.process_single_email(email) ``` ```python if self.email_parser.contains_keywords(email, 'clickup'): self.handle_clickup_request(email) ``` ```python task_result = self.clickup.create_task( list_id=task_data.get( 'list_id', self.config.get('clickup', 'templates', 'standard') ), name=task_data.get( 'name', f"Solicitação de {email['sender']}" ), description=task_data.get( 'description', email['body'] ), assignees=task_data.get('assignees', []), priority=task_data.get('priority', 3), due_date=task_data.get('due_date') ) ``` ### Technical Analysis The Apple Mail query result is never parsed. Regardless of whether Apple Mail returns messages, returns no messages, fails, or access is unavailable, `get_recent_emails()` always returns a synthetic message containing a configured ClickUp keyword. The production processor therefore treats test data as a real email and creates a ClickUp task on every execution. The declared deployment model recommends execution every five minutes through existing cron jobs, which can produce approximately 288 duplicate tasks per day. This is not a hidden persistence mechanism: the code only reads existing crontab en ...[truncated 1206 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove all fixture data from production code. 2. Return an empty list when no messages are available or when parsing is not implemented. 3. Parse actual Apple Mail results into a defined message structure before processing. 4. Fail closed when Apple Mail access or parsing fails; do not substitute synthetic records. 5. Introduce an explicit `--demo` or `--dry-run` mode for sample data and prohibit external writes in that mode. 6. Add idempotency controls based on a stable email message ID. 7. Persist processed message IDs so scheduler reruns cannot recreate the same task. 8. Validate sender, account, timestamp, and message ID before any CRM mutation. 9. Require confirmation or an approval queue until email parsing is production-ready. 10. Add mocked tests proving that zero emails create zero tasks and that repeated processing does not duplicate records. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (60)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The documented behavior does not cleanly match the declared purpose: it includes WhatsApp notification handling, logging, and references to automation components that are not fully represented in the manifest. Description-behavior mismatch is dangerous because users and security controls may approve the skill for one purpose while it performs additional communication and operational actions, enabling covert data propagation or unexpected side effects.

Missing User Warnings

High
Confidence
95% confidence
Finding
The function accesses Apple Mail content, including sender, subject, and message body, without any visible consent, prompt, or disclosure mechanism. Silent collection of recent email content is highly sensitive and particularly risky because this skill is for workflow automation, where users may not expect host mailbox scraping.

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill documents capabilities that imply shell execution, filesystem access, environment-variable use, and network/API operations, but it does not declare any explicit tool scope or permission boundaries. In an automation skill that processes email and updates third-party systems, missing scope declarations increases the chance of over-privileged execution, unintended data access, and abuse of local/system resources.

Vague Triggers

Medium
Confidence
90% confidence
Finding
The trigger phrases include broad terms like client onboarding and project completion, which are common across many business contexts and not uniquely bound to Alan Harper Composites. Overbroad activation can cause the skill to run in unintended contexts, increasing the risk of processing the wrong user's data, initiating external actions unexpectedly, or exposing internal business automations where they do not belong.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The skill describes automatic monitoring and parsing of email content from named accounts without an explicit privacy warning or consent boundary. Because emails commonly contain personal, commercial, and operationally sensitive information, silent or underspecified monitoring creates privacy, compliance, and data-handling risks, especially when data is forwarded into ClickUp, Pipedrive, logs, and notifications.

Context-Inappropriate Capability

Medium
Confidence
90% confidence
Finding
The skill states that email processing leverages Apple Mail via osascript integration, which introduces local script-execution capability. Even if intended for benign automation, osascript materially expands the attack surface because email-derived content or workflow parameters could be routed into system-level scripting paths, enabling local command execution or unauthorized access to desktop mail data.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
The configuration monitors a personal Gmail account alongside a corporate address for AHC-specific business automation, which expands processing beyond clearly scoped business systems. This creates a real risk of unauthorized collection of personal communications and accidental triggering of business actions from non-corporate email, especially because downstream automations can create tasks and deals automatically.

Vague Triggers

Medium
Confidence
91% confidence
Finding
The trigger keywords are broad and common terms such as 'clickup', 'pipedrive', 'add deal', and 'nova tarefa', while workflows are configured to auto-create tasks and deals. This makes unintended activation plausible from ordinary email content, forwarded messages, signatures, or casual discussion, leading to unauthorized or erroneous changes in external business systems.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The README describes automated monitoring and processing of email accounts, including parsing content and triggering downstream actions, but does not warn about privacy, consent, retention, or handling of sensitive business data. Because this skill processes potentially confidential communications and customer information, missing privacy guidance increases the risk of unauthorized or noncompliant deployment.

Intent-Code Divergence

Medium
Confidence
97% confidence
Finding
The README presents WhatsApp as an implemented integration in the overview, but later states that real WhatsApp integration is not implemented. This inconsistency can mislead operators into assuming messages are actually being delivered, causing missed alerts, incorrect workflow expectations, and unsafe business reliance on a nonexistent notification channel.

Intent-Code Divergence

Medium
Confidence
96% confidence
Finding
The workflow diagram claims real-time WhatsApp notifications occur automatically, while later troubleshooting states notifications are only logged and the real integration is pending. In an automation skill handling project and client workflows, this can create operational blind spots if staff depend on urgent notifications that are never sent.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The onboarding workflow documentation explains how to create clients, projects, deals, and related records in external systems, but does not clearly warn that these are real side effects. Users may treat the script like a dry-run helper and unintentionally create persistent CRM/project records, leading to data pollution, accidental customer creation, or business process errors.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The project completion workflow can trigger invoicing, generate reports, and notify stakeholders, yet the documentation does not emphasize that these may be irreversible or business-critical actions. In a production operations context, silent execution of completion steps can cause premature billing, inaccurate status changes, or unintended customer/stakeholder communication.

Session Persistence

Medium
Category
Rogue Agent
Content
**Solução**:
```bash
# Verificar cron jobs
crontab -l

# Verificar se IDs estão presentes:
# 7c4c353d-55dd-4de9-b315-344f68e147e1 (Ian ClickUp)
Confidence
85% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Session Persistence

Medium
Category
Rogue Agent
Content
**Solução**:
```bash
# Verificar cron jobs
crontab -l

# Verificar se IDs estão presentes:
# 7c4c353d-55dd-4de9-b315-344f68e147e1 (Ian ClickUp)
Confidence
85% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Session Persistence

Medium
Category
Rogue Agent
Content
**Solução**:
```bash
# Verificar cron jobs
crontab -l

# Verificar se IDs estão presentes:
# 7c4c353d-55dd-4de9-b315-344f68e147e1 (Ian ClickUp)
Confidence
85% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
This code accesses credentials from environment variables and configuration, then transmits task and CRM data to external ClickUp and Pipedrive APIs. Although the functions have internal docstrings, there is no user-facing warning, confirmation, or visible disclosure that credentials and potentially user data will be sent to third-party services.

External Transmission

Medium
Category
Data Exfiltration
Content
self.config = config
        self.api_token = self.config.get_env_or_config('CLICKUP_API_TOKEN', 'clickup', 'api_token')
        self.team_id = self.config.get('clickup', 'team_id')
        self.base_url = self.config.get('clickup', 'api_url', default='https://api.clickup.com/api/v2')
        
        if not self.api_token:
            raise Exception("ClickUp API token não encontrado")
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
self.config = config
        self.api_token = self.config.get_env_or_config('CLICKUP_API_TOKEN', 'clickup', 'api_token')
        self.team_id = self.config.get('clickup', 'team_id')
        self.base_url = self.config.get('clickup', 'api_url', default='https://api.clickup.com/api/v2')
        
        if not self.api_token:
            raise Exception("ClickUp API token não encontrado")
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
def __init__(self, config):
        self.config = config
        self.api_token = self.config.get_env_or_config('PIPEDRIVE_API_TOKEN', 'pipedrive', 'api_token')
        self.base_url = self.config.get('pipedrive', 'api_url', default='https://api.pipedrive.com/v1')
        
        if not self.api_token:
            raise Exception("Pipedrive API token não encontrado")
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
def __init__(self, config):
        self.config = config
        self.api_token = self.config.get_env_or_config('PIPEDRIVE_API_TOKEN', 'pipedrive', 'api_token')
        self.base_url = self.config.get('pipedrive', 'api_url', default='https://api.pipedrive.com/v1')
        
        if not self.api_token:
            raise Exception("Pipedrive API token não encontrado")
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Intent-Code Divergence

Medium
Confidence
96% confidence
Finding
The docstring says the method retrieves recent emails from monitored accounts, yet the implementation ends by returning a fixed example message regardless of account contents or the `since_time` argument. This is an active contradiction between documented intent and real behavior, not merely an incomplete implementation detail.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
This utility reads local Apple Mail via AppleScript, which is a powerful host-execution capability and exposes message subjects, senders, and content from the user's machine. In an automation skill, this is dangerous because it crosses from ordinary SaaS workflow integration into desktop data access without strong scoping or transparency.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
end tell
                '''
                
                result = subprocess.run(['osascript', '-e', script], 
                                      capture_output=True, text=True)
                
                if result.returncode == 0:
Confidence
91% confidence
Finding
The code invokes AppleScript through osascript to read Apple Mail content from the host system. Even though the subprocess arguments are passed as a list rather than through a shell, this still grants the skill host-level access to local mail data and expands the attack surface to sensitive desktop resources.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The script performs real external writes to Pipedrive and ClickUp and sends WhatsApp notifications as part of onboarding, but there is no explicit confirmation, dry-run default, or safeguard before side effects occur. In an agent skill context, this increases the risk of accidental client creation, CRM deal creation, project spam, or unintended notifications triggered from misunderstood prompts or bad inputs.