Skip to content

DokuWiki Plugin Security — XSS Prevention, CSRF Protection, and Secure Coding

DodaTech Updated 2026-06-28 7 min read

In this tutorial, you'll learn how to write secure DokuWiki plugins, covering XSS (Cross-Site Scripting) prevention, CSRF (Cross-Site Request Forgery) protection, input validation, output escaping, permission checks, and secure coding best practices.

What You'll Learn

  • Common security vulnerabilities in plugins
  • XSS prevention: escaping output
  • CSRF protection: using security tokens
  • Input validation for plugin parameters
  • Permission checks in plugins
  • Secure data storage
  • DokuWiki's built-in security functions

Why It Matters

A vulnerable plugin can compromise your entire wiki. XSS attacks can steal session cookies, redirect users to malicious sites, or deface pages. CSRF attacks can make admin users perform actions without their knowledge. Because DokuWiki plugins run with full wiki permissions, a single insecure plugin creates a security hole. Understanding plugin security is essential for anyone writing or maintaining plugins.

Real-World Use

A developer writes a custom plugin that fetches data from an external API and displays it on wiki pages. Without proper output escaping, an attacker who controls the API response could inject JavaScript into the wiki page, stealing session cookies from all users who view that page. Following Secure Coding Practices prevents this.

Learning Path

flowchart LR
  A[Plugin Configuration] --> B[Plugin Security]
  B --> C[Template Anatomy]
  C --> D[Template Variables]
  D --> E[Bootstrap Template]
  E --> F[Custom Template]

XSS Prevention

XSS (Cross-Site Scripting) occurs when user-controlled data is rendered without escaping, allowing attackers to inject JavaScript.

Using hsc() for Output Escaping

DokuWiki provides the hsc() (HTML Special Characters) function:

<?php
// Unsafe (vulnerable to XSS)
$renderer->doc .= $userInput;

// Safe (escaped)
$renderer->doc .= hsc($userInput);

When to Escape

Always escape when outputting:

  • User input (form data, URL parameters)
  • Data from external sources (APIs, databases)
  • Plugin configuration values
  • File names and paths

Context-Specific Escaping

Different contexts need different escaping:

<?php
// HTML attribute context
$renderer->doc .= '<img alt="' . hsc($altText) . '" src="' . hsc($imageUrl) . '">';

// URL context
$renderer->doc .= '<a href="' . hsc($url) . '">' . hsc($linkText) . '</a>';

// JavaScript context (avoid if possible)
$renderer->doc .= '<script>var name = "' . hsc(addslashes($name)) . '";</script>';

Avoid Raw HTML in Syntax Plugins

Instead of generating raw HTML, use DokuWiki's renderer methods:

<?php
// Unsafe: raw HTML
$renderer->doc .= '<div class="my-class">' . $content . '</div>';

// Safer: use DokuWiki rendering
$renderer->divstart('my-class');
$renderer->cdata($content);
$renderer->divend();

CSRF Protection

CSRF (Cross-Site Request Forgery) tricks authenticated users into performing actions they did not intend.

Using Security Tokens

DokuWiki provides a CSRF token system. Always include tokens in forms:

<?php
// Generate form with CSRF token
$token = getSecurityToken();
echo '<form method="post">';
echo '<input type="hidden" name="sectok" value="' . $token . '">';
echo '<input type="submit" value="Delete Page">';
echo '</form>';

Validating Tokens

Check the token when processing form submissions:

<?php
// Validate CSRF token
if (!checkSecurityToken()) {
    // Invalid token - reject request
    http_response_code(403);
    echo 'Security token validation failed.';
    exit;
}

AJAX CSRF Protection

For AJAX requests, include the token in the request header:

// Using jQuery with DokuWiki
$.ajax({
    url: '/wiki/lib/exe/ajax.php',
    data: {
        call: 'myplugin_function',
        sectok: DOKU.sectok
    }
});

Input Validation

Always validate input from users and external sources.

Validate URL Parameters

<?php
// Validate page ID parameter
$pageId = $_REQUEST['id'];
if (!page_exists($pageId) && !auth_quickaclcheck($pageId)) {
    // Invalid or unauthorized page
    return;
}

Validate Numeric Input

<?php
// Unsafe
$count = $_REQUEST['count'];

// Safe
$count = (int) $_REQUEST['count'];
if ($count < 1 || $count > 100) {
    $count = 10; // Default value
}

Validate File Uploads

<?php
// Check file type
$allowedTypes = array('jpg', 'png', 'gif', 'pdf');
$extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
if (!in_array($extension, $allowedTypes)) {
    throw new Exception('File type not allowed.');
}

// Check file size
if ($_FILES['file']['size'] > 5000000) {
    throw new Exception('File too large.');
}

Permission Checks

Plugins must check that the user has permission to perform actions.

Check ACL Permissions

<?php
// Check if user can read a page
if (auth_quickaclcheck($pageId) < AUTH_READ) {
    http_response_code(403);
    echo 'Access denied.';
    return;
}

// Check if user can edit a page
if (auth_quickaclcheck($pageId) < AUTH_EDIT) {
    http_response_code(403);
    echo 'You do not have permission to edit this page.';
    return;
}

Check Admin Status

<?php
// Check if user is admin
if (!auth_isadmin()) {
    http_response_code(403);
    echo 'Admin access required.';
    return;
}

Action Plugin Permission Checks

For action plugins that modify data:

<?php
public function handle_page_save($event, $param) {
    global $INPUT;
    $pageId = $event->data['id'];

    // Check that the user has edit permission
    if ($INPUT->server->str('REMOTE_USER') && auth_quickaclcheck($pageId) >= AUTH_EDIT) {
        // Proceed with the action
    } else {
        // Log unauthorized attempt
        msg('You do not have permission to edit this page.', -1);
        $event->preventDefault();
    }
}

Secure Data Storage

File Permissions

If your plugin writes files, ensure proper permissions:

<?php
// Set restrictive permissions for plugin data
$dataDir = DOKU_INC . 'data/plugin-data/myplugin/';
if (!is_dir($dataDir)) {
    mkdir($dataDir, 0755, true);
}

$file = $dataDir . 'data.txt';
file_put_contents($file, $data);
chmod($file, 0644);

Avoid Storing Secrets in Plugin Files

Do not hard-code API keys or passwords in plugin files. Use configuration settings:

<?php
// In plugin's conf/default.php
$conf['api_key'] = '';

// In conf/local.php
$conf['plugin']['myplugin']['api_key'] = 'your-actual-key';

// In plugin code
$apiKey = $this->getConf('api_key');

SQL Injection Protection

If your plugin interacts with a database (uncommon in DokuWiki), use parameterized queries:

<?php
// Unsafe: string concatenation
$result = $db->query("SELECT * FROM users WHERE name = '" . $name . "'");

// Safe: parameterized query (if using PDO)
$stmt = $db->prepare("SELECT * FROM users WHERE name = ?");
$stmt->execute(array($name));

DokuWiki Security Functions Reference

Function Purpose
hsc($string) Escape HTML special characters
getSecurityToken() Generate CSRF token
checkSecurityToken() Validate CSRF token
auth_quickaclcheck($id) Check ACL permissions
auth_isadmin() Check if current user is admin
cleanID($id) Sanitize page ID
media_savefile() Secure file upload handling
mail_send() Secure email sending

Common Mistakes

  1. Not escaping plugin output: The most common plugin vulnerability. Every piece of user-controlled data that appears in output must be escaped with hsc().
  2. Not checking permissions: A plugin that performs admin actions without checking admin status can be exploited by regular users.
  3. Not validating CSRF tokens: Forms in admin plugins must include and validate security tokens.
  4. Storing sensitive data in readable files: Plugin configuration files should not contain plain-text passwords or API keys.
  5. Trusting external data sources: Data from APIs, databases, or file uploads may be malicious. Validate and escape everything.

Practice Questions

  1. What is the hsc() function in DokuWiki, and when should it be used in plugin development?
  2. How does DokuWiki's CSRF protection system work, and what functions are involved?
  3. What permission checks should an admin plugin perform before executing sensitive operations?
  4. Challenge: Review the plugin you wrote in Lesson 22 (or any existing plugin) for security vulnerabilities. Check for: unescaped output, missing CSRF protection, missing permission checks, unchecked input validation, and insecure data storage. Write a security audit report that includes each vulnerability found, its severity, and the code changes needed to fix it. Implement the fixes.

FAQ

What is the difference between XSS and CSRF?

XSS (Cross-Site Scripting) injects malicious scripts into pages viewed by other users. CSRF (Cross-Site Request Forgery) tricks authenticated users into performing unintended actions. XSS attacks the user's browser; CSRF attacks the user's authenticated session.

Does DokuWiki automatically escape plugin output?

No. DokuWiki escapes core output but cannot automatically escape plugin output because it does not know what the plugin intends to output. Plugin authors must use hsc() or the renderer methods for safe output.

Can a plugin access the DokuWiki database?

DokuWiki does not use a database, so traditional SQL injection does not apply. However, plugins that use external databases should use parameterized queries to prevent SQL injection.

How do I report a security vulnerability in a DokuWiki plugin?

Contact the plugin author directly. If the vulnerability is in a plugin on the official repository, you can also report it to the DokuWiki security team at security@dokuwiki.org.

Are there automated tools for scanning DokuWiki plugin security?

General PHP security scanners (like RIPS or Phan) can find common vulnerabilities. There is no DokuWiki-specific plugin scanner. Manual code review is the most reliable approach.

Mini Project

Goal: Perform a security audit on a plugin.

  1. Select an existing plugin (either one you wrote or a community plugin)
  2. Review the plugin code for:
    • Any $renderer->doc .= without hsc() wrapping
    • Forms without CSRF tokens
    • Missing ACL or admin permission checks
    • Unvalidated user input
    • Insecure file operations
  3. Create a vulnerability report with findings and severities
  4. Fix each vulnerability found
  5. Test the fixed plugin to ensure functionality is preserved
  6. Document the security improvements made

What's Next

Plugins extend functionality. Now explore template anatomy to understand how DokuWiki's visual layer works.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro