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. ]]>
