Back to skill

Security audit

Alexandrie

Security checks for vulnerabilities and agentic risk

Overview

This appears to be a real Alexandrie notes client, but it needs Review because it handles live credentials and session files unsafely and can delete remote notes immediately.

Install only if you trust the specific Alexandrie account/environment and are comfortable with a shell script reading that local password file. Before use, the credential loading should be changed to read a single secret as data, cookies should be stored in a private user-owned state directory, and delete should require confirmation or a clearly intentional force option.

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
alexandrie.sh:12
Finding
Arbitrary Shell Code Execution Through Sourced Credential File<![CDATA[ ## Vulnerability Details **File Location**: `alexandrie.sh:12-14` **Vulnerability Type**: Executable credential-file loading **Risk Level**: High ### Vulnerable Code ```bash # Load password from env source /home/eth3rnit3/clawd/.env 2>/dev/null || true PASSWORD="${ALEXANDRIE_PASSWORD:-}" ``` ### Technical Analysis The script uses Bash `source` to obtain a single credential from `/home/eth3rnit3/clawd/.env`. Unlike a data-only configuration parser, `source` evaluates the entire file as shell code in the current process. Consequently, command substitutions, function definitions, redirections, and arbitrary commands placed in the `.env` file execute with the privileges of the user invoking the Skill. This happens before command dispatch, so even non-authentication operations such as `help` trigger evaluation. The declared functionality requires access only to `ALEXANDRIE_PASSWORD`. Executing every statement in a general environment file exceeds that minimum requirement. Sourcing the file may also load unrelated values into the shell, unnecessarily expanding the sensitive-data exposure surface. ### Attack Path 1. An attacker or compromised local process obtains permission to modify or replace `/home/eth3rnit3/clawd/.env`. 2. The attacker adds a shell payload, for example a command substitution or ordinary shell command. 3. A user or Agent invokes any `alexandrie.sh` command. 4. Bash evaluates the malicious statement through `source`. 5. The payload runs under the invoking user's account before the requested Alexandrie operation begins. This path requires the attacker to be able to alter the referenced credential file or a component of its path. ### Impact Assessment Successful exploitation permits arbitrary command execution with all operating-system privileges available to the invoking user. The payload could read or modify files accessible to that account, access other credentials available to the process, alter note data through the authen ...[truncated 216 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not use `source` for credential storage. 2. Prefer requiring the caller to provide `ALEXANDRIE_PASSWORD` through an already established environment or a dedicated secret manager. 3. If file-based storage is necessary, place only the password value in a dedicated file and read it strictly as data: ```bash PASSWORD_FILE="${ALEXANDRIE_PASSWORD_FILE:-$HOME/.config/alexandrie/password}" if [[ ! -f "$PASSWORD_FILE" || -L "$PASSWORD_FILE" ]]; then echo "Error: Invalid password file" >&2 exit 1 fi PASSWORD=$(<"$PASSWORD_FILE") ``` 4. Verify that the credential file is owned by the expected user and is not group- or world-accessible. 5. Set restrictive permissions, such as `0600` for the secret file and `0700` for its parent directory. 6. Load the password only for operations that require a new login rather than for every command. 7. Avoid suppressing all loading errors with `2>/dev/null || true`; report configuration and permission failures clearly without printing secret contents. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
alexandrie.sh:8
Finding
Predictable Authentication State Files in Shared Temporary Storage<![CDATA[ ## Vulnerability Details **File Locations**: `alexandrie.sh:8-9`, `alexandrie.sh:22-28`, `alexandrie.sh:33-35`, and `alexandrie.sh:40` **Vulnerability Type**: Unsafe predictable temporary files **Risk Level**: Medium ### Vulnerable Code ```bash TOKEN_FILE="/tmp/alexandrie_cookies.txt" USER_ID_FILE="/tmp/alexandrie_user_id" ``` ```bash auth_curl() { if [[ ! -f "$TOKEN_FILE" ]]; then echo "Error: Not logged in. Run: $0 login" >&2 exit 1 fi curl -s -b "$TOKEN_FILE" -c "$TOKEN_FILE" "$@" } ``` ```bash RESPONSE=$(curl -s -c "$TOKEN_FILE" -X POST "$BASE_URL/auth" \ -H "Content-Type: application/json" \ -d "{\"username\": \"$USERNAME\", \"password\": \"$PASSWORD\"}") # Extract user ID from response USER_ID=$(echo "$RESPONSE" | jq -r '.result.id // empty' 2>/dev/null) if [[ -n "$USER_ID" && "$USER_ID" != "null" ]]; then echo "$USER_ID" > "$USER_ID_FILE" ``` ### Technical Analysis The client stores authentication cookies and the authenticated user ID at fixed, globally predictable paths under `/tmp`. It does not create a private runtime directory, set a restrictive `umask`, verify file ownership, or reject symbolic links and other unexpected file types before reading or writing these paths. `/tmp` is normally shared among local users. Although sticky-directory protections restrict deletion of files owned by other users, they do not make predictable names safe against pre-creation before the legitimate client uses them. The user ID write uses ordinary shell redirection: ```bash echo "$USER_ID" > "$USER_ID_FILE" ``` If an attacker can pre-create `/tmp/alexandrie_user_id` as a symbolic link, the redirection can follow that link and overwrite a file writable by the victim with the returned numeric user ID. Predictable cookie storage also creates risks of session-state pre-creation, tampering, or disclosure where local permissions permit access. ### Attack Path A file-overwrite attack can proceed as follows: 1 ...[truncated 1699 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Store state in a user-private runtime directory, preferring `$XDG_RUNTIME_DIR` when it is available and owned by the current user. 2. Otherwise, create a unique directory with `mktemp -d` and enforce restrictive permissions: ```bash umask 077 STATE_DIR=$(mktemp -d "${TMPDIR:-/tmp}/alexandrie.XXXXXXXX") TOKEN_FILE="$STATE_DIR/cookies" USER_ID_FILE="$STATE_DIR/user_id" ``` 3. If authentication state must persist across separate invocations, use a stable private directory such as `$XDG_STATE_HOME/alexandrie` or `$HOME/.local/state/alexandrie`, created with mode `0700`. 4. Create files with mode `0600` and validate that they: - are regular files; - are owned by the effective user; - are not symbolic links; - are not group- or world-accessible. 5. Write the user ID through a securely created temporary file inside the private directory, then atomically rename it. 6. Remove cookie and user-ID files after logout and provide cleanup for abandoned temporary state. 7. Consider avoiding a separate user-ID file by extracting the authenticated identity from a securely stored session response or querying it from the server when needed. ]]>
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
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (11)

Tool Parameter Abuse

High
Category
Tool Misuse
Content
- `GET /nodes/search?q=query` - Search nodes
- `POST /nodes` - Create node
- `PUT /nodes/:nodeId` - Update node
- `DELETE /nodes/:nodeId` - Delete node

### Authentication
JWT token stored in cookies after login (`/tmp/alexandrie_cookies.txt`).
Confidence
80% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Credential Access

High
Category
Privilege Escalation
Content
USER_ID_FILE="/tmp/alexandrie_user_id"

# Load password from env
source /home/eth3rnit3/clawd/.env 2>/dev/null || true
PASSWORD="${ALEXANDRIE_PASSWORD:-}"

if [[ -z "$PASSWORD" ]]; then
Confidence
94% confidence
Finding
The script sources a local .env file as executable shell code, not as inert configuration. If that file is modified by another local user, compromised process, or unsafe sync mechanism, arbitrary commands could run in the script's execution context and credentials could be stolen or additional actions performed.

Credential Access

High
Category
Privilege Escalation
Content
PASSWORD="${ALEXANDRIE_PASSWORD:-}"

if [[ -z "$PASSWORD" ]]; then
    echo "Error: ALEXANDRIE_PASSWORD not set in .env"
    exit 1
fi
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill explicitly discloses where a live password is stored and notes that JWT session cookies are written to a predictable file path, which exposes sensitive authentication material handling details. In an agent setting, this increases the chance of credential harvesting, unintended secret access, or session-token theft by other tools, users, or processes with local access.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The markdown documents a `delete` command that removes notes, but it does not warn that the action is destructive or irreversible, nor does it mention any confirmation step. For a skill description, omitting a warning about data deletion can leave users unaware of the risk to their stored notes.

External Transmission

Medium
Category
Data Exfiltration
Content
echo "Error: Not logged in. Run: $0 login" >&2
        exit 1
    fi
    curl -s -b "$TOKEN_FILE" -c "$TOKEN_FILE" "$@"
}

# Commands
Confidence
70% 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
}')
        
        echo "Creating note: $NAME"
        auth_curl -X POST "$BASE_URL/nodes" \
            -H "Content-Type: application/json" \
            -d "$JSON" | jq '.'
        ;;
Confidence
70% 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
'{name: $name, content: $content, accessibility: 1, role: 3, user_id: $userId}')
        
        echo "Updating note $NODE_ID..."
        auth_curl -X PUT "$BASE_URL/nodes/$NODE_ID" \
            -H "Content-Type: application/json" \
            -d "$JSON" | jq '.'
        ;;
Confidence
70% 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
95% confidence
Finding
The delete command performs an authenticated destructive action immediately with no confirmation, dry-run, or safety guard. In a CLI that manipulates remote notes, a mistyped node ID or accidental invocation can cause irreversible data loss on the server.

Missing User Warnings

Low
Confidence
84% confidence
Finding
The code sources a local environment file and reads the ALEXANDRIE_PASSWORD credential, but there is no surrounding disclosure beyond an internal comment. For safety-sensitive credential handling, users should be explicitly informed that the script reads secrets from the environment or a local .env file.

Intent-Code Divergence

Low
Confidence
93% confidence
Finding
The help output says `create <name> [content] [categoryId] [parentId]`, implying four arguments and support for `categoryId`. But the `create` implementation only reads three positional arguments total after the command (`NAME`, `CONTENT`, `PARENT_ID`) and never handles any `categoryId` field. This is an active documentation-to-code contradiction, not just an omitted detail.

Static analysis

No suspicious patterns detected.