robotstxt-documentation-mar.../docs/audit-pre-deploy-1.1.1.md
2026-06-08 12:31:51 +00:00

4.8 KiB

Pre-Deploy AI Security Audit — v1.1.1

Date: 2026-06-08 Plugin: Documentation Markdown (by ROBOTSTXT) Version: 1.1.0 → 1.1.1 Auditor: Claude Sonnet (Senior WordPress Plugin Security Auditor role) Scope: Full codebase (all 7 PHP plugin files)


Executive Summary

Overall status: CONDITIONAL PASS → PASS (after fixes applied)

All [CRITICAL] findings were resolved before tagging. No SQL injection, no CSRF gaps, no direct object reference, no privilege escalation vectors found. Access is gated behind edit_pages throughout with both UI-level and execution-level checks.

Security risk: Low (after fixes) Version recommendation: stable


Findings Resolved Before Release

[CRITICAL → FIXED] Finding 011 — CommonMark raw HTML passthrough

File: robotstxt-documentation-markdown-map.php:296 Problem: CommonMark's default config allows raw HTML blocks from Markdown. A compromised upstream GitHub repository could inject <script>, <iframe>, or event handlers into synced WordPress post content. Fix applied: html_input => 'strip', allow_unsafe_links => false in CommonMarkConverter config.

[WARNING → FIXED] Finding 002 — base64 decode without length validation

File: robotstxt-documentation-markdown-functions.php:55 Problem: base64_decode() result not length-checked before substr() IV extraction. Tampered options could cause silent decryption failures or short-IV oracle scenarios. Fix applied: Added false === $decoded || strlen($decoded) <= $iv_length guard.

[WARNING → FIXED] Finding 008 — Settings option autoloaded

File: robotstxt-documentation-markdown.php:72, 1164 Problem: Encrypted GitHub token loaded with every WordPress request via autoload. Fix applied: add_option(..., '', false) and update_option(..., false).

[WARNING → FIXED] Finding 018 — wp_update_post() return unchecked

File: robotstxt-documentation-markdown-map.php:324 Problem: Sync silently reported success even if post update failed. Fix applied: Return value checked; error returned on failure.

[WARNING → FIXED] Finding 020 — base64_decode() unchecked in GitHub fetch

File: robotstxt-documentation-markdown-github.php:289 Problem: Malformed GitHub API response (bad base64) would cause silent empty post. Fix applied: Added false === $decoded guard returning WP_Error.

[BUG → FIXED] Admin notices not displayed

File: robotstxt-documentation-markdown.php:908 Problem: Messages for mapping_created, mapping_updated, mapping_deleted, sync_complete, and error parameters were redirected to URL but never rendered. Fix applied: Complete message map added to robotstxt_docmd_render_admin_notices().


Findings Deferred to Future Release

ID Severity Description Target
001 WARNING Token key derivation should use HKDF instead of raw wp_salt() — would require token migration v1.2.0
003 WARNING Debug action nonce/page checks split across two if blocks — refactoring risk v1.2.0
005 INFO esc_js() in onclick pattern — safe with fixed string but fragile for future edits v1.2.0
006 WARNING get_posts(post_type=any, limit=100) on Add Mapping page — performance on large sites v1.2.0
009 INFO GitHub API URL: branch/path not rawurlencode()d — no current attack vector, defensive hardening v1.2.0
010 INFO target_post_type not validated against registered post types at save v1.2.0
013 INFO Debug "cached vs fresh" indicator always shows cached after first fetch v1.2.0
014 INFO Discover page refresh=1 lacks nonce — forces GitHub API call via CSRF v1.2.0

Deferred findings documented in docs/known-issues.md.


Positive Findings (No Action Required)

  • All state-changing actions protected with nonces (wp_nonce_field, wp_nonce_url, check_admin_referer, wp_verify_nonce)
  • Capability checks (current_user_can('edit_pages')) applied in both UI rendering and execution logic for all admin pages and handlers
  • All $_POST/$_GET access goes through robotstxt_docmd_input_string() / robotstxt_docmd_input_int() type-narrowing helpers
  • All output escaping at render time (esc_html, esc_attr, esc_url, esc_js, wp_kses_post)
  • All redirects via wp_safe_redirect() to admin_url() destinations
  • No raw SQL; custom SQL (transient cleanup) uses $wpdb->prepare() with $wpdb->esc_like()
  • ABSPATH guard on every PHP file
  • No eval(), no suspicious base64_decode() (documented necessary use for GitHub API decoding), no shell functions
  • GitHub token encrypted at rest (AES-256-CBC, key from wp_salt('auth'))
  • uninstall.php uses WP_UNINSTALL_PLUGIN guard and respects user data-preservation preference