Back to skill

Security audit

Readwise & Reader API

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its Readwise purpose, but it has unsafe command argument handling and immediate delete actions that deserve review before installation.

Review carefully before installing. Use a revocable Readwise token, avoid letting untrusted page text or prompts choose command arguments, and require explicit confirmation before any delete action. The publisher should add strict numeric validation for --limit and confirmation or dry-run safeguards for destructive commands.

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/readwise.sh:158
Finding

Command Injection Through the Unvalidated list --limit Argument

Content
View full analysis
100 ? 100 : remaining)) local params="limit=${page_size}" # ... local count count=$(echo "$all_results" | jq 'length') remaining=$((limit - count)) done ``` ### Technical Analysis The `cmd_list` function accepts an arbitrary string through `--limit` and stores it in `limit`. The same value is copied into `remaining`, after which both variables are evaluated as Bash arithmetic expressions. Bash arithmetic evaluation is not equivalent to strict integer parsing. Variable contents can be recursively interpreted as arithmetic syntax. In particular, malicious expressions involving array subscripts can trigger command substitutions while Bash resolves the expression. Consequently, quoting the original command-line argument does not make its later use in `$((...))` safe. This vulnerability is reachable before the value is established to be a decimal integer. It therefore creates a local command-execution primitive when an attacker can influence arguments passed to the Skill. ### Attack Path 1. An attacker causes the agent or user to invoke `readwise.sh list` with a crafted `--limit` value instead of an integer. 2. Argument parsing stores the complete attacker-controlled expression in `limit`. 3. The value is copied to `remaining`. 4. Pagination evaluates `remaining` in `local page_size=$((...))`, and later evaluates `limit` in `remaining=$((limit - count))`. 5. Bash interprets the supplied content as arithmetic syntax. A crafted expression using arithmetic array-index evaluation can cause an embedded command substitution to run. 6. The ...[truncated 719 chars]
Remediation
View remediation
0 )) || die "--limit must be greater than zero" ``` Additional hardening should include: 1. Enforce a reasonable maximum value to prevent excessive API calls or memory consumption. 2. Convert the validated value once and use only the normalized integer afterward. 3. Apply the same validation consistently to every numeric command-line option. 4. Add regression tests covering empty, negative, hexadecimal-like, arithmetic-expression, array-subscript, and excessively large values. 5. Reject missing option values explicitly before reading `$2`, producing a controlled validation error. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/readwise.sh:272
Finding

Command Injection Through the Unvalidated highlights --limit Argument

Content
View full analysis
= limit )); then break fi ``` ### Technical Analysis The `cmd_highlights` function does not verify that `--limit` contains only decimal digits. It later uses `limit` as an operand in the arithmetic command `(( count >= limit ))`. During Bash arithmetic processing, variable contents may be recursively interpreted as arithmetic expressions rather than being converted using strict integer parsing. Crafted arithmetic content, including array-subscript expressions capable of triggering command substitutions, can therefore execute shell commands when the pagination condition is evaluated. The sink is normally reached after the first successful Readwise export response. Thus, exploitation requires the command to proceed far enough to evaluate the pagination condition, but it does not require control over the remote API response. ### Attack Path 1. An attacker influences an invocation of `readwise.sh highlights` and supplies a crafted expression as `--limit`. 2. The parser stores the expression in `limit` without validating its type or range. 3. The script makes the initial authenticated highlights export request. 4. After processing the response, the script evaluates `(( count >= limit ))`. 5. Bash recursively evaluates the malicious arithmetic content. 6. An embedded command substitution reached through arithmetic expression processing executes locally with the Skill process’s privileges. ### Impact Assessment Successful exploitation can execute arbitrary commands as the user running the Skill. The resulting scope includes: ...[truncated 446 chars]
Remediation
View remediation
0 )) || die "--limit must be greater than zero" ``` Also: 1. Define an upper bound appropriate for highlight exports. 2. Never place unvalidated external strings in `((...))` or `$((...))`. 3. Add tests proving that arithmetic expressions and array-subscript syntax are rejected. 4. Check that `$2` exists before consuming the value of `--limit`. 5. Consider a shared integer-validation helper so all commands enforce identical rules. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/readwise.sh:382
Finding

Command Injection Through the Unvalidated books --limit Argument

Content
View full analysis
1000 ? 1000 : remaining)) local params="page_size=${page_size}&page=${page}" # ... local count count=$(echo "$all_books" | jq 'length') remaining=$((limit - count)) done ``` ### Technical Analysis The `cmd_books` function trusts the `--limit` argument to be numeric but does not enforce that assumption. Both `remaining` and `limit` are evaluated in Bash arithmetic expansions. Bash recursively resolves variable values in arithmetic contexts. A crafted value can consequently be interpreted as an arithmetic expression, and array-subscript processing within such an expression can expose command-substitution behavior. This permits command execution rather than merely causing a malformed-number error. The first arithmetic sink occurs while calculating `page_size`, before the Books API request is sent, making this command path directly reachable once dependency and token checks have completed. ### Attack Path 1. An attacker induces an invocation of `readwise.sh books` containing a crafted `--limit` argument. 2. The script stores the argument in `limit` and copies it into `remaining`. 3. The first pagination iteration evaluates `remaining` in `$((remaining > 1000 ? 1000 : remaining))`. 4. Bash parses the attacker-controlled value as arithmetic code. 5. Crafted array-index arithmetic can cause an embedded command substitution to execute. 6. The injected process inherits the privileges and environment of the Skill. ### Impact Assessment An attacker who exploits this issue obtains arbitrary command execution as the invoking account. Potential consequenc ...[truncated 517 chars]
Remediation
View remediation
0 )) || die "--limit must be greater than zero" ``` Complete hardening should also: 1. Impose a safe maximum to limit pagination, memory use, and API traffic. 2. Reject negative numbers, signs, whitespace, arithmetic operators, variable names, and array syntax. 3. Verify that `--limit` has a following argument before accessing `$2`. 4. Centralize numeric parsing in a reusable validation function. 5. Add automated tests for malicious arithmetic input and boundary values. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (10)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 17)May include surrounding context.

md
scripts/readwise.sh [--pretty] <command> [args...]

Tool Parameter Abuse

High
Category
Tool Misuse
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).

Content

Scanner excerpt · references/api.md (reported line 70)May include surrounding context.

md
Body fields (all optional): `title, author, summary, published_date, image_url, seen, location, category, tags, notes`

### DELETE /delete/{document_id}/ — Delete Document

Returns 204.

Tool Parameter Abuse

High
Category
Tool Misuse
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).

Content

Scanner excerpt · references/api.md (reported line 134)May include surrounding context.

md
Body: `{text?, note?, location?, url?, color?}` — color: yellow, blue, pink, orange, green, purple

### DELETE /highlights/{id}/ — Delete Highlight

### Highlight Tags

Tool Parameter Abuse

High
Category
Tool Misuse
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).

Content

Scanner excerpt · references/api.md (reported line 140)May include surrounding context.

md
- `GET /highlights/{id}/tags/` — list tags
- `POST /highlights/{id}/tags/` — add tag `{name: "tag"}`
- `DELETE /highlights/{id}/tags/{tag_id}` — remove tag

### GET /books/ — List Books

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill documents use of a shell-based CLI but does not declare any tool scope or allowed-tools boundary, leaving execution capabilities implicit. This increases the chance an agent can invoke shell access more broadly than intended and makes review, sandboxing, and policy enforcement weaker.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The trigger description is very broad (e.g. 'interact with Readwise/Reader in any way'), which can cause the agent to select this skill for loosely related requests. In a shell-capable skill, over-selection raises the risk of unintended API actions, data exposure, or execution of operations the user did not specifically request.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The documentation exposes a document deletion command without any warning, confirmation requirement, or recovery guidance. In this context, Reader documents are user data; accidental or prompt-induced invocation could permanently remove saved items and cause data loss.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill similarly documents highlight deletion with no warning or confirmation guidance. Because highlights and notes may represent curated user knowledge, unintended deletion can destroy meaningful personal data and is more dangerous in a productivity knowledge-management skill.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The document delete command performs an irreversible API DELETE immediately on the provided ID and then reports success, with no confirmation prompt, dry-run mode, or explicit safeguard. In an agent setting, this increases the risk that a mistaken parse, prompt injection, ambiguous user request, or wrong ID selection causes unintended permanent data loss in the user's Readwise Reader account.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The highlight deletion path sends a DELETE request as soon as an ID is supplied, without any validation or confirmation of the target highlight. Because this skill is meant to be used by an automated agent managing personal reading data, a misinterpreted instruction or maliciously induced action could silently remove highlights the user did not intend to delete.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.