Back to skill

Security audit

Preny Analytics

Security checks for vulnerabilities and agentic risk

Overview

This appears to be a Preny analytics integration, but it also asks users to handle live tokens unsafely and includes under-disclosed customer conversation and reply capabilities.

Review carefully before installing. Prefer a read-only, scoped Preny API credential rather than a copied browser session token, do not store tokens in ~/.bashrc, verify requests only go to trusted Preny API hosts, and avoid using the conversation or reply scripts unless you explicitly need and authorize customer-support operations.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/preny-handler.js:6
Finding
Bearer Credentials Can Be Redirected to an Arbitrary Network Endpoint<![CDATA[ ## Vulnerability Details **File Location**: `scripts/preny-handler.js:6-7, 98-138`; `scripts/preny-cli.sh:7-9, 27-40`; `scripts/preny-stats.sh:7-8, 56-65`; `scripts/preny-tags.sh:7-8, 42-49`; `scripts/preny-conversations.sh:10-12, 28-33, 48-53, 90-97` **Vulnerability Type**: Unvalidated API endpoint override with credential forwarding **Risk Level**: High ### Vulnerable Code ```javascript const PRENY_API_BASE = process.env.PRENY_API_URL || 'https://api-production.prenychatbot.ai/api/v1'; const PRENY_TOKEN = process.env.PRENY_TOKEN; async function callAPI(from, to, limit = 30) { const url = `${PRENY_API_BASE}/statistics/stats?from=${from}&to=${to}&skip=0&limit=${limit}&sort=-1&type=interact`; const response = await fetch(url, { method: 'GET', headers: { 'Accept': 'application/json', 'Authorization': `Bearer ${PRENY_TOKEN}`, 'Content-Type': 'application/json' } }); return response.json(); } ``` The equivalent shell implementation is: ```bash API_URL="${PRENY_API_URL:-https://api.preny.ai/v1}" API_KEY="${PRENY_API_KEY}" WORKSPACE_ID="${PRENY_WORKSPACE_ID}" api_call() { local method="$1" local endpoint="$2" local data="$3" local url="${API_URL}${endpoint}" local args=(-s -X "$method" -H "Authorization: Bearer ${API_KEY}" -H "X-Workspace-ID: ${WORKSPACE_ID}" -H "Content-Type: application/json") if [ -n "$data" ]; then args+=(-d "$data") fi curl "${args[@]}" "$url" } ``` ### Technical Analysis The scripts accept `PRENY_API_URL` directly from the process environment and attach a sensitive bearer credential to requests sent to the resulting URL. No validation restricts the URL scheme, hostname, port, or destination. Sending a bearer token to the official Preny API is necessary for the declared analytics functionality. Allowing the destination to be changed to an arbitrary origin while forwarding the same token is not required for normal operation and violates least-pri ...[truncated 1808 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `PRENY_API_URL` overrides unless custom endpoints are an explicit operational requirement. 2. If overrides are required, parse and validate the URL before creating any credential-bearing request: - Require `https:`. - Enforce an exact allowlist of documented Preny API hostnames. - Reject embedded credentials, unexpected ports, IP literals, and subdomain-suffix bypasses. 3. Compare the final request origin against the allowlist immediately before adding the `Authorization` header. 4. Disable redirects or ensure authorization headers are never forwarded to a different origin. 5. Add safe transport options to shell calls, such as `--fail-with-body`, `--proto '=https'`, and an explicit redirect policy. 6. Use narrowly scoped, read-only analytics tokens rather than browser session tokens or credentials that can access conversations. 7. Document every external hostname contacted by the Skill and fail closed when the destination is not recognized. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/preny-conversations.sh:28
Finding
Undeclared Conversation and Customer-PII Operations Exceed the Skill's Analytics Scope<![CDATA[ ## Vulnerability Details **File Location**: `scripts/preny-conversations.sh:28-102`; `scripts/preny-cli.sh:128-158` **Vulnerability Type**: Excessive privilege and functionality beyond the declared analytics purpose **Risk Level**: High ### Vulnerable Code ```bash response=$(curl -s -X GET \ "${API_URL}/conversations/${CONV_ID}" \ -H "Authorization: Bearer ${API_KEY}" \ -H "X-Workspace-ID: ${WORKSPACE_ID}" \ -H "Content-Type: application/json") echo "┌─────────────────────────────────────────┐" echo "│ 👤 Khách hàng: $(echo "$response" | jq -r '.data.customer.name')" echo "│ 📞 SĐT: $(echo "$response" | jq -r '.data.customer.phone')" echo "│ 📧 Email: $(echo "$response" | jq -r '.data.customer.email')" echo "│ 📱 Kênh: $(echo "$response" | jq -r '.data.channel')" echo "│ 🏷️ Trạng thái: $(echo "$response" | jq -r '.data.status')" echo "└─────────────────────────────────────────┘" echo "" echo "💬 TIN NHẮN:" echo "───────────────────────────────────────────" echo "$response" | jq -r '.data.messages[] | "[\(.timestamp)] \(.sender): \(.content)"' ``` The same script can perform an outbound write operation: ```bash response=$(curl -s -X POST \ "${API_URL}/conversations/${CONV_ID}/messages" \ -H "Authorization: Bearer ${API_KEY}" \ -H "X-Workspace-ID: ${WORKSPACE_ID}" \ -H "Content-Type: application/json" \ -d "{\"type\":\"text\",\"content\":\"${MESSAGE}\",\"sender\":\"agent\"}") ``` ### Technical Analysis The declared Skill purpose is analytics and aggregate reporting of metrics such as customer counts, messages, conversions, and tags. The package nevertheless includes operations that: - Enumerate conversations - Retrieve an individual customer's name, phone number, and email address - Print complete message histories - Send a message while identifying the sender as an agent These operations require access to substantially more sensitive information and authority than aggregate analytics. The ...[truncated 1668 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove conversation retrieval and reply functions from this analytics Skill. 2. If conversation management is required, publish it as a separate, explicitly documented, opt-in Skill. 3. Use separate credentials: - Read-only aggregate-statistics credentials for analytics - Independently authorized conversation-read credentials - Separately controlled message-send credentials 4. Ensure the analytics token cannot retrieve raw customer records or send messages. 5. Redact phone numbers, email addresses, and message content by default. 6. Require explicit user authorization for each PII retrieval, not only for message sending. 7. Add audit logging for conversation access and outbound messages without logging bearer credentials or complete message bodies. 8. Update the manifest and documentation to enumerate all capabilities and required environment variables if these functions are retained. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/preny-conversations.sh:68
Finding
Unescaped Message Content Is Interpolated Directly into a JSON Request Body<![CDATA[ ## Vulnerability Details **File Location**: `scripts/preny-conversations.sh:68-94` **Vulnerability Type**: Improper JSON construction using untrusted input **Risk Level**: Medium ### Vulnerable Code ```bash reply) CONV_ID="$1" MESSAGE="$2" if [ -z "$CONV_ID" ] || [ -z "$MESSAGE" ]; then echo "Error: Missing conversation ID or message" echo "Usage: ./preny-conversations.sh reply <conv_id> <message>" exit 1 fi echo "⚠️ Bạn có muốn gửi tin nhắn sau không?" echo "" echo "Hội thoại: $CONV_ID" echo "Nội dung: $MESSAGE" echo "" read -p "Xác nhận gửi? (y/N): " confirm if [ "$confirm" != "y" ] && [ "$confirm" != "Y" ]; then echo "❌ Đã hủy gửi tin nhắn" exit 0 fi response=$(curl -s -X POST \ "${API_URL}/conversations/${CONV_ID}/messages" \ -H "Authorization: Bearer ${API_KEY}" \ -H "X-Workspace-ID: ${WORKSPACE_ID}" \ -H "Content-Type: application/json" \ -d "{\"type\":\"text\",\"content\":\"${MESSAGE}\",\"sender\":\"agent\"}") ``` ### Technical Analysis `MESSAGE` is inserted into a JSON string without JSON encoding. Message content containing quotation marks, backslashes, control characters, or JSON fragments can terminate or corrupt the intended `content` value. Shell command injection is not established here because the variable expansion remains inside a quoted shell argument. The confirmed weakness is request-body injection and malformed JSON generation. Whether injected duplicate or additional fields alter server behavior depends on the API's JSON parser and schema validation. The interactive confirmation does not sanitize the payload. It also may be ineffective in automated execution contexts where input can be pre-supplied. ### Attack Path 1. An untrusted message value containing JSON metacharacters reaches the `reply` command. 2. The caller confirms the displayed message, or an automated environment supplies co ...[truncated 834 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Construct the request body with a JSON-aware serializer rather than string interpolation: ```bash payload=$(jq -n --arg message "$MESSAGE" \ '{type: "text", content: $message, sender: "agent"}') response=$(curl -s -X POST \ "${API_URL}/conversations/${CONV_ID}/messages" \ -H "Authorization: Bearer ${API_KEY}" \ -H "X-Workspace-ID: ${WORKSPACE_ID}" \ -H "Content-Type: application/json" \ --data-binary "$payload") ``` Additionally: 1. Validate `CONV_ID` against the documented identifier format before using it in a URL path. 2. Apply server-compatible message length and character restrictions. 3. Treat API errors and non-2xx status codes as failures. 4. Add tests for quotes, backslashes, line breaks, Unicode, and control characters. 5. Preserve explicit confirmation for outbound messaging, but do not treat confirmation as input validation. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
docs/how-to-get-token.md:29
Finding
Documentation Recommends Persistent Plaintext Storage of the Preny Bearer Token<![CDATA[ ## Vulnerability Details **File Location**: `docs/how-to-get-token.md:29-33` **Vulnerability Type**: Persistent plaintext credential storage **Risk Level**: Medium ### Vulnerable Code ```bash # Add to environment export PRENY_TOKEN="your-token-here" # Or add to bashrc for long-term use echo 'export PRENY_TOKEN="your-token-here"' >> ~/.bashrc source ~/.bashrc ``` ### Technical Analysis The documentation recommends writing the Preny bearer token directly into `~/.bashrc`. This is a persistent plaintext file that is commonly copied into backups, included in diagnostic archives, synchronized between systems, or exposed through overly permissive file permissions. A shell startup file is also loaded by many interactive shell sessions, which unnecessarily broadens the number of processes and contexts in which the credential is available. The Skill requires the token only when making Preny requests, so global and persistent exposure exceeds the minimum necessary lifetime and scope. The documentation correctly warns users not to share or commit the token, but that warning does not mitigate the insecure storage recommendation. ### Attack Path 1. A user follows the documentation and writes a valid token into `~/.bashrc`. 2. The file persists after the Skill finishes and may be loaded into future shell environments. 3. Another local user, compromised process, backup reader, support tool, or configuration-sync service obtains the file. 4. The attacker extracts `PRENY_TOKEN`. 5. The attacker reuses the token against Preny until it expires or is revoked. ### Impact Assessment Credential disclosure can expose business analytics and any additional Preny capabilities authorized to the token. Because the documentation describes the token as having access to business data, compromise may affect sensitive customer and operational information. The impact depends on local file permissions, token lifetime, server-side token scope, and whether the user rotates the ...[truncated 33 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the recommendation to store the token directly in `~/.bashrc`. 2. Prefer an operating-system credential manager, dedicated secrets manager, or runtime secret injection mechanism. 3. If file-based storage is unavoidable: - Use a dedicated credential file outside the repository. - Set permissions to `0600`. - Load it only for the process that needs the token. - Exclude it from backups and synchronization where practical. 4. Recommend short-lived, narrowly scoped, read-only API tokens instead of copied browser session tokens. 5. Document revocation and rotation procedures. 6. Warn users that environment variables may be visible to child processes and, on some systems, process-inspection interfaces. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (35)

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
Advertising real-time automated sales analysis when the implementation is only manual CLI queries to specific statistics endpoints is a material transparency failure. This can mislead operators into overtrusting the scope, freshness, and automation level of the data flow, obscuring what data is actually being accessed and when.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
Advertising real-time automated sales analysis when the implementation is only manual CLI queries to specific statistics endpoints is a material transparency failure. This can mislead operators into overtrusting the scope, freshness, and automation level of the data flow, obscuring what data is actually being accessed and when.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
Advertising real-time automated sales analysis when the implementation is only manual CLI queries to specific statistics endpoints is a material transparency failure. This can mislead operators into overtrusting the scope, freshness, and automation level of the data flow, obscuring what data is actually being accessed and when.

YARA rule 'backdoor_persistence': Backdoor persistence with malicious payloads (shell commands, SSH key injection, hidden root users) [malware]

High
Category
YARA Match
Content
h sách requests, tìm request có tên `stats` hoặc `statistics`
2. Click vào request đó
3. Chuyển sang tab **Headers**
4. Tìm mục **Request Headers**
5. Tìm dòng `Authorization: Bearer <token>`
6. Copy phần token (chuỗi sau "Bearer ")

### Bước 5: Lưu Token
```bash
# Thêm vào environment
export PRENY_TOKEN="your-token-here"

# Hoặc thêm vào bashrc để dùng lâu dài
echo 'export PRENY_TOKEN="your-token-here"' >> ~/.bashrc
source ~/.bashrc
```

## Cách 2: Từ Console (Cách nhanh)

1. Mở DevTools (`F12`)
2. Chuyển sang tab **Console**
3. Paste đoạn code sau:

```javascript
// Lấy token từ localStorage
const token = localStorage.getItem('token') || 
              JSON.parse(localStorage.getItem('user') || '{}').token;
console.log('Your Preny Token:', token);
```

4. Copy token được in ra

## Token hết hạn怎么办?

Token Preny có thời hạn (thường 7 ngày). Khi hết hạn:

1. Đăng nhập lại https://app.preny.ai
2. Lấy t
Confidence
75% confidence
Finding
YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).

Description-Behavior Mismatch

High
Confidence
97% confidence
Finding
The script retrieves full conversation details including customer name, phone, email, and message contents, which goes beyond the stated analytics/sales-data purpose of the skill. In this context, the mismatch is dangerous because it expands access to customer PII and live support interactions without clear necessity, increasing privacy, misuse, and unauthorized data-handling risk.

Context-Inappropriate Capability

High
Confidence
98% confidence
Finding
The script can send outbound messages to customers through the reply action, which is not justified by an analytics-focused skill description. Even with a local confirmation prompt, this creates a high-risk capability for unauthorized customer contact, social engineering, spam, or harmful business actions if invoked by an agent or automation in the wrong context.

Context-Inappropriate Capability

High
Confidence
98% confidence
Finding
The script explicitly instructs users to retrieve a live Authorization bearer token from browser DevTools and place it into an environment variable. That normalizes unsafe credential extraction and reuse of a session/API token outside its intended context, increasing the risk of account compromise, token leakage in shell history or process environments, and unauthorized API access.

Vague Triggers

Medium
Confidence
84% confidence
Finding
The README states that users can "just ask in natural language" without defining a strict trigger scope, which makes invocation ambiguous. In a skill that grants access to real-time sales analytics and customer-related data, ambiguous triggering increases the chance of unintended execution, data exposure, or abuse through prompt overlap with normal chat.

Vague Triggers

Medium
Confidence
89% confidence
Finding
The example trigger phrase "Thống kê hôm nay" is broad, generic language that could easily appear in ordinary conversation and unintentionally invoke the skill. Because this skill exposes business analytics through natural-language queries backed by a bearer token, accidental or opportunistic invocation could disclose sensitive sales and customer metrics to users who did not explicitly intend to run the skill.

Lp3

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding
The skill declares access to environment variables and implies network/shell-capable operation via required binaries and token use, but does not declare an explicit tool scope such as allowed-tools or permissions. This weakens least-privilege controls and makes it harder for reviewers and runtime policy to constrain what the skill can do, especially when handling customer analytics and conversation data.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The skill promotes direct connection to a third-party chatbot and real-time analysis of sales-related data but provides no warning about privacy, data transmission, or customer-information handling. In this context, the likely data includes customer conversations, phone numbers, and behavioral status, so omission of privacy disclosure increases the risk of uninformed use and regulatory or policy violations.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The manifest description and the visible documentation content are entirely in Vietnamese, with no indication that language selection is optional or that the skill is intentionally restricted to a Vietnamese-only audience. This constitutes a natural-language policy concern because it forces a locale/language without documented opt-in or justification.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The manifest explicitly advertises analysis of phone numbers, customer tags, interaction status, and new/returning customer behavior, which are privacy-sensitive data categories. There is no visible notice about consent, minimization, retention, access controls, or safe handling, so users may expose regulated personal data to the skill without understanding the privacy implications.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The document instructs users to extract a live bearer token from browser traffic and persist it in shell environment configuration, which increases the chance of credential leakage through shell history, shared accounts, backups, or local compromise. While meant for convenience, these steps normalize unsafe handling of a sensitive authentication secret that grants access to business data.

External Transmission

Medium
Category
Data Exfiltration
Content
set -e

API_URL="${PRENY_API_URL:-https://api.preny.ai/v1}"
API_KEY="${PRENY_API_KEY}"
WORKSPACE_ID="${PRENY_WORKSPACE_ID}"
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
set -e

API_URL="${PRENY_API_URL:-https://api.preny.ai/v1}"
API_KEY="${PRENY_API_KEY}"
WORKSPACE_ID="${PRENY_WORKSPACE_ID}"
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
This shell script performs HTTP requests with authentication headers and retrieves analytics and conversation data, but the code provides no user-facing notice before these network operations occur. Although missing credentials are reported, there is no warning that running commands will contact a remote service and transmit workspace-identifying information.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
User-facing strings throughout the script, including command descriptions and output, are in Vietnamese only. This imposes a specific language on users without opt-in or justification, which matches the language/locale policy violation criteria.

Description-Behavior Mismatch

Medium
Confidence
94% confidence
Finding
The skill is described as a real-time sales analytics tool, but it also exposes operational customer conversation queues and message previews. This is a scope mismatch that can lead users to grant or use the tool for analytics while unintentionally disclosing customer communications data beyond the stated purpose.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
The code prints customer-facing conversation metadata and previews of last messages, which may contain personal, confidential, or commercially sensitive information. Because this access is not justified by the stated analytics purpose, it increases the risk of unauthorized data exposure and privacy violations.

Natural-Language Policy Violations

Medium
Confidence
97% confidence
Finding
The script emits user-facing prompts and status text in Vietnamese, beginning with the conversation list header, and continues this pattern throughout the file. This enforces a specific language choice without offering the user a locale option or documenting that the skill is intentionally region-specific.

External Transmission

Medium
Category
Data Exfiltration
Content
exit 0
        fi
        
        response=$(curl -s -X POST \
            "${API_URL}/conversations/${CONV_ID}/messages" \
            -H "Authorization: Bearer ${API_KEY}" \
            -H "X-Workspace-ID: ${WORKSPACE_ID}" \
Confidence
87% confidence
Finding
This POST request transmits operator-supplied message content to an external service, affecting real customers and data outside the local environment. External transmission is expected for API clients, but here it is security-relevant because the skill's stated purpose is analytics, while this call performs customer messaging and can be abused for unauthorized outbound communication.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
This code sends date-range query parameters to an external Preny API and includes a bearer token from the environment in the request headers. Although the file comments describe API usage, there is no confirmation prompt or explicit user-facing warning that the user's query will trigger outbound requests using configured credentials.

Missing User Warnings

Medium
Confidence
86% confidence
Finding
The tag statistics handler performs external HTTP requests with bearer authentication, but the file provides no user disclosure that asking about tags causes data retrieval from a remote service. This is a safety-relevant external data access operation under the missing-warning rule for code files.

Missing User Warnings

Medium
Confidence
86% confidence
Finding
This function issues authenticated network requests to fetch system-tag data, which can affect privacy expectations because user/system data is sent to a remote API. There is no confirmation, visible notice, or warning in this code path to disclose that behavior to the user.

Static analysis

Detected: suspicious.env_credential_access

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
scripts/preny-handler.js:6