Back to skill

Security audit

Gandi - Registrar & DNS

Security checks for vulnerabilities and agentic risk

Overview

The skill is a disclosed Gandi management tool, but it needs review because credential handling and local profile storage have real safety gaps.

Review before installing. Use separate least-privilege Gandi tokens, prefer read-only tokens for routine checks, do not place real tokens on command lines, keep api_url pinned to Gandi production or sandbox, and avoid profile names or configs from untrusted input until path validation is fixed.

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/gandi-api.js:66
Finding
Bearer Token Can Be Sent to an Arbitrary Configured HTTPS Endpoint<![CDATA[ ## Vulnerability Details **File Location**: `scripts/gandi-api.js:66-75, 216-242` **Vulnerability Type**: Unrestricted credential destination / credential exfiltration **Risk Level**: High ### Vulnerable Code ```js export function readApiUrl() { try { if (fs.existsSync(URL_FILE)) { const url = fs.readFileSync(URL_FILE, 'utf8').trim(); if (url) return url; } } catch (error) { // Ignore errors, use default } return DEFAULT_API_URL; } ``` ```js export function gandiApi(endpoint, method = 'GET', data = null, queryParams = {}, tokenOverride = null) { return new Promise((resolve, reject) => { const token = tokenOverride || readToken(); const apiUrl = readApiUrl(); // Build URL with query parameters const url = new URL(endpoint, apiUrl); Object.entries(queryParams).forEach(([key, value]) => { if (value !== undefined && value !== null) { url.searchParams.append(key, value); } }); const options = { method, headers: { 'Authorization': `Bearer ${token}`, 'Accept': 'application/json' } }; // Add Content-Type for requests with body if (data && ['POST', 'PUT', 'PATCH'].includes(method)) { options.headers['Content-Type'] = 'application/json'; } const req = https.request(url, options, (res) => { ``` ### Technical Analysis The API base URL is loaded from `~/.config/gandi/api_url` and used without validating its hostname, port, or expected Gandi origin. The request code subsequently attaches the Gandi Personal Access Token to every request through the `Authorization` header. Use of HTTPS protects the connection in transit but does not establish that the recipient is Gandi. An attacker-controlled server with a valid TLS certificate can receive the token if the configuration file is modified to reference that server. A custom endpoint can be useful for sandbox testing, but unrestricted destinations exceed the minimum s ...[truncated 1350 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Allow only the documented Gandi origins by default: - `https://api.gandi.net` - `https://api.sandbox.gandi.net` 2. Parse the configured value with `new URL()` and reject: - Non-HTTPS protocols - Embedded usernames or passwords - Unexpected hostnames - Fragments - Unexpected ports 3. Associate credentials with their intended environment. A production token must never be sent to the sandbox or a custom endpoint, and vice versa. 4. If custom endpoints are required for development, require an explicit unsafe-development flag and separate test credentials. 5. Log the selected hostname before authentication without logging the token. 6. Apply restrictive permissions to `api_url` and its parent directory, although permissions should supplement rather than replace destination validation. 7. Consider pinning requests to a fixed API origin in production instead of accepting a file-based override. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/manage-profiles.js:35
Finding
Gandi API Tokens Are Accepted Through Command-Line Arguments<![CDATA[ ## Vulnerability Details **File Location**: `scripts/manage-profiles.js:35-50, 96-104` **Vulnerability Type**: Secret exposure through process arguments and shell history **Risk Level**: Medium ### Vulnerable Code ```js const args = process.argv.slice(2); if (args.length < 1) { console.error('Usage: node manage-profiles.js <action> [options]'); console.error(''); console.error('Actions:'); console.error(' list - List all profiles'); console.error(' add <name> <token> - Add a new profile'); console.error(' remove <name> - Remove a profile'); console.error(' default <name> - Set default profile'); console.error(' show <name> - Show profile details'); console.error(' migrate - Migrate legacy token'); console.error(''); console.error('Examples:'); console.error(' node manage-profiles.js list'); console.error(' node manage-profiles.js add personal YOUR_TOKEN'); console.error(' node manage-profiles.js add work YOUR_TOKEN --set-default'); ``` ```js async function addAction(name, token, setDefault = false) { if (!name || !token) { console.error('❌ Usage: node manage-profiles.js add <name> <token>'); process.exit(1); } console.log(`📝 Adding profile "${name}"...`); ``` ### Technical Analysis The profile-management command requires users to provide the Gandi Personal Access Token as a positional command-line argument. Command-line arguments can be exposed through: - Process inspection utilities while the command is running - Operating-system process monitoring and auditing - Shell history - Terminal session recording - CI/CD logs - Wrapper scripts and job telemetry Although the profile manager later stores tokens in files with mode `0600`, secure destination permissions do not prevent disclosure that occurs before the token is written. ### Attack Path 1. A user follows the documented command an ...[truncated 827 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the token positional argument from the command interface. 2. Read the token using a hidden interactive prompt that disables terminal echo. 3. For automation, accept the token through: - Standard input - A protected file descriptor - A secret-manager integration - A narrowly scoped environment variable 4. Avoid printing or logging the token under all success and error conditions. 5. Update usage messages and examples so they never encourage placing real tokens in shell commands. 6. Document shell-history cleanup and immediate token rotation for users who previously followed the affected instructions. 7. Add automated tests verifying that token values do not appear in process arguments or application output. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/profile-manager.js:108
Finding
Unsanitized Profile Names Permit Filesystem Path Traversal<![CDATA[ ## Vulnerability Details **File Location**: `scripts/profile-manager.js:108-147, 159-170` **Vulnerability Type**: Path traversal leading to unintended file write or deletion **Risk Level**: High ### Vulnerable Code ```js export async function addProfile(name, token, options = {}) { ensureConfigDirs(); const config = loadProfiles(); // Check if profile already exists if (config.profiles[name]) { throw new Error(`Profile '${name}' already exists`); } // Save token to file const tokenFile = `tokens/${name}.token`; const tokenPath = path.join(CONFIG_DIR, tokenFile); fs.writeFileSync(tokenPath, token, { mode: 0o600 }); // Fetch organization info let orgInfo; try { // Temporarily use this token to fetch org info const result = await gandiApi('/v5/organization/organizations', 'GET', null, {}, token); orgInfo = result.data[0]; // Use first org } catch (error) { // Clean up token file on error fs.unlinkSync(tokenPath); throw new Error(`Failed to fetch organization info: ${error.message}`); } ``` ```js export function removeProfile(name) { const config = loadProfiles(); if (!config.profiles[name]) { throw new Error(`Profile '${name}' not found`); } // Delete token file const tokenPath = path.join(CONFIG_DIR, config.profiles[name].token_file); if (fs.existsSync(tokenPath)) { fs.unlinkSync(tokenPath); } // Remove profile delete config.profiles[name]; ``` ### Technical Analysis The profile name is inserted directly into a relative filesystem path: ```text tokens/[profile name].token ``` No validation rejects path separators, traversal components such as `..`, absolute paths, or platform-specific path syntax. `path.join()` normalizes traversal components rather than enforcing confinement to `TOKENS_DIR`. The same unsafe path is used during error cleanup and profile removal. Consequently, the issue affects both file creation and deletion. The process can only modify fil ...[truncated 1621 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Validate profile names against a strict allowlist, for example: ```js if (!/^[A-Za-z0-9_-]{1,64}$/.test(name)) { throw new Error('Invalid profile name'); } ``` 2. Reject profile names containing: - `/` or `\` - `.` or `..` path components - Absolute paths - Null bytes - Platform-specific drive or device syntax 3. Resolve the final path and enforce directory confinement: ```js const base = path.resolve(TOKENS_DIR); const tokenPath = path.resolve(base, `${name}.token`); if (!tokenPath.startsWith(`${base}${path.sep}`)) { throw new Error('Token path escapes token directory'); } ``` 4. Generate random internal token filenames rather than deriving filenames from user-controlled profile names. 5. Validate `token_file` fields loaded from `profiles.json` before reading or deleting them. 6. Use exclusive creation where appropriate and protect against symbolic-link attacks. 7. Perform path validation before any write, API request, cleanup, or deletion. 8. Add tests covering traversal strings, absolute paths, mixed separators, encoded separators, and malicious `profiles.json` entries. ]]>
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (141)

Tool Parameter Abuse

High
Category
Tool Misuse
Content
#### delete-dns-record.js
- **Purpose:** Delete a DNS record
- **Network calls:** DELETE /v5/livedns/domains/{domain}/records/{name}/{type} (Gandi API)
- **Side effects:** ⚠️ **DELETES DNS RECORD** - can break websites/email
- **Usage:** `node delete-dns-record.js example.com old A [--force]`
- **What it does:**
Confidence
90% confidence
Finding
This skill exposes a destructive DELETE operation whose parameters directly control which DNS record is removed, and the docs indicate deletion can be forced with `--force`. In an agent setting, insufficient validation, confirmation hardening, or policy gating around attacker-influenced `domain`, `name`, and `type` values could lead to unauthorized or unsafe DNS changes that disrupt websites, email, verification records, or security controls.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
#### delete-email-forward.js
- **Purpose:** Delete email forward
- **Network calls:** DELETE /v5/email/forwards/{domain}/{mailbox} (Gandi API)
- **Side effects:** ⚠️ **STOPS EMAIL FORWARDING** - emails will bounce
- **Usage:** `node delete-email-forward.js example.com mailbox [--force]`
- **What it does:**
Confidence
91% confidence
Finding
This documented DELETE operation can remove email forwards based on user-supplied `domain` and `mailbox` parameters, immediately causing mail loss or bounce behavior. In an agent-executed environment, parameter abuse or prompt-influenced invocation could disable routing for critical addresses or interfere with account recovery, support, or security notification mailboxes.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The skill description appears materially broader and partially inconsistent with the documented or inferred behavior, including undeclared local configuration inspection, token/source reporting, contact-data handling, and cleanup behaviors. Security reviewers and users may grant trust or permissions based on inaccurate claims, which can lead to unsafe execution of sensitive local-file or account-modifying actions.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
The skill description appears materially broader and partially inconsistent with the documented or inferred behavior, including undeclared local configuration inspection, token/source reporting, contact-data handling, and cleanup behaviors. Security reviewers and users may grant trust or permissions based on inaccurate claims, which can lead to unsafe execution of sensitive local-file or account-modifying actions.

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding
The skill description appears materially broader and partially inconsistent with the documented or inferred behavior, including undeclared local configuration inspection, token/source reporting, contact-data handling, and cleanup behaviors. Security reviewers and users may grant trust or permissions based on inaccurate claims, which can lead to unsafe execution of sensitive local-file or account-modifying actions.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The skill description appears materially broader and partially inconsistent with the documented or inferred behavior, including undeclared local configuration inspection, token/source reporting, contact-data handling, and cleanup behaviors. Security reviewers and users may grant trust or permissions based on inaccurate claims, which can lead to unsafe execution of sensitive local-file or account-modifying actions.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
The skill description appears materially broader and partially inconsistent with the documented or inferred behavior, including undeclared local configuration inspection, token/source reporting, contact-data handling, and cleanup behaviors. Security reviewers and users may grant trust or permissions based on inaccurate claims, which can lead to unsafe execution of sensitive local-file or account-modifying actions.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The skill description appears materially broader and partially inconsistent with the documented or inferred behavior, including undeclared local configuration inspection, token/source reporting, contact-data handling, and cleanup behaviors. Security reviewers and users may grant trust or permissions based on inaccurate claims, which can lead to unsafe execution of sensitive local-file or account-modifying actions.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding
The skill description appears materially broader and partially inconsistent with the documented or inferred behavior, including undeclared local configuration inspection, token/source reporting, contact-data handling, and cleanup behaviors. Security reviewers and users may grant trust or permissions based on inaccurate claims, which can lead to unsafe execution of sensitive local-file or account-modifying actions.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The skill description appears materially broader and partially inconsistent with the documented or inferred behavior, including undeclared local configuration inspection, token/source reporting, contact-data handling, and cleanup behaviors. Security reviewers and users may grant trust or permissions based on inaccurate claims, which can lead to unsafe execution of sensitive local-file or account-modifying actions.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The skill description appears materially broader and partially inconsistent with the documented or inferred behavior, including undeclared local configuration inspection, token/source reporting, contact-data handling, and cleanup behaviors. Security reviewers and users may grant trust or permissions based on inaccurate claims, which can lead to unsafe execution of sensitive local-file or account-modifying actions.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The skill description appears materially broader and partially inconsistent with the documented or inferred behavior, including undeclared local configuration inspection, token/source reporting, contact-data handling, and cleanup behaviors. Security reviewers and users may grant trust or permissions based on inaccurate claims, which can lead to unsafe execution of sensitive local-file or account-modifying actions.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The skill description appears materially broader and partially inconsistent with the documented or inferred behavior, including undeclared local configuration inspection, token/source reporting, contact-data handling, and cleanup behaviors. Security reviewers and users may grant trust or permissions based on inaccurate claims, which can lead to unsafe execution of sensitive local-file or account-modifying actions.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The skill description appears materially broader and partially inconsistent with the documented or inferred behavior, including undeclared local configuration inspection, token/source reporting, contact-data handling, and cleanup behaviors. Security reviewers and users may grant trust or permissions based on inaccurate claims, which can lead to unsafe execution of sensitive local-file or account-modifying actions.

Credential Access

High
Category
Privilege Escalation
Content
name: gandi
description: "Comprehensive Gandi domain registrar integration for domain and DNS management. Register and manage domains, create/update/delete DNS records (A, AAAA, CNAME, MX, TXT, SRV, and more), configure email forwarding and aliases, check SSL certificate status, create DNS snapshots for safe rollback, bulk update zone files, and monitor domain expiration. Supports multi-domain management, zone file import/export, and automated DNS backups. Includes both read-only and destructive operations with safety controls."
disable-model-invocation: true
metadata: {"openclaw":{"version":"0.2.7","disable-model-invocation":true,"capabilities":["dns-modification","email-management","domain-registration","destructive-operations"],"credentials":{"type":"file","location":"~/.config/gandi/api_token","description":"Gandi Personal Access Token (PAT)","permissions":600},"requires":{"bins":["node","npm"],"env":["GANDI_API_TOKEN"]},"primaryEnv":"GANDI_API_TOKEN"}}
---

# Gandi Domain Registrar Skill
Confidence
87% confidence
Finding
The skill explicitly uses an API token credential stored in a predictable local path or environment variable, and the token grants access to registrar, DNS, and email operations. In this context, credential access is expected functionality, but it is still security-sensitive because compromise of the token enables significant account impact.

Credential Access

High
Category
Privilege Escalation
Content
**Before running ANY script:**
1. Review the script code to understand what it does
2. Create DNS snapshots before bulk changes (`create-snapshot.js`)
3. Use read-only Personal Access Tokens where possible
4. Test on non-production domains first
5. Understand that some operations cannot be undone
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
**Before running ANY script:**
1. Review the script code to understand what it does
2. Create DNS snapshots before bulk changes (`create-snapshot.js`)
3. Use read-only Personal Access Tokens where possible
4. Test on non-production domains first
5. Understand that some operations cannot be undone
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Ae1

High
Category
analysis-evasion
Content
- `add-dns-record.js`, `delete-dns-record.js`, `update-dns-bulk.js`
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
- `list-domains.js`, `list-dns.js`, `list-snapshots.js`
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
- `list-domains.js`, `list-dns.js`, `list-snapshots.js`
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
- `list-domains.js`, `list-dns.js`, `list-snapshots.js`
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
- `list-domains.js`, `list-dns.js`, `list-snapshots.js`
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
- `list-email-forwards.js`, `check-domain.js`, `check-ssl.js`
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
- `list-email-forwards.js`, `check-domain.js`, `check-ssl.js`
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
- `list-email-forwards.js`, `check-domain.js`, `check-ssl.js`
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Static analysis

Detected: suspicious.insecure_tls_verification

HTTPS certificate verification is disabled.

Warn
Code
suspicious.insecure_tls_verification
Location
scripts/check-ssl.js:21