Back to skill

Security audit

Twenty CRM

Security checks for vulnerabilities and agentic risk

Overview

This appears to be a real Twenty CRM helper, but it needs Review because it can change or delete CRM data and has weak safety controls around credentials and configuration.

Install only if you are comfortable giving this skill API-token authority over your Twenty CRM. Use a narrowly scoped token, prefer HTTPS, avoid delete permissions unless needed, review the hardcoded config path before use, and treat delete/destroy helpers as potentially irreversible.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/twenty-config.sh:7
Finding

Arbitrary Shell Command Execution Through Sourced Configuration File

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/twenty-graphql.sh:26
Finding

Bearer Token and CRM Data Can Be Transmitted Over Plaintext HTTP

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/twenty-create-company.sh:18
Finding

Predictable Temporary File Enables Symlink-Based File Clobbering

Content
View full analysis
/tmp/twenty_create_company.json import json,sys name,domain,employees = sys.argv[1],sys.argv[2],sys.argv[3] payload = {"name": name} if domain: payload["domainName"] = domain if employees: try: payload["employees"] = int(employees) except ValueError: payload["employees"] = employees print(json.dumps(payload)) PY "$SCRIPT_DIR/twenty-rest-post.sh" "/companies" "$(cat /tmp/twenty_create_company.json)" ``` ### Technical Analysis The script writes generated JSON to a fixed filename in the shared `/tmp` directory. Shell output redirection opens the destination without exclusive creation and follows symbolic links. An attacker who can create `/tmp/twenty_create_company.json` before the victim runs the script can replace it with a symbolic link to another file writable by the victim. The redirection then truncates and overwrites the linked target. The temporary file is also not removed after use. Depending on the invoking user's `umask` and platform-specific `/tmp` protections, this can leave company input data accessible on disk and creates race conditions between concurrent invocations. ### Attack Path 1. A local attacker predicts the fixed filename `/tmp/twenty_create_company.json`. 2. The attacker creates that path as a symbolic link to a target file that the victim account can modify. 3. The victim invokes `twenty-create-company.sh`. 4. Bash follows the symbolic link while processing the output redirection. 5. The target is truncated and overwritten with the generated JSON payload. 6. The script subsequently reads from the same attacker-controlled path, allowing local interference with the CRM request as well. ### Impact Assessment The attacker can overwrite files writable by the ...[truncated 409 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (9)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill exposes shell-based capabilities that can make authenticated REST and GraphQL calls to a self-hosted CRM, but it does not declare any tool scope or allowed-tools restrictions. Without explicit scoping, an agent may invoke broader shell functionality than intended, increasing the chance of unauthorized data access, modification, or destructive actions against the CRM.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The documentation advertises a delete helper for CRM objects without any cautionary note, confirmation guidance, or safety constraints. In a CRM context this is materially risky because records may contain important business data, and an agent or user could invoke destructive deletion without understanding permanence, backup requirements, or approval expectations.

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/twenty-graphql.sh (reported line 26)May include surrounding context.

sh
BODY=$(printf '{"query":%s}' "$QUERY_JSON")
fi

curl -sS -X POST "$TWENTY_BASE_URL/graphql" \
  -H "Authorization: Bearer $TWENTY_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This shell script performs an HTTP DELETE request, and may target an even more destructive '/destroy' endpoint, but it provides no confirmation prompt, warning message, or visible user disclosure before executing the operation. The brief usage comments describe syntax but do not warn about deletion impact, which increases the risk of accidental destructive use.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script performs an outbound HTTP request with curl and includes the TWENTY_API_KEY bearer token in the Authorization header. While the code is straightforward, there is no confirmation prompt, user-facing log/message, or inline warning explaining that a credential-backed network request will be made.

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/twenty-rest-patch.sh (reported line 18)May include surrounding context.

sh
exit 1
fi

curl -sS -X PATCH "$TWENTY_BASE_URL/rest${PATH_PART}" \
  -H "Authorization: Bearer $TWENTY_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The script performs a network PATCH request and sends user-supplied JSON along with a bearer token, but it provides no confirmation prompt, visible disclosure, or explanatory comment warning that data will be transmitted to a remote service. This is a safety-relevant operation for a code file because it modifies remote state and uses sensitive credentials.

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/twenty-rest-post.sh (reported line 18)May include surrounding context.

sh
exit 1
fi

curl -sS -X POST "$TWENTY_BASE_URL/rest${PATH_PART}" \
  -H "Authorization: Bearer $TWENTY_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

This shell script performs a network POST request using user-provided JSON and includes an Authorization bearer token from configuration, but the file provides no confirmation prompt, warning message, or explanatory comment about transmitting data off-host. For a code file, this is a safety-relevant external data transmission and credential use with no visible user disclosure in the script itself.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.