Back to skill

Security audit

CordysCRM

Security checks for vulnerabilities and agentic risk

Overview

This CRM skill is mostly coherent, but it exposes high-impact CRM credentials and write authority through unsafe, under-scoped runtime paths that users should review before installing.

Install only if you trust the publisher and deployment environment, can restrict CRM credentials to least privilege, and can disable or harden the raw API and .env loading paths. Avoid using administrator or executive CRM keys until raw requests, approval actions, plaintext identity persistence, and confirmation requirements are tightened.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/cordys.py:529
Finding

CRM Credentials Can Be Transmitted to an Arbitrary External Domain

Content
View full analysis
str: """Execute API request.""" check_keys() headers = { "X-Access-Key": CORDYS_ACCESS_KEY, "X-Secret-Key": CORDYS_SECRET_KEY, "X-Request-Source": "SKILL", "Content-Type": f"{content_type}; charset=utf-8" } ``` ```python def raw_api(method: str, path: str, *args) -> str: """Execute raw API request.""" if path.startswith("http"): if not validate_url(path): print("Request rejected: target domain does not match configured Cordys CRM domain", file=sys.stderr) print(f"Configured domain: {CORDYS_CRM_DOMAIN}", file=sys.stderr) print("To force sending, set CORDYS_ALLOW_UNTRUSTED=1", file=sys.stderr) if os.environ.get("CORDYS_ALLOW_UNTRUSTED", "0") != "1": sys.exit(1) else: warn("Untrusted-domain mode enabled; continuing request") url = path else: url = f"{CORDYS_CRM_DOMAIN}{path}" return api(method, url) ``` The equivalent shell behavior is: ```bash raw_api() { local method="$1" path="$2" shift 2 if [[ "$path" == http* ]]; then if ! validate_url "$path"; then echo "Request rejected: target domain does not match configured Cordys CRM domain" >&2 echo "Configured domain: $CORDYS_CRM_DOMAIN" >&2 if [[ "${CORDYS_ALLOW_UNTRUSTED:-0}" != "1" ]]; then exit 1 else warn "Untrusted-domain mode enabled; continuing request" fi fi api "$method" "$path" "$@" else api "$method" "${CORDYS_CRM_DOMAIN}${path}" "$@" fi } ``` ...[truncated 1974 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/cordys.py:529
Finding

Raw API Interface Bypasses Query-Only and No-Deletion Security Policies

Content
View full analysis
str: """Execute raw API request.""" if path.startswith("http"): if not validate_url(path): print("Request rejected: target domain does not match configured Cordys CRM domain", file=sys.stderr) print(f"Configured domain: {CORDYS_CRM_DOMAIN}", file=sys.stderr) print("To force sending, set CORDYS_ALLOW_UNTRUSTED=1", file=sys.stderr) if os.environ.get("CORDYS_ALLOW_UNTRUSTED", "0") != "1": sys.exit(1) else: warn("Untrusted-domain mode enabled; continuing request") url = path else: url = f"{CORDYS_CRM_DOMAIN}{path}" return api(method, url) ``` ```python def handle_raw_command(args: list) -> None: """Handle raw API command.""" if len(args) < 2: die("raw requires an HTTP method and path") method = args[0] path = args[1] print(raw_api(method, path)) ``` The shell dispatcher likewise accepts any method: ```bash raw) method="${1:-}"; shift || die "raw requires an HTTP method" path="${1:-}"; shift || die "raw requires a path" raw_api "$method" "$path" "$@" ;; ``` ### Technical Analysis The Skill documentation states that raw API access supports queries only and that deletion is absolutely prohibited. These restrictions are not enforced by either executable implementation. The caller directly controls the HTTP method and path. There is no allowlist of read-only methods, no endpoint policy, and no rejection of destructive or administrative routes. Therefore, the raw interface can bypass the module restrictions imposed on s ...[truncated 1504 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/cordys.sh:8
Finding

Shell Launcher Executes the Project .env File as Arbitrary Bash Code

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/cordys.sh:110
Finding

Arbitrary Raw Curl Options Can Bypass Request Validation and Manipulate Credential-Bearing Requests

Content
View full analysis
&2 echo "Configured domain: $CORDYS_CRM_DOMAIN" >&2 if [[ "${CORDYS_ALLOW_UNTRUSTED:-0}" != "1" ]]; then exit 1 else warn "Untrusted-domain mode enabled; continuing request" fi fi api "$method" "$path" "$@" else api "$method" "${CORDYS_CRM_DOMAIN}${path}" "$@" fi } ``` ### Technical Analysis The raw shell interface forwards every trailing user-supplied argument directly to curl after adding the CRM credentials. Quoting `"$@"` prevents shell word splitting but does not make the options safe: curl still interprets each argument as a command-line option. Depending on curl behavior and supplied arguments, an attacker may manipulate: - Additional URLs. - Proxy configuration. - Redirect behavior. - Request headers. - Request methods and bodies. - Local output paths. - Protocol selection. - Configuration-file loading. The URL validation checks only the initially supplied `path`. It does not parse or approve the subsequent curl options. Therefore, those options form a second request-control channel outside the validation boundary. ### Attack Path 1. An attacker causes the Agent to invoke the shell raw command with extra curl argument ...[truncated 1137 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
core/role-engine.md:145
Finding

CRM Identity Information Is Persisted in a Plaintext Workspace File

Content
View full analysis
Automatically obtained: 2026-05-09 10:30 > Matched role: sales-manager ## Identity Information | Field | Value | |------|-----| | User ID | admin | | Name | Example User | | Position | Sales Department Manager | | Email | user@example.com | | Role ID | sales-manager | ``` The lifecycle instructions retain the file and silently refresh it after seven days rather than limiting it to the active session. ### Technical Analysis The role engine directs the Agent to retrieve identity information from the CRM and write it into `user-role.md` in the Skill root. The stored fields include user ID, name, position, email address, and inferred role. Adding the file to `.gitignore` only reduces accidental source-control commits. It does not provide encryption, filesystem access control, tenant isolation, secure deletion, or protection against other local processes and later workspace consumers. Persisting the full identity response is unnecessary for role selection. A minimal, short-lived role identifier and opaque user reference would satisfy most of the declared functionality with less privacy exposure. ### Attack Path 1. The Skill starts without a valid `user-role.md`. 2. It invokes `crm verify` and `crm whoami`. 3. CRM-derived identity information is written to ...[truncated 845 chars]
Remediation
View remediation
Vulnerability Patterns
  • 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 Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (48)

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

python
headers=headers,
            method=method.upper()
        )
        with request.urlopen(req) as response:
            charset = response.headers.get_content_charset() or "utf-8"
            return response.read().decode(charset, errors="replace")
    except HTTPError as e:

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · .gitignore (reported line 2)May include surrounding context.

text
# 运行时生成的文件 - 不提交
.env
user-role.md
refs/
__pycache__/

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · core/cli-spec.md (reported line 308)May include surrounding context.

md
try:
    from dotenv import load_dotenv
except ImportError:
    # 如果没有 python-dotenv,提供简单的 .env 加载实现
    def load_dotenv(dotenv_path=None):
        if dotenv_path and os.path.exists(dotenv_path):
            with open(dotenv_path) as f:

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · core/role-engine.md (reported line 39)May include surrounding context.

md
try:
    from dotenv import load_dotenv
except ImportError:
    # 如果没有 python-dotenv,提供简单的 .env 加载实现
    def load_dotenv(dotenv_path=None):
        if dotenv_path and os.path.exists(dotenv_path):
            with open(dotenv_path) as f:

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · scripts/cordys.py (reported line 19)May include surrounding context.

python
try:
    from dotenv import load_dotenv
except ImportError:
    # 如果没有 python-dotenv,提供简单的 .env 加载实现
    def load_dotenv(dotenv_path=None):
        if dotenv_path and os.path.exists(dotenv_path):
            with open(dotenv_path) as f:

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · scripts/cordys.py (reported line 34)May include surrounding context.

python
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SKILL_DIR="$(dirname "$SCRIPT_DIR")"
ENV_FILE="${SKILL_DIR}/.env"

# ── 加载环境变量 ──────────────────────────────────────────────────────
if [[ -f "$ENV_FILE" ]]; then

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · scripts/cordys.sh (reported line 8)May include surrounding context.

sh
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SKILL_DIR="$(dirname "$SCRIPT_DIR")"
ENV_FILE="${SKILL_DIR}/.env"

# ── 加载环境变量 ──────────────────────────────────────────────────────
if [[ -f "$ENV_FILE" ]]; then

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill explicitly requires secrets, external network access, and relies on shell/CLI command construction, but it does not declare an explicit tool scope such as allowed-tools or permissions. That creates an overprivileged execution model where the agent may access broader shell, network, or environment capabilities than intended, increasing the blast radius of prompt injection, misrouting, or command construction mistakes.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The trigger words are very broad common business terms such as 客户, 合同, 订单, 审批, 漏斗, and CRM, which can cause the skill to activate in unrelated conversations. Because this skill has access to secrets, networked CRM APIs, and write workflows, unintended invocation can expose sensitive data or lead to accidental state-changing operations in a high-value business system.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

This section documents approval, create, update, batch-update, and transition endpoints in an operational CRM skill without prominent safety gating or explicit warnings about destructive or irreversible effects. In an agent context, such documentation materially enables the model to perform state-changing actions on production CRM records, increasing the risk of unintended approvals, data corruption, bulk edits, or workflow transitions from ambiguous user prompts.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
80% confidence
Finding

The file presents the CLI semantic specification entirely in Chinese and states that all AI-generated commands must follow this specification, which can amount to a forced language/locale constraint if applied universally. The policy allows locale constraints only when user choice is offered or the restriction is clearly documented and justified, which is not present here.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The skill documents approval, create, update, batch-update, and transformation commands that change CRM state, but it does not require confirmation prompts, explicit warnings, or other guardrails before destructive or high-impact actions. In an agent setting, this can lead to unintended record modification, workflow approvals, or business-process changes from ambiguous prompts or prompt injection, especially because the same spec also maps natural-language intents directly to write operations.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This markdown file presents all instructions, API descriptions, and command examples only in Chinese. Under the policy, forcing a specific language without user opt-in or documented regional justification is a natural-language policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

文档中的标题、说明和触发样例全部以中文固定表达,且路由规则依赖中文短语匹配,未说明是否支持其他语言或允许用户选择语言。这会形成默认强制语言/locale 行为,属于缺少用户选择的语言策略问题。

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The routing priorities use broad natural-language triggers such as vague work instructions and fuzzy search phrases without strong confirmation gates. In a CRM skill that can route into write workflows and cross-module data access, ambiguous phrasing can cause the agent to select an unintended execution path, leading to unauthorized data exposure or accidental modification if the downstream engine acts on the route.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The intent-mapping table defines many trigger phrases like '批一下', '待审批', '看看XX公司', and '搜一下XX' without scope restrictions or exclusion rules. In this CRM context, those triggers can invoke role-specific workflows, approvals, company-wide reporting, or linkage analysis from casual or ambiguous input, increasing the risk of over-broad data retrieval or unintended business actions.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The document defines the output layer entirely in Chinese and states that all AI-generated output must follow this specification. This effectively imposes a specific language/locale on all responses without any user opt-in or alternative language path, which matches the language/locale policy violation criteria.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The phrase "有什么要注意的" is a broad everyday expression and could unintentionally invoke a full risk scan outside a clearly defined sales context. The document does not state required context, explicit trigger boundaries, or exclusions for this phrase.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The activation examples "看看团队" and especially "有什么问题" are generic phrases that could appear in many ordinary conversations, making it unclear when this skill should trigger versus when the user is asking a broader question. The file does not provide narrowing constraints or negative examples to limit these phrases to a specific reporting context.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill instructs the system to persist personal identity data such as user ID, name, position, and email into a local markdown file without any explicit notice, consent flow, retention control, or storage protection guidance. This creates a privacy and data-handling risk because local artifacts may be exposed to other tools, users, backups, or version-control mistakes.

Content

No source excerpt is available for this finding.

Ssd 3

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

Inferring role and access posture from historical conversations requires inspecting prior user interactions beyond the immediate task context. This is dangerous because it expands processing of potentially sensitive conversational data, can misclassify users into broader views, and may cause privacy violations or unintended access decisions based on behavioral profiling.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The document title, module descriptions, examples, and expected prompts are all written in Chinese, and the interaction examples assume Chinese-language user input. There is no statement that users may choose another language or that the skill is intentionally limited to a Chinese-only compliance or regional context.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The role-matching keywords are broad enough to cause accidental activation of the contract-admin profile during ordinary CRM conversations involving terms like 商务, 法务, or 合同管理. In this skill, misrouting is security-relevant because the activated profile changes recommended commands, data scope, and workflow behavior, which can expose contract and approval data to users or contexts that did not intend to access this role.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The entire skill description, triggers, workflows, and output template are written exclusively in Chinese, with no indication that users may choose another language or locale. Under the policy, a skill that effectively requires a specific language without opt-in can be a natural-language policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
81% confidence
Finding

All headings, examples, trigger phrases, and operational instructions are presented exclusively in Chinese, and the file does not indicate that language selection is optional or region-specific. This can violate language or locale policy where users should be allowed to choose their preferred language unless a justified locale constraint is documented.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.