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 can make authenticated CRM changes and deletions, including a destroy mode, without built-in safeguards.

Review before installing. Use a least-privilege Twenty API key, point TWENTY_BASE_URL only at the CRM instance you intend to manage, keep any config file private and user-owned, and require explicit human approval before an agent runs DELETE or destroy operations.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/twenty-config.sh:11
Finding

Arbitrary Shell Execution Through Unsafe Configuration Loading

Content
View full analysis

Vulnerability Details

File Location: scripts/twenty-config.sh:11, 29-31
Vulnerability Type: Executable configuration file / arbitrary shell command execution
Risk Level: Medium

Vulnerable Code

bash
CONFIG_FILE="${TWENTY_CONFIG_FILE:-$DEFAULT_CONFIG_FILE}"

if [ -f "$CONFIG_FILE" ]; then
  # shellcheck disable=SC1090
  source "$CONFIG_FILE"
fi

Technical Analysis

The script treats config/twenty.env as a data-based environment file but loads it with Bash's source built-in. Sourcing a file executes its entire contents in the current shell rather than parsing only environment-variable assignments.

Consequently, a configuration file can contain arbitrary shell commands, command substitutions, functions, redirections, or other Bash syntax. The TWENTY_CONFIG_FILE environment variable also allows the caller to select any readable file as the configuration source.

This becomes exploitable when an attacker can modify the default configuration file, influence TWENTY_CONFIG_FILE, or otherwise cause a malicious file to be loaded. The injected commands execute with the same operating-system privileges and environment as the invoked CRM helper.

Attack Path

  1. An attacker gains control over config/twenty.env or influences the process environment to set TWENTY_CONFIG_FILE to an attacker-controlled readable file.
  2. The attacker places shell commands in that file, potentially alongside valid TWENTY_BASE_URL and TWENTY_API_KEY assignments.
  3. A user or agent invokes any helper that sources twenty-config.sh.
  4. twenty-config.sh executes source "$CONFIG_FILE".
  5. The attacker's commands run before the intended CRM API request and inherit the helper's privileges and environment.

Impact Assessment

Successful exploitation permits arbitrary command execution under the account running the Skill. The attacker could read files available to that account, access the configured Twenty CRM API key, alter local data, or mak ...[truncated 327 chars]

Remediation
View remediation

Remediation Suggestions

Replace source with a non-executing configuration parser:

  1. Accept only an explicit allowlist of keys, namely TWENTY_BASE_URL and TWENTY_API_KEY.
  2. Parse assignment lines as data without eval, source, or shell expansion.
  3. Reject command substitutions, shell operators, functions, redirections, unrecognized keys, and malformed lines.
  4. Prefer direct environment-variable configuration or a structured format parsed by a safe standard parser.
  5. If TWENTY_CONFIG_FILE remains supported, resolve and validate the path and ensure that the file is a regular file owned by the expected user.
  6. Reject configuration files writable by group or other users and recommend mode 0600.
  7. Avoid exporting the API key unless child processes genuinely require it; pass secrets only to the specific command that needs them.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (11)

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

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

Content

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

md
## Secret handling

- Do not commit `TWENTY_API_KEY`.
- If using `config/twenty.env`, keep it private (for example: `chmod 600 config/twenty.env`).

## Scope

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

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

Content

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

md
## Secret handling

- Do not commit `TWENTY_API_KEY`.
- If using `config/twenty.env`, keep it private (for example: `chmod 600 config/twenty.env`).

## Scope

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding

The skill exposes shell-capable scripts but does not declare any explicit tool scope such as permissions or allowed-tools. That increases the chance an agent can invoke broader shell behavior than intended, reducing policy visibility and making misuse of the skill harder to constrain or audit.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The documentation includes a DELETE helper for CRM objects without any warning, confirmation step, or guidance on safe use. In a CRM context, accidental or agent-initiated deletions can permanently remove business records, making destructive actions easier to trigger unintentionally.

Content

No source excerpt is available for this finding.

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
70% confidence
Finding

Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Content

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

md
## Security

- Keep `TWENTY_API_KEY` out of git and avoid storing it in shared/world-readable files.
- If you use `config/twenty.env`, prefer restrictive permissions (for example `chmod 600 config/twenty.env`).
- Pass REST query parameters as separate `key=value` arguments; do not append raw query strings to REST paths.

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 27)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" \

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The skill manifest says the skill interacts with Twenty CRM via REST/GraphQL, which is broad, but this file specifically implements DELETE operations and an optional /destroy endpoint for stronger destructive action. That behavior is more dangerous than generic interaction and is not signaled anywhere in the file documentation or manifest description excerpt.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

This script performs irreversible or potentially irreversible DELETE operations, including an optional /destroy mode, without any confirmation prompt, dry-run mode, or secondary validation beyond path format checking. In an agentic or automated context, that increases the chance of accidental record loss from malformed inputs, misuse, or prompt-induced actions, especially because the command directly authenticates and executes against the live API.

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 19)May include surrounding context.

sh
fi
validate_rest_path "$PATH_PART"

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
88% confidence
Finding

The script performs a network PATCH request with a JSON payload and sends a bearer token from an environment-sourced configuration, but there is no confirmation prompt, user-facing log message, or explanatory comment near the operation. For code files, outbound network actions and credential use should have some visible disclosure unless clearly communicated elsewhere in the skill materials.

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 19)May include surrounding context.

sh
fi
validate_rest_path "$PATH_PART"

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" \

Static analysis

No suspicious patterns detected.