Back to skill

Security audit

paperless-ngx-tools

Security checks for vulnerabilities and agentic risk

Overview

This Paperless-ngx skill mostly does what it claims, but it handles sensitive document data and credentials in ways users should review before installing.

Install only if you trust the Paperless server and token scope. Configure PAPERLESS_URL with HTTPS whenever the server is not strictly local, use a low-privilege Paperless token, avoid --full for sensitive OCR content unless needed, specify safe download output paths, and review advanced DELETE/bulk-edit operations before allowing an agent to run them.

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

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:14
Finding

API Token and Sensitive Document Data Can Be Transmitted over Plaintext HTTP

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:14-22; credential transmission sinks also occur in scripts/types.mjs:33-43, scripts/tags.mjs:34-45, scripts/correspondents.mjs:33-44, and scripts/upload.mjs:126-130
Vulnerability Type: Cleartext transmission of credentials and sensitive data
Risk Level: High

The documented configuration explicitly permits an http:// Paperless endpoint:

markdown
Set environment variables in `~/.clawdbot/clawdbot.json`:

```json
{
  "env": {
    "PAPERLESS_URL": "http://your-paperless-host:8000",
    "PAPERLESS_TOKEN": "your-api-token"
  }
}
text

The scripts accept this URL without validating its protocol and send the API token in an HTTP authorization header. For example:

```javascript
const baseUrl = PAPERLESS_URL.replace(/\/$/, '');

async function run() {
  if (values.create) {
    const res = await fetch(`${baseUrl}/api/document_types/`, {
      method: 'POST',
      headers: {
        'Authorization': `Token ${PAPERLESS_TOKEN}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({ name: values.create })
    });

The upload operation additionally sends the selected document and its metadata over the same unvalidated transport:

javascript
const res = await fetch(`${baseUrl}/api/documents/post_document/`, {
  method: 'POST',
  headers: { 'Authorization': `Token ${PAPERLESS_TOKEN}` },
  body: formData
});

Technical Analysis

Bearer-style API tokens must only be transmitted through an authenticated, encrypted channel. When PAPERLESS_URL uses HTTP, the Authorization: Token ... header, request paths, query text, tag names, correspondent names, document titles, and uploaded document bytes are exposed to any party capable of observing or modifying traffic.

This behavior is functionally necessary insofar as the Skill must authenticate to the user-configured Paperless-ngx API. It does not, however, follow least exposure because it neither requires HTTPS ...[truncated 2014 chars]

Remediation
View remediation

Remediation Suggestions

  1. Require PAPERLESS_URL to use HTTPS by parsing it with the standard URL class and rejecting http::
    javascript
    const parsedUrl = new URL(PAPERLESS_URL);
    if (parsedUrl.protocol !== 'https:') {
      throw new Error('PAPERLESS_URL must use HTTPS');
    }
    
  2. If local plaintext access is an essential compatibility requirement, permit it only through an explicit opt-in such as PAPERLESS_ALLOW_INSECURE_HTTP=true, and restrict it to loopback addresses by default.
  3. Replace all documented http:// examples with https://.
  4. Display a prominent warning that API tokens and documents are exposed when plaintext HTTP is enabled.
  5. Centralize authenticated request handling so every script applies the same protocol and destination validation.
  6. Configure Paperless-ngx behind TLS with certificate verification enabled. Do not disable Node.js TLS verification.
  7. Rotate any token that may already have traversed an untrusted plaintext network.
  8. Use a dedicated Paperless account and token with only the document permissions required for these operations.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/download.mjs:49
Finding

Server-Controlled Filename Allows Local Path Traversal and File Overwrite

Content
View full analysis

Vulnerability Details

File Location: scripts/download.mjs:49-62
Vulnerability Type: Path traversal and arbitrary local file overwrite
Risk Level: Medium

The download script obtains a filename from remote document metadata and uses it directly in a local output path:

javascript
// Determine which file to download
const endpoint = values.original ? 'original' : 'download';
const filename = values.original ? meta.original_file_name : (meta.archived_file_name || meta.original_file_name);

// Download the file
const res = await fetch(`${baseUrl}/api/documents/${docId}/${endpoint}/`, { headers });
if (!res.ok) throw new Error(`HTTP ${res.status}: ${res.statusText}`);

const buffer = Buffer.from(await res.arrayBuffer());

// Determine output path
const outputPath = values.output || join(process.cwd(), filename);

await writeFile(outputPath, buffer);

Technical Analysis

meta.original_file_name and meta.archived_file_name cross a remote trust boundary. The client assumes that these values are safe leaf filenames, but it performs no basename normalization, traversal rejection, or containment check before passing the resulting path to writeFile.

A filename containing path components such as ../../target can escape the current working directory after normalization by join. The downloaded response body is then written to the resulting path. Because writeFile replaces existing file contents by default, this can overwrite files writable by the process.

Exploitation depends on an attacker being able to influence the filename returned by the configured Paperless server. This could occur through a compromised or malicious server, a server-side filename-validation weakness, or attacker-controlled document metadata. The risk remains client-side because this script treats remote metadata as a trusted local path.

The explicit --output option is user-directed functionality and is not itself the vulnerability. The vulnerable case is the ...[truncated 1725 chars]

Remediation
View remediation

Remediation Suggestions

  1. Treat remote filename fields as untrusted and reduce them to a leaf filename:
    javascript
    import { basename, resolve, sep } from 'node:path';
    
    const safeFilename = basename(filename);
    if (!safeFilename || safeFilename === '.' || safeFilename === '..') {
      throw new Error('Invalid filename returned by server');
    }
    
  2. Reject filenames whose sanitized value differs from the supplied value, rather than silently accepting traversal attempts.
  3. Resolve the final path and verify that it remains inside the intended directory:
    javascript
    const downloadDir = resolve(process.cwd());
    const outputPath = resolve(downloadDir, safeFilename);
    
    if (!outputPath.startsWith(downloadDir + sep)) {
      throw new Error('Download path escapes the destination directory');
    }
    
  4. Consider requiring an explicit --output path or writing downloads to a dedicated, preconfigured directory.
  5. Avoid overwriting existing files by default. Use exclusive creation, such as the wx flag, and require explicit confirmation or an --overwrite option.
  6. Apply filename length limits and reject NUL characters, separators, control characters, and platform-specific reserved names.
  7. Run the Skill as an unprivileged account with write access limited to the intended download directory.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Output HandlingUnvalidated Output Injection, Cross-Context Output, Unbounded Output
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (8)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill requires sensitive environment variables and performs networked document operations, but the manifest does not declare an explicit tool scope such as permissions or allowed-tools. That makes the skill's capabilities less transparent to the agent/runtime and to users reviewing it, increasing the risk of overbroad execution against a document management system containing sensitive data.

Content

No source excerpt is available for this finding.

Unbounded Output

Medium
Category
Output Handling
Confidence
84% confidence
Finding

The documented --full option disables truncation for OCR text output, which can cause very large document contents to be emitted in full. In this skill's context, that can leak entire sensitive document bodies into agent transcripts/logs, overwhelm downstream consumers, or trigger denial-of-service-like behavior from excessively large outputs.

Content

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

Include OCR text content

node {baseDir}/scripts/get.mjs 28 --content

Full content (no truncation)

node {baseDir}/scripts/get.mjs 28 --content --full

text

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The documentation instructs users to upload local files and download documents to local paths, but it does not clearly warn that these actions transfer potentially sensitive documents to a remote service and may write files onto the local filesystem. In a document-management context, this can expose confidential records or create unintended local persistence if an agent executes the workflow without explicit user awareness.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

This markdown file documents upload, update, and especially delete operations on documents, but it does not include any warning that these actions may modify or permanently remove user data. Under the markdown-file criteria for missing user warnings, destructive or data-affecting behaviors should be disclosed to users.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The reference includes create, update, and delete endpoints for tags and document types, but it does not warn users that these operations can alter categorization metadata or remove objects. In markdown documentation, potentially destructive or integrity-affecting behaviors should be accompanied by user-facing warnings.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
80% confidence
Finding

The file documents modifying correspondents and testing mail account connections, but it does not disclose that these actions can change stored metadata or initiate network interactions with external mail systems. For markdown files, behaviors affecting privacy or system integrity should be clearly warned about.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

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

Update document metadata

bash
curl -X PATCH \
  -H "Authorization: Token $PAPERLESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"title": "New Title", "correspondent": 5, "tags": [1, 2]}' \

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The manifest description limits the skill to document-centric operations: search, upload, tag, and retrieve. This script lists and creates Paperless-ngx document types via /api/document_types/, which is administrative metadata management not described in the manifest.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.