Back to skill

Security audit

Wiki.js CLI

Security checks for vulnerabilities and agentic risk

Overview

This Wiki.js management skill is review-worthy because it handles API tokens and destructive wiki actions but permits unsafe HTTP configuration, has thin safeguards, and ships with packaging inconsistencies.

Review this carefully before installing. Use only HTTPS Wiki.js URLs, create a least-privilege API token, protect ~/.config/wikijs.json, and avoid --force, restore, replace, bulk update, and delete commands unless you have a fresh backup and have reviewed the exact targets. Also verify the package contents because the declared CLI executable is missing from the artifact inspected here.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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)

T09 · Insecure Skill Coding Practices

Error
Location
lib/api.js:68
Finding

Bearer Token and Uploaded File Content May Be Transmitted Over Plaintext HTTP

Content
View full analysis

Vulnerability Details

File Location: lib/api.js:68-77, lib/api.js:502-510, lib/config.js:21-25, README.md:54-61, config/wikijs.example.json:1-4
Vulnerability Type: Plaintext transmission of sensitive information
Risk Level: High

Vulnerable Code

lib/api.js:68-77:

js
const config = loadConfig();
client = axios.create({
  baseURL: config.url,
  headers: {
    'Authorization': `Bearer ${config.apiToken}`,
    'Content-Type': 'application/json'
  },
  timeout: 30000
});

lib/api.js:502-510:

js
const response = await axios.post(
  `${config.url}/u`,
  form,
  {
    headers: {
      ...form.getHeaders(),
      'Authorization': `Bearer ${config.apiToken}`
    }
  }
);

lib/config.js:21-25:

js
if (!cachedConfig.url) {
  throw new Error('Missing "url" in config');
}
if (!cachedConfig.apiToken) {
  throw new Error('Missing "apiToken" in config');
}

README.md:54-61:

json
{
  "url": "http://your-wiki-server:3000",
  "apiToken": "YOUR_API_TOKEN_HERE",
  "defaultEditor": "markdown",
  "defaultLocale": "en"
}

config/wikijs.example.json:1-4:

json
{
  "url": "http://localhost:3000",
  "apiToken": "YOUR_API_TOKEN_HERE",
  "defaultEditor": "markdown"
}

Technical Analysis

The API client attaches the Wiki.js bearer token to every GraphQL request and asset-upload request. However, configuration validation only checks that url and apiToken are present. It does not parse the URL or require TLS.

The documentation also demonstrates a non-loopback HTTP URL. A user following this example may transmit the bearer token, GraphQL request data, page content, and uploaded file content without encryption. An attacker with a suitable network position could inspect or modify this traffic.

Sending an authentication token to the explicitly configured Wiki.js server is necessary for the declar ...[truncated 1499 chars]

Remediation
View remediation

Remediation Suggestions

  1. Parse the configured URL using the standard URL class before creating the client.
  2. Require https: for all non-loopback destinations.
  3. If local development requires HTTP, permit it only for strict loopback hostnames or addresses such as localhost, 127.0.0.1, and ::1.
  4. If a broader insecure-HTTP override is necessary, require an explicit option and display a prominent warning before transmitting credentials.
  5. Replace the non-loopback HTTP example in README.md with an HTTPS URL.
  6. Add tests confirming that non-loopback HTTP endpoints are rejected.
  7. Ensure authorization headers are never forwarded to a different origin during redirects.
  8. Recommend API tokens with only the permissions required by the intended commands.
  9. Document restrictive permissions for ~/.config/wikijs.json, such as mode 0600, to reduce local token exposure.

Example validation:

js
function validateServerUrl(value) {
  const parsed = new URL(value);
  const loopbackHosts = new Set(['localhost', '127.0.0.1', '::1']);

  if (parsed.protocol !== 'https:' && !loopbackHosts.has(parsed.hostname)) {
    throw new Error('Wiki.js URL must use HTTPS for non-loopback hosts');
  }

  return parsed.toString().replace(/\/$/, '');
}

T05 · Unauthorized Access and Privilege Escalation

Note
Location
lib/api.js:541
Finding

Health Query Retrieves Excessive Server Infrastructure Information

Content
View full analysis

Vulnerability Details

File Location: lib/api.js:541-558
Vulnerability Type: Excessive information access beyond the minimum required for a health check
Risk Level: Low

Vulnerable Code

js
export async function getHealth() {
  const query = `
    query {
      system {
        info {
          configFile
          currentVersion
          latestVersion
          operatingSystem
          hostname
          platform
        }
      }
    }
  `;

  const data = await graphql(query);
  return data?.system?.info;
}

Technical Analysis

The declared wikijs health command is intended to check connectivity. The implementation instead requests and returns the server hostname, operating system, platform, and configuration-file path in addition to version information.

Those infrastructure fields are not necessary to establish whether the Wiki.js API is reachable and responsive. This exceeds the minimum data access required for the declared health-check functionality. The information is returned only to the local caller; no evidence was found that it is transmitted to an unrelated third party.

Attack Path

  1. A caller obtains access to a Wiki.js API token accepted by the server.
  2. The caller invokes the health functionality.
  3. The client submits the broad system.info query.
  4. Wiki.js returns the configuration-file path, hostname, operating system, platform, and version information when permitted by server-side authorization.
  5. The caller obtains infrastructure details that can assist with environment fingerprinting and the selection of later attacks.

Impact Assessment

This issue does not directly grant additional operating-system privileges or bypass Wiki.js authorization. Its impact is limited to information exposed by the server under the supplied API token.

The returned data may nevertheless disclose:

  • Internal hostnames and naming conventions ...[truncated 347 chars]
Remediation
View remediation

Remediation Suggestions

  1. Reduce the health query to the minimum field needed to establish service availability.
  2. Do not return configFile, hostname, operatingSystem, or platform from the normal health command.
  3. If infrastructure diagnostics are operationally necessary, expose them through a separate, clearly named diagnostic command.
  4. Require an explicit user option before requesting detailed system information.
  5. Redact filesystem paths and hostnames by default in terminal and machine-readable output.
  6. Ensure the corresponding Wiki.js token has only the minimum GraphQL permissions required for routine health checks.
  7. Add tests asserting that the default health query does not request sensitive infrastructure fields.

A minimal query could resemble:

js
export async function getHealth() {
  const query = `
    query {
      system {
        info {
          currentVersion
        }
      }
    }
  `;

  const data = await graphql(query);
  return {
    healthy: Boolean(data?.system?.info),
    currentVersion: data?.system?.info?.currentVersion
  };
}
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
Findings (36)

Missing User Warnings

High
Category
Not specified by scanner
Confidence
95% confidence
Finding

This function issues a destructive delete mutation for a page and returns success, but there is no confirmation prompt, warning log, or explanatory comment indicating that the operation irreversibly removes user content. For a code file, destructive operations that affect user data should include some form of disclosure unless clearly guarded elsewhere.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
95% confidence
Finding

This function deletes a remote asset through a GraphQL mutation but provides no confirmation prompt, warning, or explanatory notice about the destructive action. Because asset deletion can remove user data irreversibly, the lack of disclosure is a safety concern under the code-file criteria.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: axios==1.13.4 — 16 advisory(ies): CVE-2026-44494 (axios Vulnerable to Full Man-in-the-Middle via Prototype Pollution Gadget in `co); CVE-2026-44495 (axios Vulnerable to Credential Theft and Response Hijacking via Prototype Pollut); CVE-2025-62718 (Axios has a NO_PROXY Hostname Normalization Bypass that Leads to SSRF) +13 more

High
Category
Supply Chain
Confidence
93% confidence
Finding

axios is a direct runtime dependency of this CLI, and the advisory set includes SSRF, credential leakage, redirect handling, and prototype-pollution-related network security issues. Because a CLI like this likely makes outbound HTTP requests to Wiki.js endpoints, network-layer dependency flaws are plausibly reachable and materially increase risk when interacting with attacker-influenced URLs, proxies, or redirects.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: brace-expansion==1.1.12 — 4 advisory(ies): CVE-2026-13149 (brace-expansion: DoS via exponential-time expansion of consecutive non-expanding); CVE-2026-33750 (brace-expansion: Zero-step sequence causes process hang and memory exhaustion); CVE-2026-14257 (brace-expansion: DoS via unbounded expansion length causing an out-of-memory pro) +1 more

High
Category
Supply Chain
Confidence
80% confidence
Finding

Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: browserslist==4.28.1 — 2 advisory(ies): CVE-2026-73088 (Browserslist: Uncaught crash / prototype write via untrusted browserslist-stats.); CVE-2026-73089 (Browserslist: Unbounded memory growth (no cache eviction) via distinct query res)

High
Category
Supply Chain
Confidence
80% confidence
Finding

Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: fast-uri==3.1.0 — 7 advisory(ies): CVE-2026-13676 (fast-uri vulnerable to host confusion via failed IDN canonicalization); CVE-2026-18446 (fast-uri vulnerable to host confusion via backslash authority introducer); CVE-2026-75975 (fast-uri vulnerable to server-side request forgery via malformed IPv6 normalizat) +4 more

High
Category
Supply Chain
Confidence
80% confidence
Finding

Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: form-data==4.0.5 — 1 advisory(ies): CVE-2026-12143 (form-data: CRLF injection in form-data via unescaped multipart field names and f)

High
Category
Supply Chain
Confidence
88% confidence
Finding

form-data is a direct runtime dependency and a CRLF injection in multipart field names/filenames can enable malformed request construction, header injection, or request smuggling-like effects against downstream services. In a CLI that may upload files or submit forms to Wiki.js, attacker-controlled filenames or field names could make this reachable.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: js-yaml==3.14.2 — 4 advisory(ies): CVE-2026-84375 (js-yaml: maxTotalMergeKeys does not limit CPU use for empty merge sources); CVE-2026-59869 (js-yaml: YAML merge-key chains can force quadratic CPU consumption); GHSA-5p4m-2wfm-xmqj (JS-YAML: Quadratic CPU consumption in !!omap resolution (3.x and 4.x) — CVE-2026) +1 more

High
Category
Supply Chain
Confidence
80% confidence
Finding

Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: minimatch==3.1.2 — 3 advisory(ies): CVE-2026-27904 (minimatch ReDoS: nested *() extglobs generate catastrophically backtracking regu); CVE-2026-26996 (minimatch has a ReDoS via repeated wildcards with non-matching literal in patter); CVE-2026-27903 (minimatch has ReDoS: matchOne() combinatorial backtracking via multiple non-adja)

High
Category
Supply Chain
Confidence
80% confidence
Finding

Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
81% confidence
Finding

This markdown file documents an interactive shell command and a watch mode, and elsewhere lists commands such as replace, restore-backup, bulk-update, revert, and delete, but provides no warning about possible effects on user data, system state, or long-running behavior. Under the markdown-file criteria, descriptions should warn when skill behaviors could affect user data, privacy, or system integrity.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
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.

Content

Scanner excerpt · README.md (reported line 22)May include surrounding context.

md
- **Link checker** - Find broken internal links
- **Orphan detection** - Find pages with no incoming links
- **Duplicate detection** - Find similar content across pages
- **Templates** - Create pages from reusable templates
- **Shell completion** - Auto-completion for bash/zsh/fish
- **Interactive shell** - REPL mode for multiple commands
- **Markdown linting** - Validate and fix markdown issues

Session Persistence

Medium
Category
Rogue Agent
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.

Content

Scanner excerpt · README.md (reported line 103)May include surrounding context.

md
wikijs create "/docs/guide" "User Guide" --file ./guide.md --tag "docs,guide"

# Create from stdin
cat document.md | wikijs create "/docs/readme" "README" --stdin

# Update a page
wikijs update 1 --content "New content here"

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
85% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

Scanner excerpt · README.md (reported line 115)May include surrounding context.

Delete a page (with confirmation)

wikijs delete 1 wikijs delete 1 --force # Skip confirmation

text

### Tag Management

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
85% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

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

Delete a page (with confirmation)

wikijs delete 1 wikijs delete 1 --force # Skip confirmation

text

### Tag Management

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

This markdown file describes backup restore operations, including overwrite behavior via --force, but does not provide a general user warning that these commands can replace existing wiki content or otherwise affect user data. Similar examples elsewhere in the README cover bulk updates, uploads, exports, and asset deletion, yet the documentation largely presents them as routine usage rather than highlighting data-loss or integrity risks.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The documented restore-backup <file> operation is inherently high impact because it can overwrite existing wiki content, but the skill provides no warning, safety notes, or clear expectation of destructive behavior. In an agent context, terse docs increase the chance that automated or semi-automated use invokes restore in production without backups, confirmation, or environment scoping.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

A bulk search-and-replace across pages can rapidly modify large amounts of content, yet the docs present wikijs replace "old" "new" without a warning about scope, irreversible mistakes, or mandatory preview. This is especially risky for agent-driven use because a broad or malformed pattern could corrupt many pages at once.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

uploadAsset reads an arbitrary local file path and transmits the file contents to a remote server, but the code provides no path restrictions, size limits, destination validation, or caller-facing safety controls. In an agent skill context, this materially increases the risk of unintended local file exfiltration if upstream inputs can influence filePath or if users are not explicitly informed that local files will be uploaded.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

With no manifest available, the surrounding module appears to be a Wiki.js content/pages/assets API wrapper, but this function additionally retrieves host-level system details such as configFile, operatingSystem, hostname, and platform. That capability is broader and more sensitive than ordinary page or asset management and is not justified by the rest of the module's apparent purpose.

Content

No source excerpt is available for this finding.

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
60% confidence
Finding

Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Content

Scanner excerpt · lib/helpers.js (reported line 19)May include surrounding context.

js
}

export function setDebug(enabled) {
  debugMode = enabled;
  if (enabled) verboseMode = true;
}

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

This code persists offline data to a cache file in the user's home directory using writeFileSync, but the operation has no unconditional user-facing notice, confirmation, comment, or docstring explaining that user content will be stored locally. The existing debug message only appears in debug mode, so normal users may not realize their data is being written to disk.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
74% confidence
Finding

The entry "Updated documentation to English" indicates a language choice imposed in project documentation, but does not mention any user opt-in or region-specific justification. The policy requires flagging language or locale constraints when they force a specific language without user choice.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

The manifest sets defaultLocale to en, which is a natural-language locale choice applied by default. In this file there is no indication that users can opt into another language or that the English default is required for a documented region-specific purpose.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The code hardcodes toLocaleString('fr-FR', ...), which enforces a specific language/locale for all users. This is a natural-language policy concern because it removes locale choice and may conflict with organizational expectations for user-selected or environment-based localization.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: @babel/core==7.29.0 — 1 advisory(ies): CVE-2026-49356 (@babel/core: Arbitrary File Read via sourceMappingURL Comment)

Low
Category
Supply Chain
Confidence
60% confidence
Finding

Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.