Back to skill

Security audit

KitchenOwl API

Security checks for vulnerabilities and agentic risk

Overview

This KitchenOwl helper is mostly purpose-aligned, but it handles passwords and saved tokens unsafely enough that users should review it before installing.

Install only if you are comfortable giving the skill access to your KitchenOwl account. Prefer HTTPS URLs, avoid putting passwords or tokens directly on the command line, check permissions on ~/.config/kitchenowl-api/session.json, and treat generic request/graphql commands as capable of changing more than shopping lists.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/kitchenowl-api.sh:37
Finding
Session Tokens Stored Without Enforced Restrictive Permissions<![CDATA[ ## Vulnerability Details **File Location**: `scripts/kitchenowl-api.sh`, lines 4–7 and 37–41 **Vulnerability Type**: Insecure storage of authentication credentials **Risk Level**: High ### Vulnerable Code ```bash SESSION_DIR="${HOME}/.config/kitchenowl-api" SESSION_FILE="${SESSION_DIR}/session.json" mkdir -p "$SESSION_DIR" ``` ```bash save_session() { local base="$1" access="$2" refresh="$3" jq -n --arg base "$base" --arg access "$access" --arg refresh "$refresh" \ '{base_url:$base,access_token:$access,refresh_token:$refresh,updated_at:(now|todate)}' > "$SESSION_FILE" } ``` ### Technical Analysis The script stores access and refresh tokens in `~/.config/kitchenowl-api/session.json`, but neither the directory nor the session file is assigned an explicit restrictive permission mode. The resulting permissions depend entirely on the invoking user's `umask`. Under a permissive `umask`, the directory or file may be readable by other local accounts. Access and refresh tokens are bearer credentials: possession is generally sufficient to authenticate without knowing the user's password. Writing directly to the destination also lacks atomic replacement and does not verify that the destination is a regular file owned by the expected user. ### Attack Path 1. A user runs the `login` command. 2. The script receives access and refresh tokens from the KitchenOwl server. 3. `save_session` writes the tokens to `~/.config/kitchenowl-api/session.json`. 4. A permissive `umask` causes the file or its parent directory to be accessible to another local account. 5. The local attacker reads the JSON file and extracts the bearer or refresh token. 6. The attacker submits the stolen credential to the configured KitchenOwl instance and impersonates the victim. ### Impact Assessment A successful attacker can obtain the KitchenOwl privileges associated with the stolen token. Depending on the victim's account permissions and available API endpoints, this may allow ...[truncated 333 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Set a restrictive process mask before creating or writing credential files: ```bash umask 077 ``` - Create the session directory with an explicit mode: ```bash install -d -m 700 "$SESSION_DIR" ``` - Write the session through a securely created temporary file in the same directory, enforce mode `600`, and atomically rename it: ```bash tmp_file=$(mktemp "${SESSION_DIR}/session.json.XXXXXX") trap 'rm -f "$tmp_file"' EXIT jq -n --arg base "$base" --arg access "$access" --arg refresh "$refresh" \ '{base_url:$base,access_token:$access,refresh_token:$refresh,updated_at:(now|todate)}' \ > "$tmp_file" chmod 600 "$tmp_file" mv -f "$tmp_file" "$SESSION_FILE" trap - EXIT ``` - Before loading the session, verify that the file is a regular file, is not a symbolic link, is owned by the current user, and is not accessible by group or other users. - Where available, prefer an operating-system credential store or secret manager instead of a plaintext JSON file. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/kitchenowl-api.sh:91
Finding
Predictable Temporary File Enables Symlink-Based File Overwrite<![CDATA[ ## Vulnerability Details **File Location**: `scripts/kitchenowl-api.sh`, lines 91–92 **Vulnerability Type**: Unsafe predictable temporary file **Risk Level**: High ### Vulnerable Code ```bash for p in "${candidates[@]}"; do code=$(curl -ks -o /tmp/kowl_probe.$$ -w '%{http_code}' "${BASE_URL%/}${p}") loc=$(curl -ksI "${BASE_URL%/}${p}" | awk -F': ' 'tolower($1)=="location"{print $2}' | tr -d '\r' || true) ``` ### Technical Analysis The probe command writes each HTTP response body to `/tmp/kowl_probe.$$`, where `$$` is the process ID. Process IDs are predictable, `/tmp` is normally shared by local users, and the script does not securely create the file before passing it to `curl`. If an attacker creates that pathname as a symbolic link before `curl` opens it, `curl -o` can follow the link and truncate or replace the linked target with the HTTP response body. The pathname is reused for every probe request and is not deleted after execution. This is a time-of-check/time-of-use and unsafe temporary-file vulnerability. Its severity is greatest when a privileged account runs the script. ### Attack Path 1. A local attacker predicts or observes the process ID likely to be assigned to a victim's script process. 2. The attacker creates `/tmp/kowl_probe.<PID>` as a symbolic link to a file writable by the victim. 3. The victim runs `kitchenowl-api.sh probe`. 4. `curl -o /tmp/kowl_probe.<PID>` follows the attacker-created symbolic link. 5. The target file is truncated or overwritten with a response body from the probed server. 6. If the victim is privileged and the target is security-sensitive, the overwrite may corrupt configuration or alter behavior of another process. Successful exploitation depends on winning the timing or PID-prediction race and selecting a target writable by the account running the script. ### Impact Assessment The direct impact is arbitrary file corruption within the invoking user's write privileges. If an administrator runs t ...[truncated 403 chars]
Remediation
<![CDATA[ ## Remediation Suggestions The response body is not used, so direct it to `/dev/null` instead of creating a temporary file: ```bash code=$(curl -ks -o /dev/null -w '%{http_code}' "${BASE_URL%/}${p}") ``` If a response body must be retained: - Create the file with `mktemp` in a user-controlled directory. - Apply mode `600`. - Register a cleanup trap. - Do not reuse a predictable pathname. - Verify that any destination is a regular file and not a symbolic link. Example: ```bash tmp_file=$(mktemp "${TMPDIR:-/tmp}/kowl_probe.XXXXXX") chmod 600 "$tmp_file" trap 'rm -f "$tmp_file"' EXIT ``` ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/kitchenowl-api.sh:59
Finding
Credentials and Bearer Tokens Can Be Transmitted Over Plaintext HTTP<![CDATA[ ## Vulnerability Details **File Location**: `scripts/kitchenowl-api.sh`, lines 59–73 and 103–127 **Vulnerability Type**: Cleartext transmission of sensitive information **Risk Level**: High ### Vulnerable Code ```bash api_call() { local method="$1" path="$2" body="${3:-}" [[ -n "$BASE_URL" ]] || { echo "BASE_URL missing (set --base-url or KITCHENOWL_URL)." >&2; exit 1; } local url="${BASE_URL%/}${path}" local -a args=( -sS -X "$method" "$url" -H 'Accept: application/json' ) if [[ -n "$TOKEN" ]]; then args+=( -H "Authorization: Bearer $TOKEN" ) fi if [[ -n "$body" ]]; then args+=( -H 'Content-Type: application/json' --data "$body" ) fi curl "${args[@]}" } ``` ```bash local payload payload=$(jq -n --arg u "$username" --arg p "$password" --arg d "$device" \ '{username:$u,password:$p,device:$d}') local resp resp=$(api_call POST /api/auth "$payload") ``` ### Technical Analysis The script accepts an arbitrary base URL and concatenates it directly with the API path. It does not require an `https://` scheme before sending login credentials, bearer tokens, or request bodies. When a user supplies an `http://` endpoint, the password in the login payload and any authorization header are transmitted without transport encryption or authenticated server identity. An attacker positioned on the network path can observe the traffic. An active attacker may also modify requests and responses. Although plaintext HTTP can be useful for loopback development, accepting it silently for arbitrary hosts creates an unsafe default for credentials. ### Attack Path 1. A user, configuration file, or automation sets `KITCHENOWL_URL`, `KITCHENOWL_BASE_URL`, or `--base-url` to an `http://` URL. 2. The user runs `login`, `request`, or `graphql`. 3. The script sends the password, bearer token, or sensitive request data over plaintext HTTP. 4. A network observer captures the traffic, or an active network attacker intercepts and modifies it. 5. The ...[truncated 628 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Require HTTPS for non-loopback hosts before any credential or token is transmitted. - Reject unsupported schemes and malformed URLs. - If plaintext HTTP is needed for local development, require an explicit option such as `--allow-insecure-http` and restrict it to loopback addresses by default. - Produce a clear error before constructing or sending a sensitive request. Example validation: ```bash case "$BASE_URL" in https://*) ;; http://localhost*|http://127.0.0.1*|http://[::1]*) [[ "${ALLOW_INSECURE_HTTP:-0}" == "1" ]] || { echo "Plaintext HTTP requires explicit opt-in." >&2 exit 1 } ;; *) echo "A valid HTTPS base URL is required." >&2 exit 1 ;; esac ``` - Keep TLS certificate verification enabled. The probe command should also avoid `curl -k`, because disabling verification permits endpoint spoofing and unreliable probe results. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/kitchenowl-api.sh:103
Finding
Passwords and Access Tokens Exposed Through Command-Line Arguments<![CDATA[ ## Vulnerability Details **File Location**: `scripts/kitchenowl-api.sh`, lines 103–111, 137–150, and 159–169; `SKILL.md`, lines 29–33 **Vulnerability Type**: Sensitive information exposure through process arguments and shell history **Risk Level**: Medium ### Vulnerable Code The documented login flow places the password directly in the command line: ```bash {baseDir}/scripts/kitchenowl-api.sh login \ --base-url https://kitchenowl.example.com \ --username USERNAME \ --password 'PASSWORD' \ --device openclaw ``` The script accepts the password as an argument: ```bash cmd_login() { local username="" password="" device="openclaw" base="" while [[ $# -gt 0 ]]; do case "$1" in --base-url) base="$2"; shift 2 ;; --username) username="$2"; shift 2 ;; --password) password="$2"; shift 2 ;; --device) device="$2"; shift 2 ;; *) echo "Unknown arg: $1" >&2; exit 1 ;; esac done ``` It also accepts bearer tokens as command-line arguments: ```bash while [[ $# -gt 0 ]]; do case "$1" in --base-url) base="$2"; shift 2 ;; --token) token_override="$2"; shift 2 ;; --json) body="$2"; shift 2 ;; *) echo "Unknown arg: $1" >&2; exit 1 ;; esac done ``` ```bash while [[ $# -gt 0 ]]; do case "$1" in --query) query="$2"; shift 2 ;; --variables) variables="$2"; shift 2 ;; --base-url) base="$2"; shift 2 ;; --token) token_override="$2"; shift 2 ;; *) echo "Unknown arg: $1" >&2; exit 1 ;; esac done ``` ### Technical Analysis Command-line arguments may be exposed through shell history, operating-system process inspection, audit subsystems, job schedulers, terminal logging, monitoring agents, and CI/CD logs. Quoting a password prevents shell expansion but does not remove it from the argument vector or command history. The issue affects both account passwords supplied through `--password` and bearer credentials supplied through `--token`. Whether another local user can inspect process ...[truncated 1072 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Prompt for passwords interactively without echoing them: ```bash read -r -s -p "Password: " password printf '\n' >&2 ``` - Support reading credentials from a protected file descriptor or standard input for non-interactive use. - Prefer an operating-system secret store or a dedicated secret-manager integration. - Replace `--token TOKEN` with safer alternatives such as: - a protected token file, - a file descriptor, - a secret-manager reference, or - the existing environment-variable mechanism when its exposure characteristics are acceptable. - Warn users that environment variables can also be exposed in some execution environments. - Remove password-bearing command examples from the recommended workflow and document the interactive or file-descriptor-based method instead. - If compatibility requires retaining secret-bearing arguments, mark them as deprecated and emit a warning. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (8)

Credential Access

High
Category
Privilege Escalation
Content
Supported environment variables:

- `KITCHENOWL_URL` (e.g. `https://kitchenowl.example.com`) **[preferred]**
- `KITCHENOWL_TOKEN` (Bearer token; access token or long-lived token)
- `KITCHENOWL_REFRESH_TOKEN` (optional)
- `KITCHENOWL_BASE_URL` (legacy compatibility)
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Lp3

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding
The skill documents use of a shell script capable of authenticating to an external service and issuing authenticated read/write API requests, but it declares no tool scope or permission boundaries. That increases the chance an agent can invoke shell-based, state-changing operations without explicit guardrails or user-approval expectations.

Description-Behavior Mismatch

Medium
Confidence
96% confidence
Finding
The script exposes generic `request` and `graphql` subcommands that can invoke arbitrary API paths and GraphQL operations, which exceeds the stated skill purpose of shopping-list read/update. In an agent-skill context, this broad capability increases the blast radius if the skill is invoked with untrusted prompts or misused by another component, potentially enabling access to unrelated account data or state-changing operations.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
Access and refresh tokens are persisted in `~/.config/kitchenowl-api/session.json` without any warning, opt-in, or permission hardening. On multi-user or shared systems, this can expose long-lived credentials to other local processes or users if file permissions are too broad, and it increases the impact of host compromise.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The login command constructs a JSON payload containing the username and password and sends it via an HTTP request. While network transmission is inherent to login, the script provides no user disclosure in help text or prompts about sending credentials to the configured server, which matters because the base URL is user-supplied.

Missing User Warnings

Low
Confidence
89% confidence
Finding
The description explicitly supports modifying shopping-list items, but the skill text does not warn that operations can change remote user data. In an agent setting, missing disclosure around mutating actions makes unintended or overly broad changes more likely.

Missing User Warnings

Low
Confidence
85% confidence
Finding
The login flow stores tokens in a local session file, but the documentation does not warn users about credential persistence, file permissions, or cleanup. This can expose reusable authentication material to other local users, backups, or later unintended agent access.

Context-Inappropriate Capability

Low
Confidence
84% confidence
Finding
The `probe` functionality enumerates multiple candidate endpoints and follows redirects to discover deployment details unrelated to normal shopping-list operations. While not inherently exploit code, it provides reconnaissance capability that is unnecessary for the declared skill scope and could aid misuse against self-hosted instances.

Static analysis

No suspicious patterns detected.