Back to skill

Security audit

Ghostfolio

Security checks for vulnerabilities and agentic risk

Overview

This Ghostfolio helper matches its purpose, but it needs review because it handles a long-lived financial-data token and includes unsafe remote/TLS guidance.

Install only if you will configure GHOSTFOLIO_BASE_URL yourself and keep it to localhost or a verified HTTPS Ghostfolio server. Do not use curl -k with real tokens; fix certificate trust instead. Rotate the Ghostfolio token if it may have been sent to the wrong host, and avoid leaving probe response files in /tmp.

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
SKILL.md:15
Finding
Long-Lived Authentication Token Can Be Sent to an Untrusted Configurable Endpoint## Vulnerability Details **File Location**: `SKILL.md:15-17`, `SKILL.md:39-42`, and `SKILL.md:93-96` **Vulnerability Type**: Credential exposure through insufficient endpoint validation **Risk Level**: High The skill defines a user-configurable base URL and subsequently sends the long-lived Ghostfolio token to that URL. It neither validates the destination hostname nor requires HTTPS for non-loopback destinations. ```bash # Prefer local access when available export GHOSTFOLIO_BASE_URL="http://127.0.0.1:3333" # Optional remote example: # export GHOSTFOLIO_BASE_URL="https://rpi5.gate-mintaka.ts.net:8444" ``` The anonymous exchange sends the long-lived token in a request body: ```bash AUTH_TOKEN=$(curl -fsS "$GHOSTFOLIO_BASE_URL/api/v1/auth/anonymous" \ -H 'Content-Type: application/json' \ --data "{\"accessToken\":\"$GHOSTFOLIO_TOKEN\"}" \ | jq -r '.authToken') ``` The direct authentication probe sends it as a bearer token: ```bash code=$(curl -s -o /tmp/gf_probe.json -w '%{http_code}' "$GHOSTFOLIO_BASE_URL$ep" \ -H "Authorization: Bearer $GHOSTFOLIO_TOKEN" \ -H 'Accept: application/json' \ -H "x-ghostfolio-timezone: $GHOSTFOLIO_TIMEZONE") ``` ### Technical Analysis `GHOSTFOLIO_BASE_URL` determines the server receiving both authentication requests and authenticated API calls. No hostname allowlist, URL-scheme validation, trust confirmation, or loopback-only restriction is applied before the long-lived token is transmitted. Although plaintext HTTP is appropriate for the documented IPv4 loopback address when the service is local, the same variable can contain an arbitrary non-loopback HTTP or HTTPS destination. The remote example also uses a project-specific hostname rather than clearly limiting remote access to an administrator-verified Ghostfolio instance. Consequently, an incorrectly configured or attacker-influenced environment value can direct the authentication material to a server out ...[truncated 1145 chars]
Remediation
## Remediation Suggestions - Permit plaintext HTTP only when the parsed destination is an explicit loopback address such as `127.0.0.1` or `::1`. - Require HTTPS for every non-loopback destination. - Validate the destination hostname against an administrator-controlled allowlist before transmitting credentials. - Require explicit user confirmation when the endpoint differs from the expected Ghostfolio host. - Remove the project-specific remote hostname from the generic skill example or clearly mark it as a placeholder that must be replaced and independently verified. - Recommend short-lived, narrowly scoped, and revocable API credentials rather than long-lived tokens. - Avoid inheriting security-sensitive endpoint values from untrusted execution environments. - Document token rotation and immediate revocation procedures for suspected disclosure.

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:121
Finding
TLS Certificate Verification Bypass Recommended for Authenticated Requests## Vulnerability Details **File Location**: `SKILL.md:121-123` **Vulnerability Type**: Improper certificate validation guidance **Risk Level**: Medium The troubleshooting guidance recommends temporarily disabling TLS certificate verification: ```markdown - Connectivity issues - Prefer local URL (`http://127.0.0.1:3333`) if service runs locally. - For remote TLS diagnostics only, temporary `curl -k` can help. ``` ### Technical Analysis The `curl -k` option, also known as `--insecure`, disables validation of the remote server's TLS certificate and hostname. Encryption without authentication does not establish that the client is communicating with the intended Ghostfolio server. This is particularly hazardous in this skill because requests carry a long-lived bearer token or exchange that token for an authentication token. A user may also forget to remove `-k` after diagnostics, causing the unsafe behavior to persist in copied commands or automation. ### Attack Path 1. A user encounters a certificate validation error while accessing a remote Ghostfolio server. 2. Following the troubleshooting advice, the user adds `-k` to an authenticated `curl` request. 3. An attacker able to intercept or redirect network traffic presents an arbitrary certificate. 4. Because certificate and hostname verification are disabled, `curl` accepts the attacker's endpoint. 5. The authenticated request, including the bearer token or token-exchange body, is delivered to the attacker. 6. The attacker may steal the credential, observe financial data, or return forged API responses. ### Impact Assessment An attacker in a suitable network or routing position can impersonate the Ghostfolio server. This may expose authentication tokens and sensitive portfolio responses or allow response manipulation. Any subsequent unauthorized Ghostfolio access is limited to the permissions of the intercepted token.
Remediation
## Remediation Suggestions - Remove the recommendation to use `curl -k` or `--insecure`. - Diagnose TLS failures with non-bypassing tools and options such as `curl -v`, certificate inspection, and server-chain verification. - Install the correct trusted certificate authority in the system trust store. - For private certificate authorities, use `curl --cacert /trusted/path/ca.pem` with an independently verified CA certificate. - Verify that the certificate's subject alternative name matches the configured hostname. - If certificate pinning is operationally appropriate, document a securely distributed public-key pin rather than disabling verification. - Never submit a real token while diagnosing a server whose identity has not been authenticated.

T09 · Insecure Skill Coding Practices

Note
Location
SKILL.md:88
Finding
Predictable Shared Temporary File Used for Authenticated API Responses## Vulnerability Details **File Location**: `SKILL.md:88-98` **Vulnerability Type**: Unsafe temporary-file handling **Risk Level**: Low The connectivity probe repeatedly writes authenticated API responses to a fixed path in the shared `/tmp` directory: ```bash # 1) Try direct bearer first for ep in \ '/api/v2/portfolio/performance?range=ytd' \ '/api/v1/portfolio/holdings?range=ytd' \ '/api/v1/portfolio/dividends?groupBy=month&range=ytd' do code=$(curl -s -o /tmp/gf_probe.json -w '%{http_code}' "$GHOSTFOLIO_BASE_URL$ep" \ -H "Authorization: Bearer $GHOSTFOLIO_TOKEN" \ -H 'Accept: application/json' \ -H "x-ghostfolio-timezone: $GHOSTFOLIO_TIMEZONE") echo "direct $ep -> $code" done ``` ### Technical Analysis `/tmp/gf_probe.json` is predictable and shared across invocations. The command does not securely create the file, verify its type or ownership, set restrictive permissions explicitly, or remove it afterward. On systems where applicable filesystem protections do not prevent the operation, another local user may pre-create the path or arrange a symbolic-link attack. Concurrent probes can also overwrite each other's output. Moreover, the resulting file may retain sensitive portfolio responses after the connectivity test completes. ### Attack Path 1. A local attacker predicts the fixed path `/tmp/gf_probe.json`. 2. Before the victim runs the probe, the attacker creates a conflicting path or symbolic link where platform protections permit it. 3. The victim runs the documented authenticated probe. 4. `curl` follows or overwrites the prepared destination using the victim's filesystem privileges. 5. This may overwrite another file writable by the victim, interfere with the probe, or leave sensitive API response data at a known location. 6. The fixed file remains after execution unless the user manually removes it. ### Impact Assessment The principal impact is local exposure o ...[truncated 308 chars]
Remediation
## Remediation Suggestions - Because the probe only needs the HTTP status, replace the output path with `-o /dev/null`. - If the response body must be retained, create a private temporary file with `mktemp`. - Set a restrictive process umask, such as `umask 077`, before creating files containing portfolio data. - Register a cleanup trap to delete the temporary file on normal exit, interruption, or error. - Do not reuse a predictable filename across users or concurrent invocations. - Validate that any retained temporary object is a regular file owned by the current user. - Prefer keeping diagnostic response data in memory when practical.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (3)

Tool Parameter Abuse

High
Category
Tool Misuse
Content
- Connectivity issues
  - Prefer local URL (`http://127.0.0.1:3333`) if service runs locally.
  - For remote TLS diagnostics only, temporary `curl -k` can help.

## Safety Notes
Confidence
90% confidence
Finding
Recommending curl -k disables TLS certificate validation, making HTTPS connections vulnerable to man-in-the-middle interception and spoofed servers. In this skill, that becomes more dangerous because authentication tokens are used against API endpoints, so bypassing TLS verification can directly expose credentials and portfolio data.

External Transmission

Medium
Category
Data Exfiltration
Content
### Mode B — Anonymous exchange (required in some environments)

```bash
AUTH_TOKEN=$(curl -fsS "$GHOSTFOLIO_BASE_URL/api/v1/auth/anonymous" \
  -H 'Content-Type: application/json' \
  --data "{\"accessToken\":\"$GHOSTFOLIO_TOKEN\"}" \
| jq -r '.authToken')
Confidence
92% confidence
Finding
The skill instructs sending the long-lived GHOSTFOLIO_TOKEN to an HTTP endpoint as JSON during the anonymous auth exchange. Because the documented default base URL is plain HTTP on localhost and the skill also permits remote base URLs, this can expose a sensitive bearer credential to network interception, local proxying, or SSRF-style redirection if the base URL is altered.

External Transmission

Medium
Category
Data Exfiltration
Content
'/api/v1/portfolio/holdings?range=ytd' \
  '/api/v1/portfolio/dividends?groupBy=month&range=ytd'
do
  code=$(curl -s -o /tmp/gf_probe.json -w '%{http_code}' "$GHOSTFOLIO_BASE_URL$ep" \
    -H "Authorization: Bearer $GHOSTFOLIO_TOKEN" \
    -H 'Accept: application/json' \
    -H "x-ghostfolio-timezone: $GHOSTFOLIO_TIMEZONE")
Confidence
95% confidence
Finding
The connectivity probe sends the raw GHOSTFOLIO_TOKEN as a Bearer token to multiple endpoints, which transmits the credential to whatever host is configured in GHOSTFOLIO_BASE_URL. In context, this is risky because the skill encourages configurable local or remote URLs, so a misconfigured or malicious endpoint could capture the token during troubleshooting.