Back to skill

Security audit

Erxes

Security checks for vulnerabilities and agentic risk

Overview

The skill is a mostly coherent erxes management helper, but it handles live OAuth tokens and powerful business-data mutations with under-scoped transport, browser-launch, and deletion safeguards.

Review this before installing on a real erxes workspace. Use only trusted HTTPS erxes gateway URLs, avoid remote http:// endpoints, and treat the printed session JSON as a secret because it contains bearer/refresh tokens. Require explicit user confirmation before delete, merge, user invitation/deactivation, automation, or organization-structure changes, and avoid putting real passwords in prompts or request examples.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/login.sh:6
Finding

OAuth Tokens May Be Transmitted over Unencrypted HTTP

Content
View full analysis

Vulnerability Details

File Location: scripts/login.sh:6-16,35-38
Vulnerability Type: Acceptance of plaintext transport for sensitive OAuth traffic
Risk Level: High

Vulnerable Code

bash
BASE="${ERXES_BASE_URL%/}"
CLIENT="${ERXES_CLIENT_ID:-erxes-local}"

if [ -z "$BASE" ]; then
  echo "ERXES_BASE_URL is required" >&2
  exit 1
fi

# Extract subdomain from a gateway URL like https://demo.next.erxes.io/gateway -> demo
SUB=$(echo "$BASE" | sed -E 's|https?://([^./]+).*|\1|')

RESP=$(curl -sf -X POST "$BASE/oauth/device/code" \
  -H "Content-Type: application/json" \
  -H "erxes-subdomain: $SUB" \
  -d "{\"client_id\":\"$CLIENT\"}")
bash
TOK=$(curl -s -X POST "$BASE/oauth/token" \
  -H "Content-Type: application/json" \
  -H "erxes-subdomain: $SUB" \
  -d "{\"grant_type\":\"urn:ietf:params:oauth:grant-type:device_code\",\"device_code\":\"$DC\",\"client_id\":\"$CLIENT\"}")

The associated instructions explicitly permit arbitrary URL forms, and the login reference includes loopback HTTP:

text
Accept the URL in whatever form the user gives and normalize it to ERXES_BASE_URL=<url>.
bash
ERXES_BASE_URL=http://localhost:4000 ERXES_CLIENT_ID=my-client bash scripts/login.sh

Technical Analysis

The script does not validate the URL scheme before sending OAuth Device Flow requests. Because curl accepts http:// endpoints, a non-loopback server can receive both the device-code request and token polling requests over unencrypted transport.

The token response is expected to contain an access token and a refresh token. When a remote HTTP endpoint is used, an on-path attacker can observe or modify this authentication exchange. HTTPS certificate validation by curl does not mitigate the issue because no TLS connection exists in the HTTP case.

Loopback HTTP may be appropriate for local development, but the current implementation does not distinguish loopback addresses from arbitrary remote hosts.

Attack Path

...[truncated 1245 chars]

Remediation
View remediation

Remediation Suggestions

  1. Parse ERXES_BASE_URL with a proper URL parser before making any request.
  2. Require https:// for all non-loopback hosts.
  3. Permit http:// only when the normalized hostname is exactly an approved loopback address, such as localhost, 127.0.0.1, or [::1].
  4. Reject unsupported schemes, embedded credentials, malformed hosts, and ambiguous URL forms.
  5. Keep TLS certificate verification enabled and do not add curl -k or equivalent bypasses.
  6. Consider an explicit development-only flag before allowing loopback HTTP.
  7. Document the transport restriction consistently in SKILL.md and erxes-app-token-auth.md.
  8. Add tests confirming that remote HTTP URLs are rejected while valid HTTPS and explicitly approved loopback-development URLs are accepted.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/login.sh:20
Finding

Untrusted OAuth Response URI Is Automatically Dispatched to a Local Handler

Content
View full analysis

Vulnerability Details

File Location: scripts/login.sh:20-31
Vulnerability Type: Unsafe external URI handling
Risk Level: Medium

Vulnerable Code

bash
DC=$(echo "$RESP" | grep -o '"device_code":"[^"]*"' | cut -d'"' -f4)
URI=$(echo "$RESP" | grep -o '"verification_uri_complete":"[^"]*"' | cut -d'"' -f4 \
  | sed "s/<subdomain>/$SUB/g")

if [ -z "$DC" ] || [ -z "$URI" ]; then
  echo "Failed to start OAuth device flow" >&2
  echo "$RESP" >&2
  exit 1
fi

echo "Open this URL in your browser to approve access:" >&2
echo "$URI" >&2
open "$URI" 2>/dev/null || true

Technical Analysis

The verification_uri_complete value is supplied by the configured gateway and is passed directly to the macOS open command. Although the shell quotes the value and therefore limits ordinary shell metacharacter injection, open is a general resource dispatcher rather than an HTTPS-only browser launcher.

The script does not validate the URI scheme, destination origin, or relationship to the configured gateway. A malicious or compromised gateway can consequently return a custom URI scheme or another resource type. The operating system may dispatch that value to a registered local application or protocol handler.

The concrete result depends on the host operating system and installed handlers. This finding does not establish that every arbitrary URI yields code execution; it establishes an unsafe trust boundary that can expose vulnerable or privileged handlers.

Attack Path

  1. An attacker controls or compromises the gateway configured through ERXES_BASE_URL.
  2. The script requests /oauth/device/code.
  3. The gateway returns a valid-looking device_code and an attacker-selected verification_uri_complete.
  4. The script substitutes the subdomain placeholder, if present, and passes the resulting value to open.
  5. macOS dispatches the resource to the application registered for that URI scheme or resource type.
  6. If that handler performs sensitiv ...[truncated 634 chars]
Remediation
View remediation

Remediation Suggestions

  1. Parse verification_uri_complete as a URI before opening it.
  2. Allow only the https scheme in normal operation.
  3. Prefer requiring the verification URI to use the expected gateway origin or a documented allowlist of trusted authentication origins.
  4. Reject custom schemes, local file paths, file:// URIs, embedded credentials, and malformed or ambiguous URLs.
  5. If validation fails, display a clear error and do not invoke open.
  6. Consider printing the validated HTTPS URL and requiring deliberate user interaction rather than automatically launching it.
  7. If automatic launch remains necessary, invoke a browser-specific mechanism rather than a general-purpose resource dispatcher where practical.
  8. Add tests using hostile values such as custom schemes and local-file URIs to ensure they are rejected.
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
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (14)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The skill is described as GraphQL CRUD management, but it also performs browser-based OAuth login, token acquisition, and token refresh handling. This mismatch can mislead reviewers and users about the true security-sensitive behavior, causing credential-handling logic to receive less scrutiny than it should.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
91% confidence
Finding

The skill explicitly handles accessToken and refreshToken, instructing the agent to read bearer tokens from login output and use them for API calls. Even though it advises against writing tokens to disk, in-memory credential handling is still highly sensitive: any downstream logging, prompt leakage, shell output capture, or misuse of the refresh token could enable unauthorized access to the erxes instance.

Content

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

md
- Read `accessToken` from the login JSON response.
- Send `Authorization: Bearer <accessToken>` and `erxes-subdomain: <subdomain>` headers on GraphQL calls.
- If the access token expires during the current task, use the in-memory `refreshToken` to get a new access token.
- Do not write tokens to `.auth.json` or any other project file.
- Read [erxes-graphql-api.md](./erxes-graphql-api.md) only when you need query or mutation examples.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill invokes shell-based authentication (bash scripts/login.sh) but does not declare any tool scope or allowed-tools restrictions. That omission weakens least-privilege guarantees and can allow broader-than-expected command execution in environments that rely on explicit permission declarations for safety review.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill documentation switches into Mongolian for headings and capability descriptions, but nowhere indicates that this language choice is optional or user-selected. This can violate a language/locale policy when a skill effectively forces one language for core instructions without opt-in or justification.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
80% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

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

md
- `ERXES_CLIENT_ID` is optional. Default to `erxes-local`.
- Accept the URL in whatever form the user gives and normalize it to `ERXES_BASE_URL=<url>`.
- Do not explain OAuth internals unless the user asks.
- Do not ask the user to copy tokens manually.
- Do not store tokens in project files.
- The script opens the browser, waits for approval, and prints a session JSON payload to stdout.

Ae4

Medium
Category
analysis-evasion
Confidence
80% confidence
Finding

Suspicious Unicode normalization or mixed-script content

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

The title and description, and effectively the whole skill document, are presented in Mongolian with no indication that this locale is optional or required for a justified region-specific use case. Under the language/locale policy, forcing a specific language without user opt-in is a natural-language policy concern.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The documentation presents destructive mutations such as customer deletion as routine examples without requiring confirmation, warning about irreversibility, or suggesting safeguards. In an agent skill context, this increases the risk of unintended or prompt-induced destructive actions against production data.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The team member invitation example includes a plaintext password in the request body, normalizing direct credential handling inside the skill documentation. This can lead agents or users to generate, log, store, or transmit reusable credentials insecurely, especially in environments where prompts, traces, or request payloads are retained.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The invitation example embeds a temporary password directly in sample variables with no warning about secret sensitivity. This encourages insecure credential practices and raises the chance that secrets will appear in chat transcripts, code snippets, analytics, or application logs.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% 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/login.sh (reported line 17)May include surrounding context.

sh
# Extract subdomain from a gateway URL like https://demo.next.erxes.io/gateway -> demo
SUB=$(echo "$BASE" | sed -E 's|https?://([^./]+).*|\1|')

RESP=$(curl -sf -X POST "$BASE/oauth/device/code" \
  -H "Content-Type: application/json" \
  -H "erxes-subdomain: $SUB" \
  -d "{\"client_id\":\"$CLIENT\"}")

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% 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/login.sh (reported line 39)May include surrounding context.

sh
echo "Waiting for approval..." >&2
while true; do
  sleep 5
  TOK=$(curl -s -X POST "$BASE/oauth/token" \
    -H "Content-Type: application/json" \
    -H "erxes-subdomain: $SUB" \
    -d "{\"grant_type\":\"urn:ietf:params:oauth:grant-type:device_code\",\"device_code\":\"$DC\",\"client_id\":\"$CLIENT\"}")

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The script prints the full token response, including the OAuth access token, directly to stdout. In CLI and agent environments, stdout is commonly captured by logs, parent processes, shell history wrappers, or downstream tools, which can unintentionally disclose reusable credentials.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The quick reference states that products:manage includes productCategoriesAdd/Edit/Remove and uomsAdd/Edit/Remove, and organization:manage includes departmentsAdd/Edit/Remove and branchesAdd/Edit/Remove. In the body of the file, only the add mutations are actually shown, so the summary contradicts the concrete documented operations present here.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.