Back to skill

Security audit

reMarkable Cloud

Security checks for vulnerabilities and agentic risk

Overview

This skill is mostly aligned with sending documents to reMarkable, but it needs review because it uses persistent cloud credentials, unrestricted web fetching, and an unpinned system-wide helper install.

Review before installing. Use this only with a trusted, pinned rmapi build, avoid running it with elevated privileges, treat ~/.rmapi as sensitive account access, and avoid sending private URLs or documents unless you are comfortable with them being fetched locally and uploaded to reMarkable Cloud.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/article2ebook.py:73
Finding

Unrestricted URL Fetching Enables Server-Side Request Forgery

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/article2ebook.py:307
Finding

Predictable Shared Temporary Files Permit Symlink-Based File Overwrite

Content
View full analysis
80: safe = safe[:80].rstrip() return f"{safe}.{ext}" def main(): parser = argparse.ArgumentParser(description='Convert web article to EPUB/PDF') parser.add_argument('url', help='Article URL') parser.add_argument('--format', '-f', choices=['epub', 'pdf'], default='epub', help='Output format (default: epub)') parser.add_argument('--output', '-o', help='Output file path') parser.add_argument('--title', '-t', help='Override article title') args = parser.parse_args() print(f"Fetching: {args.url}", file=sys.stderr) title, content_html, url = fetch_article(args.url) if args.title: title = args.title print(f"Title: {title}", file=sys.stderr) if args.output: output_path = args.output else: filename = sanitize_filename(title, args.format) output_path = os.path.join(tempfile.gettempdir(), filename) if args.format == 'epub': result = to_epub(title, content_html, url, output_path) else: result = to_pdf(title, content_html, url, output_path) ``` The EPUB output is then opened using a normal path-following write operation: ```python with open(output_path, 'wb') as f: f.write(epub_data) ``` ### Technical Analysis When no explicit output path is supplied, the article title is converted into a predictable filename under the system-wide temporary directory. Article titles may be controlled through the remote page or the `-- ...[truncated 1743 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
SKILL.md:12
Finding

Unpinned Upstream Source Is Built and Installed as a System-Wide Tool

Content
View full analysis
Remediation
View remediation
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
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (13)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The code matches only one narrow portion of the description: converting a web article into EPUB or PDF. The declared purpose emphasizes reMarkable-specific delivery and file management via the reMarkable Cloud, but this code contains no authentication, no cloud access, no reMarkable API calls, no device/file listing, and no upload logic. Its actual primary behavior is local document generation from a URL. That is a material description-to-behavior mismatch.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill documents capabilities that require shell execution, network access, and file writes, but it does not declare any tool scope or permission boundaries. This makes the operational surface implicit rather than explicit, increasing the chance the agent can invoke the skill in contexts where users did not clearly consent to filesystem, network, or command execution behavior.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The invocation guidance is broad enough that the skill may trigger on ordinary mentions of reMarkable or document/article handling without strong user intent. In a skill with network access, shell usage, and cloud-side effects, overbroad triggering increases the risk of unintended uploads, web fetches, or file-management actions.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The documentation omits an important privacy and security warning: article URLs are fetched from external websites and uploaded content is transmitted to reMarkable cloud services, while auth state is cached locally. Users may unknowingly expose sensitive URLs, document contents, or metadata to third parties if these transfers are not clearly disclosed.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
89% confidence
Finding

The skill notes that rmapi caches authentication tokens at ~/.rmapi, which introduces session persistence beyond a single interaction. Persistent cloud credentials on disk can be reused by later processes or users on the same system if permissions are weak, enabling unauthorized access to the user's reMarkable account and cloud files.

Content

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

{baseDir}/scripts/remarkable.sh upload --file /path/to/book.epub --dir /

text

### Create a folder

```bash
{baseDir}/scripts/remarkable.sh mkdir --path /NewFolder

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The generated XHTML sets both xml:lang and lang to "en", forcing English metadata regardless of the source article or user preference. This is a natural-language locale policy issue because the skill does not offer opt-in or explain why English is required.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The navigation document also forces xml:lang and lang to "en" for all outputs. This creates the same locale policy problem across generated EPUB components and may mislabel non-English content.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The OPF metadata sets dc:language to "en" unconditionally, which forces an English locale even for content in other languages. There is no user opt-in or documented regional constraint that would justify this fixed language declaration.

Content

No source excerpt is available for this finding.

Tainted flow: 'output_path' from requests.get (line 345, network input) → open (file write)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/article2ebook.py (reported line 260)May include surrounding context.

python
epub_data = build_epub(title, body_content, images, author='Web Article')

    with open(output_path, 'wb') as f:
        f.write(epub_data)

    return output_path

Tainted flow: 'output_path' from requests.get (line 345, network input) → open (file write)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/article2ebook.py (reported line 300)May include surrounding context.

python
epub_data = build_epub(title, body_content, images, author='Web Article')

    with open(output_path, 'wb') as f:
        f.write(epub_data)

    return output_path

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

The manifest describes sending files/articles to reMarkable and converting web articles to ebooks, but this helper script also shells out to the local cupsfilter executable to render PDFs. Spawning a subprocess is a materially broader capability than the stated cloud/file-management purpose and is not justified by the manifest text.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/article2ebook.py (reported line 298)May include surrounding context.

python
with open(tmp_html, 'w', encoding='utf-8') as f:
        f.write(clean_html)
    try:
        result = subprocess.run(['cupsfilter', tmp_html], capture_output=True, timeout=30)
        if result.returncode == 0 and result.stdout:
            with open(output_path, 'wb') as f:
                f.write(result.stdout)

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
93% confidence
Finding

The sanitizer claims to keep only safe tags, but the allowlist includes active or styling-related elements such as style, link, form, input, object, embed, video, audio, and button. In generated EPUB/HTML/PDF workflows, preserving such markup can permit external resource loading, malformed rendering behavior, or content that executes or triggers dangerous parser behavior in downstream readers and converters.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.