Back to skill

Security audit

Hi Lite

Security checks for vulnerabilities and agentic risk

Overview

Hi-Lite is mostly a coherent local Kindle-highlight manager, but its Amazon fetch feature has under-scoped browser/session handling and an unsafe custom-domain path that users should review before installing.

Install only if you are comfortable with a skill that can read and rewrite your local Kindle-highlight library and, if you use fetch, opens a browser to Amazon and stores a reusable local login profile. Prefer explicit /hi-lite commands, avoid custom Amazon domains unless the skill is updated with an allowlist, and delete ~/.openclaw/workspace/hi-lite/.browser-data/ when you no longer want the saved session.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (2)

T08 · Insecure Dependencies

Warning
Location
SKILL.md:263
Finding
Unpinned Third-Party Package and Browser Installation<![CDATA[ ## Vulnerability Details **File Locations**: - `SKILL.md:263-269` - `README.md:70-76` **Vulnerability Type**: Unpinned third-party dependency installation **Risk Level**: Medium ### Vulnerable Code From `SKILL.md:263-269`: ```markdown ### First-Time Setup Check if Playwright is available by running `python3 -c "from playwright.sync_api import sync_playwright"`. If it fails, guide the user: ```bash pip install "playwright>=1.40.0" playwright install chromium ``` ``` The same installation instructions appear in `README.md:70-76`: ```markdown ### First-Time Setup ```bash pip install "playwright>=1.40.0" playwright install chromium ``` ``` ### Technical Analysis The package requirement uses an open-ended lower bound rather than an exact, reviewed version. Consequently, the command may install any future Playwright release accepted by the package resolver. The subsequent `playwright install chromium` command also downloads a browser artifact without a project-specified version lock or integrity digest. Python package installation can execute package build or installation logic with the invoking user's permissions. Browser binaries are also executable components. The effective code installed by these commands can therefore change after the skill itself has been audited. There is no evidence that the named Playwright package or its current browser artifact is malicious. The vulnerability is the mutable supply-chain trust model and absence of reproducible dependency verification. ### Attack Path 1. The user invokes the Amazon highlight-fetching feature. 2. The skill detects that Playwright is unavailable and presents the documented installation commands. 3. The user or agent runs `pip install "playwright>=1.40.0"`. 4. The package resolver selects a release that was not fixed or reviewed by this project. 5. `playwright install chromium` downloads an additional executable browser artifact. 6. If the package source, a future release, the user's pack ...[truncated 762 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace the open-ended requirement with an exact, reviewed version: ```bash python3 -m pip install "playwright==<audited-version>" ``` 2. Publish a lockfile or requirements file containing cryptographic hashes, and install with hash enforcement: ```bash python3 -m pip install --require-hashes -r requirements.txt ``` 3. Run installation inside a dedicated virtual environment rather than the system Python environment. 4. Document the expected package index and advise users to review custom `pip` index configuration that could enable dependency substitution. 5. Pin and document the expected Playwright-managed Chromium revision. Where supported, verify downloaded artifacts against vendor-provided checksums or signatures. 6. Periodically review and deliberately update the pinned versions rather than accepting arbitrary future releases automatically. 7. Explicitly warn users not to run the installation commands with `sudo` or another privileged account. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:272
Finding
Unvalidated Amazon Domain Used in Shell-Oriented Instructions and Browser Navigation<![CDATA[ ## Vulnerability Details **File Locations**: - `SKILL.md:272-281` - `SKILL.md:320-327` - `SKILL.md:397-414` - `SKILL.md:556-558` **Vulnerability Type**: Insufficient input validation with potential command injection and untrusted browser navigation **Risk Level**: High ### Vulnerable Code The execution instructions in `SKILL.md:272-281` direct the agent to append a user-specified domain to a Bash command: ```markdown ### Execution When the user triggers a fetch: 1. Write the following Python script to `~/.openclaw/workspace/hi-lite/raw/fetch_highlights.py`. 2. Run it via bash: `python3 ~/.openclaw/workspace/hi-lite/raw/fetch_highlights.py` (append `--amazon-domain amazon.co.uk` etc. if the user specifies a non-US domain). 3. The script opens a visible Chromium window. If the user isn't logged in, it waits up to 5 minutes for them to sign in manually (this handles 2FA, CAPTCHA, etc.). Session cookies are saved at `~/.openclaw/workspace/hi-lite/.browser-data/` so future fetches skip login. ``` The argument is accepted without validation in `SKILL.md:320-327`: ```python parser.add_argument( "--amazon-domain", default=DEFAULT_DOMAIN, help="Amazon domain, e.g. amazon.co.uk", ) parser.add_argument( "--browser-data", default=DEFAULT_BROWSER_DATA, help="Path to persistent browser profile", ) ``` It is then interpolated directly into the navigation URL in `SKILL.md:397-414`: ```python def fetch_highlights(args): domain = args.amazon_domain notebook_url = f"https://read.{domain}/notebook" output_dir = Path(args.output_dir) output_dir.mkdir(parents=True, exist_ok=True) browser_data = Path(args.browser_data) browser_data.mkdir(parents=True, exist_ok=True) with sync_playwright() as pw: context = pw.chromium.launch_persistent_context( user_data_dir=str(browser_data), headless=False, args=["--disable-blink-features=AutomationControlled"], viewport={"width": 1 ...[truncated 4134 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Define an explicit allowlist of supported Amazon domains: ```python ALLOWED_DOMAINS = { "amazon.com", "amazon.co.uk", "amazon.de", "amazon.fr", "amazon.it", "amazon.es", "amazon.ca", "amazon.com.au", "amazon.co.jp", "amazon.in", } domain = args.amazon_domain.strip().lower().rstrip(".") if domain not in ALLOWED_DOMAINS: parser.error("Unsupported Amazon domain") ``` 2. Do not accept arbitrary hostnames based only on syntax. A hostname regex alone would still permit attacker-owned domains. 3. Avoid shell-string construction. Invoke the process through an argument-array API: ```python subprocess.run( [ "python3", str(script_path), "--amazon-domain", validated_domain, ], check=True, shell=False, ) ``` 4. Update the skill instructions to explicitly prohibit `shell=True`, Bash interpolation, `eval`, and concatenation of user-controlled values into command strings. 5. Construct the URL only after allowlist validation and verify the resulting parsed hostname before navigation. 6. Consider mapping a user-facing region choice to a hardcoded domain internally, rather than accepting raw domain input. 7. Display the validated destination URL and require confirmation before opening the browser when changing regions. 8. Use a dedicated browser profile solely for this feature, apply restrictive filesystem permissions to `.browser-data`, and document how users can delete the stored session. 9. Warn users to verify the browser address before entering Amazon credentials and never to authenticate on a host outside the approved Amazon-domain list. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (10)

Intent-Code Divergence

Medium
Confidence
95% confidence
Finding
The README makes an absolute privacy claim that 'nothing is sent to any server,' but the documented auto-fetch workflow explicitly launches a browser to Amazon, transmits user data to Amazon, and stores a reusable session locally. This is a deceptive or inaccurate security/privacy representation that can mislead users into trusting the skill with credentials and personal reading data under false assumptions.

Session Persistence

Medium
Category
Rogue Agent
Content
When the user first invokes Hi-Lite or says "set up hi-lite":

1. Check if `~/.openclaw/workspace/hi-lite/` exists.
2. If not, create the directory structure:
   - `~/.openclaw/workspace/hi-lite/raw/`
   - `~/.openclaw/workspace/hi-lite/highlights/books/`
   - `~/.openclaw/workspace/hi-lite/collections/`
Confidence
60% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Session Persistence

Medium
Category
Rogue Agent
Content
2. Detect the format of each file and parse highlights from it.
3. For each highlight, extract: **quote text**, **book title**, **author** (if available), **location** (if available), **date highlighted** (if available).
4. Group highlights by book.
5. For each book, create or update a markdown file at `~/.openclaw/workspace/hi-lite/highlights/books/<slug>.md`.
6. Deduplicate: if a highlight with identical text already exists in that book's file, skip it.
7. Update `~/.openclaw/workspace/hi-lite/highlights/_index.md` with current totals.
8. Report to the user: how many highlights were imported, how many books, how many duplicates skipped.
Confidence
60% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Vague Triggers

Medium
Confidence
94% confidence
Finding
The search trigger accepts broad natural-language requests such as generic conversational queries, which can cause the skill to activate outside clearly scoped `/hi-lite` commands. That can lead to unintended access to locally stored highlights and accidental disclosure of personal reading data in response to ordinary chat prompts.

Vague Triggers

Medium
Confidence
93% confidence
Finding
Browse triggers include very generic phrases like 'show me all books' and 'list my highlights' without requiring explicit skill scope. In a multi-skill or ambient assistant environment, this increases the chance of accidental invocation and exposure of the user's local highlight library without deliberate intent.

Vague Triggers

Medium
Confidence
91% confidence
Finding
The random-quote trigger includes everyday phrases like 'surprise me' and 'give me a random quote', which are highly ambiguous and may overlap with harmless general requests. This can cause unintentional retrieval of stored reading highlights, creating a privacy leak even if the data is only local.

Session Persistence

Medium
Category
Rogue Agent
Content
## 6. Collections

**Trigger**: `/hi-lite collection <name>` or "make a collection about courage", "create a [theme] collection"

### Steps
Confidence
60% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The fetch workflow persists Amazon session cookies under a local browser profile, but the skill text does not prominently warn users about that persistent authentication state. Users may not understand that future runs can reuse their logged-in session, increasing the risk of unauthorized access by other local users or processes with workspace access.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
3. The script opens a visible Chromium window. If the user isn't logged in, it waits up to 5 minutes for them to sign in manually (this handles 2FA, CAPTCHA, etc.). Session cookies are saved at `~/.openclaw/workspace/hi-lite/.browser-data/` so future fetches skip login.
4. The script iterates through all annotated books in the sidebar, extracts highlights, and saves a JSON file to `~/.openclaw/workspace/hi-lite/raw/kindle-fetch-{timestamp}.json`.
5. After the script finishes, delete the script file (`fetch_highlights.py`) from `raw/` so it doesn't get parsed as an import.
6. Then automatically run the standard import flow (Section 2) on the fetched JSON file.

**The script to write:**
Confidence
88% confidence
Finding
The skill instructs the agent to automatically run the import flow after a fetch completes, chaining actions without a separate user confirmation. While convenient, this increases the blast radius of a single invocation and removes an opportunity for the user to inspect fetched data before it is parsed and persisted.

Session Persistence

Medium
Category
Rogue Agent
Content
### Re-Fetch

Re-fetching is safe. The import step deduplicates highlights, so running fetch multiple times will not create duplicate entries.

### Non-US Amazon Domains
Confidence
60% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Static analysis

No suspicious patterns detected.