Back to skill

Security audit

Cloudflare Manager

Security checks for vulnerabilities and agentic risk

Overview

This Cloudflare skill mostly does what it says, but it also exposes broad, under-documented Cloudflare setting changes and privileged host configuration writes that merit careful review before installation.

Install only if you are comfortable giving this skill Cloudflare zone mutation rights and sudo-backed control over cloudflared on the host. Use a narrowly scoped Cloudflare token, prefer dry-run first, review commands before execution, and avoid granting sudo until the missing sudoers guidance, config validation, backups, rollback, and update-setting scoping are addressed.

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

T08 · Insecure Dependencies

Warning
Location
requirements.txt:1
Finding

Unpinned Third-Party Dependencies Create Supply-Chain Risk

Content
View full analysis

Vulnerability Details

File Location: requirements.txt:1-2; scripts/install.sh:12-13
Vulnerability Type: Unpinned executable dependencies
Risk Level: Medium

Vulnerable Code

requirements.txt:1-2:

text
requests
PyYAML

scripts/install.sh:12-13:

bash
"$VENV_DIR/bin/pip" install -U pip
"$VENV_DIR/bin/pip" install -r "$SKILL_ROOT/requirements.txt"

Technical Analysis

The installation process retrieves the latest available versions of pip, requests, PyYAML, and their transitive dependencies from the configured Python package index. Neither exact versions nor package hashes are specified.

Consequently, the code installed by this Skill can change after the Skill itself has been reviewed. An unconditional pip upgrade further expands the mutable supply-chain surface. If a package-index account, upstream release, configured mirror, or dependency is compromised, a future installation could receive malicious or otherwise unsafe code.

Python packages may execute code during package installation and are subsequently imported by scripts/cf_manager.py. Therefore, a compromised dependency could execute with the privileges of the user running the setup or manager script.

Attack Path

  1. An attacker compromises an upstream dependency release, package-index account, or package mirror used by pip.
  2. The attacker publishes a malicious version that still satisfies the unrestricted dependency declarations.
  3. A user or agent invokes bash scripts/install.sh as documented by the Skill.
  4. Pip resolves and downloads the attacker-controlled release because no reviewed version or hash is enforced.
  5. Malicious code executes during installation or when requests or yaml is imported at runtime.
  6. The payload operates with the installing or invoking user's permissions and may access that user's files and environment variables.

Impact Assessment

Successful exploitat ...[truncated 488 chars]

Remediation
View remediation

Remediation Suggestions

  1. Pin all direct and transitive dependencies to reviewed versions in a lock file.
  2. Generate and enforce cryptographic hashes for every downloaded distribution, for example:
    bash
    "$VENV_DIR/bin/pip" install --require-hashes -r "$SKILL_ROOT/requirements.lock"
    
  3. Remove the unconditional pip install -U pip operation or pin pip to a reviewed version with an enforced hash.
  4. Generate the lock file using a controlled dependency-resolution process and commit it to the project.
  5. Prefer an explicitly trusted package index and prevent fallback to untrusted extra indexes.
  6. Periodically scan pinned packages for known vulnerabilities and update them through a reviewed change process.
  7. Run installation and runtime operations as an unprivileged, dedicated account without unnecessary access to Cloudflare credentials.

T09 · Insecure Skill Coding Practices

Note
Location
scripts/cf_manager.py:144
Finding

Privileged Cloudflared Configuration Write Is Not Validated

Content
View full analysis

Vulnerability Details

File Location: scripts/cf_manager.py:144-149
Vulnerability Type: Unchecked privileged file write and non-atomic configuration replacement
Risk Level: Low

Vulnerable Code

python
# Write back using sudo tee via subprocess
process = subprocess.Popen(['sudo', 'tee', CONFIG_PATH], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
process.communicate(input=yaml_str.encode())

# Restart cloudflared
subprocess.run(['sudo', 'systemctl', 'restart', 'cloudflared'], check=True)

Technical Analysis

The program writes directly to /etc/cloudflared/config.yml through a privileged sudo tee process but does not inspect its return code. process.communicate() waits for completion but does not raise an exception when tee exits unsuccessfully.

As a result, the application may proceed to restart cloudflared after a failed write. The target is also overwritten directly rather than through a protected temporary file and atomic rename. An interruption, storage failure, or partial write can therefore leave the active configuration truncated or malformed.

No cloudflared configuration validation is performed before the service restart. Although yaml.safe_load and structured YAML serialization prevent direct shell-command injection in this path, they do not ensure that the resulting configuration is semantically valid for cloudflared.

Attack Path

  1. An authorized user invokes update-ingress with a hostname and service value.
  2. The manager serializes the modified configuration.
  3. The privileged tee operation fails, is interrupted, or only partially writes the active configuration due to a permission, storage, or operating-system error.
  4. The process exit status is ignored.
  5. The manager invokes sudo systemctl restart cloudflared.
  6. Cloudflared restarts with stale, incomplete, or invalid configuration and may fail to start or expose routes differently from the req ...[truncated 528 chars]
Remediation
View remediation

Remediation Suggestions

  1. Check the privileged writer's exit status, preferably using:
    python
    subprocess.run(
        ["sudo", "tee", CONFIG_PATH],
        input=yaml_str,
        text=True,
        stdout=subprocess.DEVNULL,
        check=True,
    )
    
  2. Do not overwrite the live configuration directly. Write to a root-controlled temporary file in the same filesystem, set restrictive ownership and permissions, and atomically replace the destination only after validation succeeds.
  3. Validate the candidate configuration before replacement and restart, for example with the appropriate cloudflared tunnel ingress validate command.
  4. Preserve a known-good backup and restore it automatically if validation or service restart fails.
  5. Verify that cloudflared becomes healthy after restart rather than treating successful execution of systemctl restart as sufficient.
  6. Restrict sudo authorization to narrowly defined helper operations. The documentation references references/sudoers.example, but that file is absent from the reviewed project and should be supplied with a least-privilege policy.
  7. Log failures without exposing credentials or other sensitive configuration values.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (31)

Tainted flow: 'url' from os.getenv (line 84, credential/environment) → requests.get (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/cf_manager.py (reported line 33)May include surrounding context.

python
url = f"https://api.cloudflare.com/client/v4/zones/{CLOUDFLARE_ZONE_ID}/dns_records"
        params = {"per_page": 100}
        response = requests.get(url, headers=self.headers, params=params)
        return response.json()

    def add_dns(self, record_type, name, content, proxied=True, comment=""):

Tainted flow: 'url' from os.getenv (line 84, credential/environment) → requests.post (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/cf_manager.py (reported line 50)May include surrounding context.

python
if self.dry_run:
            return {"status": "dry-run", "action": "add_dns", "data": data}
            
        response = requests.post(url, headers=self.headers, json=data)
        return response.json()

    def update_dns(self, record_id, record_type, name, content, proxied=True, comment=""):

Tainted flow: 'url' from os.getenv (line 84, credential/environment) → requests.put (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/cf_manager.py (reported line 67)May include surrounding context.

python
if self.dry_run:
            return {"status": "dry-run", "action": "update_dns", "data": data}

        response = requests.put(url, headers=self.headers, json=data)
        return response.json()

    def delete_dns(self, record_id):

Tainted flow: 'url' from os.getenv (line 84, credential/environment) → requests.patch (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Unlike the DNS-specific operations, update_setting permits modification of arbitrary Cloudflare zone settings via a free-form setting_id and user-supplied value. This broadens the skill's authority beyond the advertised scope and can disable protections or weaken zone security if misused.

Content

Scanner excerpt · scripts/cf_manager.py (reported line 90)May include surrounding context.

python
if self.dry_run:
            return {"status": "dry-run", "action": "update_setting", "data": data}

        response = requests.patch(url, headers=self.headers, json=data)
        return response.json()

    def update_ingress(self, hostname, service):

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

The documented behavior does not accurately match the described purpose: the skill claims Zero Trust and tunnel management, but appears to only edit local ingress config and also perform undeclared zone-setting changes. This mismatch is dangerous because operators and higher-level agents may authorize use based on incomplete or incorrect expectations, enabling broader Cloudflare or local-system changes than intended.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
96% confidence
Finding

The code overwrites /etc/cloudflared/config.yml and restarts cloudflared immediately, without explicit warning, diff review, rollback, or confirmation. In context, this can instantly expose internal services, break existing ingress routing, or cause downtime on the host.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill exposes meaningful capabilities through installation commands, shell invocation, environment-secret use, file reads, network access, and privileged local changes, but it does not declare an explicit tool/permission scope. That weakens policy enforcement and reviewability, making it easier for an agent to invoke sensitive operations without clear guardrails or operator awareness.

Content

No source excerpt is available for this finding.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

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

md
- **Safety**: Use `--dry-run` to preview configuration changes before application.

## Security & Permissions
- **Sudo Usage**: The `update-ingress` command requires `sudo` to write to system directories and restart the `cloudflared` service.
- **Least Privilege**: Configure restricted sudo access using the pattern in `references/sudoers.example`.
- **Token Isolation**: Ensure API tokens are scoped narrowly to specific zones and permissions.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

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

md
## Security & Permissions
- **Sudo Usage**: The `update-ingress` command requires `sudo` to write to system directories and restart the `cloudflared` service.
- **Least Privilege**: Configure restricted sudo access using the pattern in `references/sudoers.example`.
- **Token Isolation**: Ensure API tokens are scoped narrowly to specific zones and permissions.

## Reference

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · scripts/cf_manager.py (reported line 105)May include surrounding context.

python
## Security & Permissions
- **Sudo Usage**: The `update-ingress` command requires `sudo` to write to system directories and restart the `cloudflared` service.
- **Least Privilege**: Configure restricted sudo access using the pattern in `references/sudoers.example`.
- **Token Isolation**: Ensure API tokens are scoped narrowly to specific zones and permissions.

## Reference

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/cf_manager.py (reported line 31)May include surrounding context.

python
def list_dns(self):
        if err := self._check_creds(): return err
        
        url = f"https://api.cloudflare.com/client/v4/zones/{CLOUDFLARE_ZONE_ID}/dns_records"
        params = {"per_page": 100}
        response = requests.get(url, headers=self.headers, params=params)
        return response.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/cf_manager.py (reported line 39)May include surrounding context.

python
def list_dns(self):
        if err := self._check_creds(): return err
        
        url = f"https://api.cloudflare.com/client/v4/zones/{CLOUDFLARE_ZONE_ID}/dns_records"
        params = {"per_page": 100}
        response = requests.get(url, headers=self.headers, params=params)
        return response.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/cf_manager.py (reported line 56)May include surrounding context.

python
def list_dns(self):
        if err := self._check_creds(): return err
        
        url = f"https://api.cloudflare.com/client/v4/zones/{CLOUDFLARE_ZONE_ID}/dns_records"
        params = {"per_page": 100}
        response = requests.get(url, headers=self.headers, params=params)
        return response.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/cf_manager.py (reported line 73)May include surrounding context.

python
def list_dns(self):
        if err := self._check_creds(): return err
        
        url = f"https://api.cloudflare.com/client/v4/zones/{CLOUDFLARE_ZONE_ID}/dns_records"
        params = {"per_page": 100}
        response = requests.get(url, headers=self.headers, params=params)
        return response.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/cf_manager.py (reported line 84)May include surrounding context.

python
def list_dns(self):
        if err := self._check_creds(): return err
        
        url = f"https://api.cloudflare.com/client/v4/zones/{CLOUDFLARE_ZONE_ID}/dns_records"
        params = {"per_page": 100}
        response = requests.get(url, headers=self.headers, params=params)
        return response.json()

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% 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/cf_manager.py (reported line 50)May include surrounding context.

python
if self.dry_run:
            return {"status": "dry-run", "action": "add_dns", "data": data}
            
        response = requests.post(url, headers=self.headers, json=data)
        return response.json()

    def update_dns(self, record_id, record_type, name, content, proxied=True, comment=""):

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% 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/cf_manager.py (reported line 67)May include surrounding context.

python
if self.dry_run:
            return {"status": "dry-run", "action": "update_dns", "data": data}

        response = requests.put(url, headers=self.headers, json=data)
        return response.json()

    def delete_dns(self, record_id):

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

DNS deletion is destructive and is executed immediately without any confirmation, preview, or safety interlock. In an agent setting, mistaken parameters or prompt manipulation could remove production DNS records and cause outages or traffic hijacking opportunities.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill claims to manage DNS, tunnels, and Zero Trust policies, but update_setting can alter arbitrary zone settings, including security-relevant controls outside that scope. Scope mismatch is dangerous because users may grant trust or credentials assuming narrower capabilities than the code actually has.

Content

No source excerpt is available for this finding.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
90% confidence
Finding

The function explicitly requires sudo/root-level access to modify host tunnel configuration, which materially increases the blast radius of the skill. In an agent context, any prompt-driven misuse can now impact the local system rather than just remote Cloudflare resources.

Content

Scanner excerpt · scripts/cf_manager.py (reported line 96)May include surrounding context.

python
def update_ingress(self, hostname, service):
        """
        Updates cloudflared config.
        REQUIRES: Sudo access on the host.
        Use --dry-run to preview changes without writing.
        """
        try:

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
50% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · scripts/cf_manager.py (reported line 105)May include surrounding context.

python
return {"error": f"Config file not found at {CONFIG_PATH}"}

            # Read current config (requires read access, usually root/cloudflared user)
            # In a typical setup, 'cat' might need sudo if permissions are tight
            try:
                with open(CONFIG_PATH, 'r') as f:
                    config = yaml.safe_load(f)

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The skill performs host-level privileged file writes and service restarts through sudo, which exceeds what many users would expect from a Cloudflare-management capability. This significantly raises risk because compromise or misuse of the skill can affect the local host, not just Cloudflare resources.

Content

No source excerpt is available for this finding.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
86% confidence
Finding

Executing sudo cat to read a protected system config demonstrates that the skill operates with elevated privileges on the host. While not command injection, it normalizes privileged execution in a broadly callable code path and expands the consequences of misuse.

Content

Scanner excerpt · scripts/cf_manager.py (reported line 110)May include surrounding context.

python
with open(CONFIG_PATH, 'r') as f:
                    config = yaml.safe_load(f)
            except PermissionError:
                # Try reading via sudo cat
                cmd = ["sudo", "cat", CONFIG_PATH]
                result = subprocess.run(cmd, capture_output=True, text=True, check=True)
                config = yaml.safe_load(result.stdout)

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/cf_manager.py (reported line 112)May include surrounding context.

python
except PermissionError:
                # Try reading via sudo cat
                cmd = ["sudo", "cat", CONFIG_PATH]
                result = subprocess.run(cmd, capture_output=True, text=True, check=True)
                config = yaml.safe_load(result.stdout)

            if 'ingress' not in config:

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
95% confidence
Finding

Using sudo tee to overwrite /etc/cloudflared/config.yml is a privileged write primitive affecting host networking and service exposure. Because the written content is derived from user-controlled inputs, this can be abused to publish or reroute internal services through Cloudflare Tunnel.

Content

Scanner excerpt · scripts/cf_manager.py (reported line 143)May include surrounding context.

python
"new_content_preview": yaml_str
                }

            # Write back using sudo tee via subprocess
            process = subprocess.Popen(['sudo', 'tee', CONFIG_PATH], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
            process.communicate(input=yaml_str.encode())

Static analysis

No suspicious patterns detected.