Skip to content

Latest commit

 

History

History
712 lines (541 loc) · 23.9 KB

File metadata and controls

712 lines (541 loc) · 23.9 KB

Handover Document: sanctify-php Integration Insights

Context

This document summarizes findings from integrating php-aegis and sanctify-php into a WordPress semantic theme (wp-sinople-theme). It provides actionable recommendations for the sanctify-php team based on real-world usage patterns.

Role Clarification

Tool Role When Used
php-aegis Runtime security library During request handling (validation, sanitization, headers)
sanctify-php Static analysis tool During development/CI (find vulnerabilities before deploy)

These are complementary, not competing tools:

  • sanctify-php finds the bugs
  • php-aegis provides the fixes

Issues Discovered During Integration

1. Haskell Toolchain Dependency

Problem: sanctify-php requires GHC/Cabal to build, which is a significant barrier for PHP developers.

Impact: Most PHP teams don't have Haskell expertise or toolchain installed.

Recommendations:

  • Provide pre-built binaries for Linux (x86_64, aarch64), macOS (Intel, Apple Silicon), Windows
  • Create official Docker image: ghcr.io/hyperpolymath/sanctify-php:latest
  • Consider GitHub Actions integration that runs analysis without local install
  • Add installation via common package managers (Homebrew, apt, nix)

Example Docker usage:

docker run --rm -v $(pwd):/workspace ghcr.io/hyperpolymath/sanctify-php analyze /workspace

2. PHP 8.x Syntax Support

Problem: Parser may not handle all PHP 8.x syntax (enums, union types, named arguments, attributes, match expressions, constructor property promotion).

Test cases needed:

// Enums (PHP 8.1+)
enum Status: string {
    case Draft = 'draft';
    case Published = 'published';
}

// Union types (PHP 8.0+)
function process(string|int $input): string|false { ... }

// Attributes (PHP 8.0+)
#[Route('/api/users')]
class UserController { ... }

// Constructor property promotion (PHP 8.0+)
class User {
    public function __construct(
        public readonly string $name,
        private int $age = 0,
    ) {}
}

// Named arguments (PHP 8.0+)
htmlspecialchars(string: $input, flags: ENT_QUOTES);

// Match expressions (PHP 8.0+)
$result = match($status) {
    Status::Draft => 'Editing',
    Status::Published => 'Live',
};

Recommendation: Add PHP 8.x grammar rules and comprehensive test suite.

3. RDF/Turtle Output Context Awareness

Problem: Static analyzer doesn't detect RDF/Turtle injection vulnerabilities in semantic web themes.

Background: Semantic WordPress themes output RDF Turtle format for linked data. Standard XSS detection won't catch Turtle-specific injection vectors.

Vulnerable pattern (not currently detected):

// DANGEROUS: addslashes() is insufficient for Turtle
$turtle = '<' . $uri . '> rdfs:label "' . addslashes($label) . '" .';

Attack vectors:

# Turtle escape sequences
\n \r \t \\ \" \uXXXX \UXXXXXXXX

# IRI injection
<http://evil.com> owl:sameAs <http://trusted.com>

Recommendation: Add detection rules for:

  • addslashes() used in RDF/Turtle context
  • Unescaped variables in Turtle string literals ("...")
  • Unescaped IRIs (<...>)
  • Missing use of proper escaping functions

Suggested rule signatures:

turtle_string_injection: Detects unescaped user input in Turtle string literals
turtle_iri_injection: Detects unescaped user input in Turtle IRIs
rdf_semantic_injection: Detects potential semantic attacks via RDF

4. WordPress Integration Documentation

Problem: No clear guidance for WordPress-specific vulnerability patterns.

WordPress-specific patterns to detect:

// DANGEROUS: Direct $_GET/$_POST usage
echo $_GET['query'];  // XSS

// DANGEROUS: Missing nonce verification
if (isset($_POST['action'])) { ... }  // CSRF

// DANGEROUS: Direct SQL interpolation
$wpdb->query("SELECT * FROM users WHERE id = " . $_GET['id']);  // SQLi

// DANGEROUS: Unescaped output
echo $user_input;  // Should use esc_html(), esc_attr(), etc.

// DANGEROUS: Privileged action without capability check
add_action('wp_ajax_delete_user', 'delete_user_handler');
function delete_user_handler() {
    // Missing: current_user_can('delete_users')
    wp_delete_user($_POST['user_id']);
}

WordPress-specific safe patterns:

// Safe escaping functions
esc_html($text)
esc_attr($attr)
esc_url($url)
wp_kses($html, $allowed)
wp_kses_post($html)

// Safe nonce verification
wp_verify_nonce($_POST['_wpnonce'], 'action_name')
check_admin_referer('action_name')

// Safe capability checks
current_user_can('edit_posts')

Recommendation: Create WordPress-specific ruleset that:

  • Detects missing esc_* function usage
  • Detects missing nonce verification in form handlers
  • Detects missing capability checks in AJAX handlers
  • Recognizes WordPress sanitization functions as safe sinks

5. IndieWeb/Micropub Pattern Detection

Problem: No awareness of IndieWeb protocols (Micropub, IndieAuth, Webmention).

Patterns to detect:

// DANGEROUS: Missing IndieAuth token verification
function handle_micropub($request) {
    $content = $request['content'];  // Unverified!
    create_post($content);
}

// DANGEROUS: Webmention SSRF
function verify_webmention($source) {
    $response = wp_remote_get($source);  // Can hit internal IPs
}

// DANGEROUS: Micropub content injection
$mf2 = Mf2\parse($html, $source);
$content = $mf2['items'][0]['properties']['content'][0];
echo $content;  // Unsanitized from external source

Recommendation: Add rules for common IndieWeb vulnerability patterns.

Integration Architecture

┌─────────────────────────────────────────────────────────────┐
│                    Development Workflow                      │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  ┌──────────────┐    ┌──────────────┐    ┌──────────────┐  │
│  │  Developer   │───▶│ sanctify-php │───▶│   Fix Code   │  │
│  │  Writes Code │    │  (Analysis)  │    │  (Guidance)  │  │
│  └──────────────┘    └──────────────┘    └──────────────┘  │
│                              │                               │
│                              ▼                               │
│                     ┌──────────────┐                        │
│                     │  php-aegis   │                        │
│                     │  (Runtime)   │                        │
│                     └──────────────┘                        │
│                                                              │
└─────────────────────────────────────────────────────────────┘

Recommended sanctify-php Output Format

When sanctify-php detects a vulnerability, it should suggest the php-aegis fix:

VULNERABILITY: XSS in output context
FILE: theme/template.php:42
CODE: echo $user_input;

RECOMMENDATION:
  Use php-aegis Sanitizer for proper encoding:

  Before: echo $user_input;
  After:  echo \PhpAegis\Sanitizer::html($user_input);

  Install: composer require hyperpolymath/php-aegis

Priority Recommendations Summary

Priority Issue Effort
P0 Pre-built binaries / Docker image Medium
P0 PHP 8.x syntax support High
P0 Official GitHub Action (sanctify-php-action) Medium
P1 WordPress-specific rulesets Medium
P1 RDF/Turtle context detection Medium
P1 SARIF output for GitHub Security tab Low
P2 Incremental analysis (cache, scan changed files only) High
P2 IndieWeb protocol patterns Low
P2 php-aegis fix suggestions in output Low

Additional Findings (Report 2)

6. GitHub Action Required

Problem: No official GitHub Action for CI integration.

Impact: Teams must write custom workflow configuration or use Docker manually.

Recommendation: Create hyperpolymath/sanctify-php-action with:

# .github/workflows/security.yml
- uses: hyperpolymath/sanctify-php-action@v1
  with:
    path: ./src
    config: sanctify.yml
    sarif-output: results.sarif

7. SARIF Output for GitHub Integration

What Works Well: SARIF format enables direct GitHub Security tab integration.

Enhancement: Ensure SARIF output includes:

  • Rule descriptions with OWASP references
  • Severity levels mapped to GitHub's critical/high/medium/low
  • Fix suggestions linking to php-aegis methods
{
  "runs": [{
    "tool": { "driver": { "name": "sanctify-php" } },
    "results": [{
      "ruleId": "xss-output",
      "level": "error",
      "message": { "text": "Unescaped output" },
      "fixes": [{
        "description": { "text": "Use PhpAegis\\Sanitizer::html()" }
      }]
    }]
  }]
}

8. Incremental Analysis

Problem: Full codebase scans are slow on large projects.

Recommendation:

  • Cache AST and taint analysis results
  • On subsequent runs, only analyze changed files
  • Invalidate cache when dependencies change
  • Use file modification timestamps or git diff
# First run: full analysis, build cache
sanctify analyze ./src --cache .sanctify-cache

# Subsequent runs: incremental
sanctify analyze ./src --cache .sanctify-cache --incremental

9. Composer Plugin Wrapper

Problem: PHP developers expect composer require installation.

Recommendation: Create a Composer plugin that:

  1. Downloads pre-built binary for platform
  2. Provides vendor/bin/sanctify wrapper
  3. Handles updates via Composer
composer require --dev hyperpolymath/sanctify-php
vendor/bin/sanctify analyze ./src

Standalone vs Combined Operation

Minimal Requirements for Each Tool

php-aegis standalone (runtime protection):

  • Zero dependencies (works everywhere PHP runs)
  • Static methods for easy drop-in usage
  • Works without sanctify-php installed

sanctify-php standalone (static analysis):

  • Pre-built binary (no Haskell needed)
  • SARIF output for any CI system
  • Works without php-aegis (just reports issues)

Combined Synergies

When both tools are used together:

┌─────────────────────────────────────────────────────────────────┐
│                    Combined Workflow                             │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  ┌────────────┐   ┌─────────────────┐   ┌──────────────────┐   │
│  │   Write    │──▶│  sanctify-php   │──▶│  Fix with        │   │
│  │   Code     │   │  (finds issues) │   │  php-aegis       │   │
│  └────────────┘   └─────────────────┘   └──────────────────┘   │
│                            │                      │              │
│                            ▼                      ▼              │
│                   ┌─────────────────────────────────────┐       │
│                   │  sanctify-php recognizes php-aegis  │       │
│                   │  methods as "safe sinks" in taint   │       │
│                   │  analysis, reducing false positives │       │
│                   └─────────────────────────────────────┘       │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

Key synergy: sanctify-php should recognize php-aegis sanitizers as safe:

-- sanctify-php taint rules
safeSinks = [
  "PhpAegis\\Sanitizer::html",
  "PhpAegis\\Sanitizer::attr",
  "PhpAegis\\Sanitizer::js",
  "PhpAegis\\Sanitizer::css",
  "PhpAegis\\Sanitizer::url",
  "PhpAegis\\TurtleEscaper::string",
  "PhpAegis\\TurtleEscaper::iri"
]

Integration Metrics

Metric Before Integration After Integration
Files with strict_types 0 24 (100%)
PHP version 7.4+ 8.2+
WordPress version 5.8+ 6.4+
CI security checks 0 4

Additional Findings (Report 3: Zotpress Plugin)

10. GHC Barrier Confirmed (Critical)

Problem: sanctify-php could not run on the Zotpress integration due to missing Haskell toolchain.

Impact: This is now confirmed across multiple integration attempts. The Haskell build requirement is the #1 adoption barrier.

Immediate Recommendations:

  1. Provide pre-built binaries for:
    • Linux x86_64 (static binary)
    • Linux aarch64 (for ARM servers)
    • macOS Intel
    • macOS Apple Silicon
    • Windows x64
  2. Publish Docker image: ghcr.io/hyperpolymath/sanctify-php:latest
  3. Create GitHub Action that uses the Docker image internally

Workaround Used: Manual analysis using sanctify-php's documented detection patterns.

11. WordPress Security API Overlap

Finding: When analyzing mature WordPress plugins (like Zotpress), they already follow WordPress security best practices using core functions.

WordPress provides equivalent security functions:

php-aegis WordPress Equivalent Notes
Validator::email() is_email() WP version is more permissive
Validator::url() wp_http_validate_url() WP has SSL enforcement
Sanitizer::html() esc_html() Identical functionality
Sanitizer::attr() esc_attr() Identical functionality
Sanitizer::js() esc_js() WP version is context-aware
Sanitizer::url() esc_url() WP handles protocols
Sanitizer::stripTags() wp_strip_all_tags() WP handles more edge cases

What sanctify-php should detect:

  • Direct use of raw PHP functions instead of WordPress equivalents
  • echo $var instead of echo esc_html($var)
  • header('Location: ...') instead of wp_redirect()
  • Missing exit; after redirect

sanctify-php rule suggestions:

-- WordPress-specific rules
wpRules = [
  ("use_wp_redirect", "header\\s*\\(\\s*['\"]Location", "Use wp_redirect() instead of header()"),
  ("missing_exit_redirect", "wp_redirect\\([^;]+\\);(?!\\s*exit)", "Add exit; after wp_redirect()"),
  ("raw_echo", "echo\\s+\\$(?!esc_)", "Escape output with esc_html()/esc_attr()"),
  ("direct_superglobal", "\\$_(GET|POST|REQUEST)\\[", "Sanitize superglobals before use")
]

12. Target Audience Clarification Needed

Finding: php-aegis value proposition is unclear for WordPress users.

Recommended positioning for sanctify-php:

When sanctify-php detects issues in WordPress code, suggest:

  1. First choice: WordPress native function (if available)
  2. Second choice: php-aegis function (for gaps WordPress doesn't cover)
VULNERABILITY: Unescaped output
FILE: plugin.php:42
CODE: echo $user_input;

RECOMMENDATION:
  WordPress: echo esc_html($user_input);
  Or php-aegis: echo \PhpAegis\Sanitizer::html($user_input);

13. WordPress-Unique Security Patterns

What sanctify-php should understand about WordPress:

// WordPress-specific security patterns

// 1. ABSPATH protection (must be at top of every PHP file)
if (!defined('ABSPATH')) exit;

// 2. Nonce verification for forms
check_admin_referer('action_name');
wp_verify_nonce($_POST['nonce'], 'action_name');

// 3. Capability checks for privileged actions
if (!current_user_can('manage_options')) return;

// 4. Prepared statements for database
$wpdb->prepare("SELECT * FROM table WHERE id = %d", $id);

// 5. Safe redirect
wp_safe_redirect($url);
exit;

Detection rules needed:

  • Missing ABSPATH check at file start
  • Form handlers without nonce verification
  • AJAX handlers without capability checks
  • Missing exit; after redirects

Additional Findings (Report 4: sinople-theme Full Integration)

14. Successful Integration Pattern

What Worked: Full integration with WordPress theme including:

  • Function wrappers: sinople_aegis_html(), sinople_aegis_attr(), sinople_aegis_json()
  • Validation wrappers: sinople_aegis_validate_*() functions
  • RDF/Turtle feed endpoint using TurtleEscaper (unique value!)
  • Graceful fallback to WordPress functions when php-aegis unavailable
  • Unit tests for the integration

Key Success: TurtleEscaper proved its unique value by enabling a /feed/turtle/ endpoint.

15. sanctify-php False Positives Identified

Issues to address:

  1. UnsafeRedirect false positive: When exit; is on the next line
// This triggers false positive:
wp_redirect($url);
exit;

// sanctify-php expects:
wp_redirect($url); exit;
  1. MissingTextDomain false positive: Flags WordPress core functions
// This may be flagged incorrectly:
__('Text', 'theme-domain');  // OK
_e('Text', 'theme-domain');  // OK
esc_html__('Text');          // May flag - but sometimes domain is optional

Recommendation: Add configuration options:

# sanctify.yml
rules:
  UnsafeRedirect:
    allow_next_line_exit: true
  MissingTextDomain:
    ignore_core_functions: true

16. PHP 8.1+ Syntax Verification Needed

Concern: Parser may not handle modern PHP syntax.

Test cases to verify:

// Nullsafe operator (PHP 8.0+)
$value = $object?->property?->method();

// Match expression (PHP 8.0+)
$result = match($type) {
    'html' => Sanitizer::html($input),
    'js' => Sanitizer::js($input),
    default => $input,
};

// Constructor property promotion (PHP 8.0+)
public function __construct(
    private readonly string $name,
) {}

// First-class callable syntax (PHP 8.1+)
$fn = Sanitizer::html(...);

17. Guix Export Documentation

Issue: Guix package export documentation is incomplete.

Recommendation: Add to sanctify-php docs:

;; guix.scm
(use-modules (guix packages)
             (guix git-download)
             (guix build-system haskell))

(package
  (name "sanctify-php")
  (version "0.1.0")
  (source (git-reference
           (url "https://github.com/hyperpolymath/sanctify-php")
           (commit (string-append "v" version))))
  (build-system haskell-build-system)
  (synopsis "PHP security static analyzer")
  (license license:agpl3+))

php-aegis Self-Identified Issues (Report 4)

These issues were discovered during sinople-theme integration:

Issue Status Resolution
Headers::secure() missing permissionsPolicy() ✅ Fixed Added in this PR
php-aegis-compat package doesn't exist 📋 Planned Create separate repo
Not published on Packagist 📋 Planned Publish after v0.2.0
WordPress mu-plugin adapter not implemented 📋 Planned Phase 7 roadmap

Additional Findings (Report 5: Sinople Theme - Critical Vulnerability Fixed)

18. TurtleEscaper Fixed Real Vulnerability

Critical Finding: The theme was using addslashes() for RDF Turtle escaping - this is SQL escaping, NOT Turtle escaping. This was a real RDF injection vulnerability.

Before (vulnerable):

// DANGEROUS: addslashes() is SQL escaping, not Turtle escaping!
$turtle = '"' . addslashes($label) . '"@en';

After (fixed):

use PhpAegis\TurtleEscaper;
$turtle = TurtleEscaper::literal($label, language: 'en');

This validates TurtleEscaper as the #1 unique value proposition of php-aegis.

19. Security Fixes Applied in Real Integration

Severity Issue Fix Applied
CRITICAL addslashes() for Turtle TurtleEscaper::literal()
CRITICAL IRI interpolation Validator::url() + error handling
HIGH URL validation via strpos() parse_url() host comparison
HIGH Unsanitized Micropub input sanitize_text_field() + wp_kses_post()
MEDIUM No security headers Headers::secure() equivalent
MEDIUM No rate limiting 1-min rate limit for Webmentions
LOW Missing strict_types Added to all files

20. New Detection Rules for sanctify-php

RDF Turtle as Distinct Output Context:

sanctify-php should recognize Turtle output contexts and flag:

-- RDF Turtle detection rules
turtleRules = [
  -- Dangerous: SQL escaping in Turtle context
  ("turtle_addslashes", "addslashes\\s*\\([^)]+\\).*['\"]@[a-z]{2}",
   "Use TurtleEscaper::literal() instead of addslashes() for Turtle"),

  -- Dangerous: String interpolation in Turtle IRI
  ("turtle_iri_interp", "<.*\\$[a-zA-Z_].*>",
   "Use TurtleEscaper::iri() for Turtle IRIs"),

  -- Dangerous: Raw variable in Turtle string
  ("turtle_string_raw", "\"\\$[a-zA-Z_][^\"]*\"@[a-z]",
   "Use TurtleEscaper::string() for Turtle literals")
]

WordPress REST API Pattern Recognition:

-- WordPress REST API rules
restRules = [
  ("rest_missing_permission", "register_rest_route.*permission_callback.*__return_true",
   "REST routes should verify permissions"),

  ("rest_raw_param", "\\$request\\[.*\\](?!.*sanitize)",
   "Sanitize REST API parameters")
]

WordPress Hook Detection (reduce false positives):

-- Functions defined via add_action/add_filter are called by WordPress
wpHookFunctions = extractFunctionsFrom [
  "add_action\\s*\\([^,]+,\\s*['\"]([^'\"]+)",
  "add_filter\\s*\\([^,]+,\\s*['\"]([^'\"]+)"
]
-- These should not be flagged as "unused functions"

21. php-aegis Enhancement Requests

From this integration:

Request Priority Notes
WordPress nonce validator Medium Validator::wpNonce($nonce, $action)
WordPress capability checker Medium Validator::wpCapability($cap)
TurtleEscaper case sensitivity docs Low Language tags should be lowercase
SPDX identifier validator Low Validator::spdx($identifier)
Headers + WordPress integration docs Medium How to use with wp_headers filter

Final Summary: Integration Value Matrix

Tool WordPress Value Non-WP Value Unique Capability
php-aegis Low (WP has esc_*) High RDF/Turtle escaping
sanctify-php High (finds WP issues) High Taint tracking

Key Learnings Across 5 Reports

  1. TurtleEscaper is the killer feature - Fixed real vulnerabilities in semantic web themes
  2. GHC barrier is critical - Confirmed in every sanctify-php integration attempt
  3. WordPress has comprehensive APIs - php-aegis basic escaping is redundant
  4. php-aegis shines in framework gaps - Security headers, extended validators, RDF/Turtle
  5. sanctify-php needs WordPress awareness - Hook detection, REST API patterns

Contact

For questions about this integration or to coordinate between repos:


Generated from real-world WordPress integration experience (Reports 1-5).