Skip to content

Commit e313e9d

Browse files
authored
Merge pull request #47 from Hypercart-Dev-Tools/rules/add-double-escape
feat: Add heuristic pattern for HTML-escaping in JSON response to Development
2 parents 6de9f74 + 207473c commit e313e9d

6 files changed

Lines changed: 326 additions & 26 deletions

File tree

CHANGELOG.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,47 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [1.1.2] - 2026-01-09
9+
10+
### Added
11+
- **New Pattern: HTML-Escaping in JSON Response URL Fields** (`wp-json-html-escape`) - **HEURISTIC**
12+
- **Category:** Reliability / Correctness
13+
- **Severity:** MEDIUM (warning)
14+
- **Type:** Heuristic (needs review)
15+
- **Description:** Detects HTML escaping functions (`esc_url`, `esc_attr`, `esc_html`) used in JSON response fields with URL-like names, which can cause double-encoding issues
16+
- **Problem:** Using `esc_url()` in JSON responses encodes `&``&`, breaking redirects in JavaScript
17+
- **Detection Strategy:** Two-step approach:
18+
1. Find files with JSON response functions (`wp_send_json_*`, `WP_REST_Response`, `wp_json_encode`)
19+
2. Check for `esc_url/esc_attr/esc_html` in array keys matching URL patterns (`url`, `redirect`, `link`, `href`, `view_url`, `redirect_url`, `edit_url`, `delete_url`, `ajax_url`, `api_url`, `endpoint`)
20+
- **Why Heuristic:**
21+
- Sometimes developers intentionally send HTML fragments in JSON (e.g., `html_content` field)
22+
- Escaping may be correct for non-URL fields (e.g., `message` field)
23+
- Context matters - pattern flags suspicious cases for review
24+
- **Remediation:**
25+
- Remove HTML escaping from JSON URL fields
26+
- Use raw URLs in JSON responses
27+
- Escape only when rendering into HTML context in JavaScript
28+
- **Example:**
29+
```php
30+
// ❌ Bad - Double-encoding
31+
wp_send_json_success(array(
32+
'redirect_url' => esc_url($url) // & becomes &
33+
));
34+
35+
// ✅ Good - Raw URL
36+
wp_send_json_success(array(
37+
'redirect_url' => $url // Escape in JS when needed
38+
));
39+
```
40+
- **Files Added:**
41+
- `dist/bin/patterns/wp-json-html-escape.json` - Pattern definition with heuristic flag
42+
- `dist/bin/fixtures/wp-json-html-escape.php` - Test fixture with 11 test cases (8 true positives, 3 edge cases)
43+
- **Pattern Library:** Now 29 total patterns (18 PHP, 6 Headless, 4 Node.js, 1 JS)
44+
- **Heuristic Patterns:** Now 10 total (was 9)
45+
- **Impact:** Helps prevent hard-to-debug redirect failures and double-encoding issues in AJAX/REST API responses
46+
- **Test Status:** ✅ Tested with fixture - detected 11/11 expected cases (8 true positives + 3 edge cases)
47+
- **Main Scanner Integration:** Integrated at lines 4778-4844 (after Smart Coupons check, before Transient check)
48+
849
## [1.1.1] - 2026-01-08
950

1051
### Added

dist/PATTERN-LIBRARY.json

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,27 @@
11
{
22
"version": "1.0.0",
3-
"generated": "2026-01-08T20:45:21Z",
3+
"generated": "2026-01-09T20:37:56Z",
44
"summary": {
5-
"total_patterns": 28,
6-
"enabled": 28,
5+
"total_patterns": 29,
6+
"enabled": 29,
77
"disabled": 0,
88
"by_severity": {
99
"CRITICAL": 9,
1010
"HIGH": 10,
11-
"MEDIUM": 6,
11+
"MEDIUM": 7,
1212
"LOW": 3
1313
},
1414
"by_category": {
15-
"performance": 9,"duplication": 5,"reliability": 4,"security": 8
15+
"performance": 9,"duplication": 5,"reliability": 5,"security": 8
1616
},
1717
"by_pattern_type": {
18-
"php": 17,
18+
"php": 18,
1919
"headless": 6,
2020
"nodejs": 4,
2121
"javascript": 1
2222
},
2323
"mitigation_detection_enabled": 4,
24-
"heuristic_patterns": 9,
24+
"heuristic_patterns": 10,
2525
"definitive_patterns": 19
2626
},
2727
"patterns": [
@@ -375,6 +375,20 @@
375375
"heuristic": false,
376376
"file": "wc-smart-coupons-thankyou-perf.json"
377377
},
378+
{
379+
"id": "wp-json-html-escape",
380+
"version": "",
381+
"enabled": true,
382+
"category": "reliability",
383+
"severity": "MEDIUM",
384+
"title": "HTML-escaping in JSON response URL fields",
385+
"description": "Detects HTML escaping functions (esc_url, esc_attr, esc_html) used in JSON response fields with URL-like names. This can cause double-encoding issues where & becomes & breaking redirects in JavaScript.",
386+
"detection_type": "",
387+
"pattern_type": "php",
388+
"mitigation_detection": false,
389+
"heuristic": true,
390+
"file": "wp-json-html-escape.json"
391+
},
378392
{
379393
"id": "wp-query-unbounded",
380394
"version": "1.0.0",

dist/PATTERN-LIBRARY.md

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,43 @@
11
# Pattern Library Registry
22

33
**Auto-generated by Pattern Library Manager**
4-
**Last Updated:** 2026-01-08 20:45:21 UTC
4+
**Last Updated:** 2026-01-09 20:37:56 UTC
55

66
---
77

88
## 📊 Summary Statistics
99

1010
### Total Patterns
11-
- **Total:** 28 patterns
12-
- **Enabled:** 28 patterns
11+
- **Total:** 29 patterns
12+
- **Enabled:** 29 patterns
1313
- **Disabled:** 0 patterns
1414

1515
### By Severity
1616
| Severity | Count | Percentage |
1717
|----------|-------|------------|
18-
| CRITICAL | 9 | 32.1% |
19-
| HIGH | 10 | 35.7% |
20-
| MEDIUM | 6 | 21.4% |
21-
| LOW | 3 | 10.7% |
18+
| CRITICAL | 9 | 31.0% |
19+
| HIGH | 10 | 34.5% |
20+
| MEDIUM | 7 | 24.1% |
21+
| LOW | 3 | 10.3% |
2222

2323
### By Type
2424
| Type | Count | Percentage |
2525
|------|-------|------------|
26-
| Definitive | 19 | 67.9% |
27-
| Heuristic | 9 | 32.1% |
26+
| Definitive | 19 | 65.5% |
27+
| Heuristic | 10 | 34.5% |
2828

2929
### Advanced Features
30-
- **Mitigation Detection Enabled:** 4 patterns (14.3%)
30+
- **Mitigation Detection Enabled:** 4 patterns (13.8%)
3131
- **False Positive Reduction:** 60-70% on mitigated patterns
3232

3333
### By Category
3434
- **performance:** 9 patterns
3535
- **duplication:** 5 patterns
36-
- **reliability:** 4 patterns
36+
- **reliability:** 5 patterns
3737
- **security:** 8 patterns
3838

3939
### By Pattern Type
40-
- **PHP/WordPress:** 17 patterns
40+
- **PHP/WordPress:** 18 patterns
4141
- **Headless WordPress:** 6 patterns
4242
- **Node.js/Server-Side JS:** 4 patterns
4343
- **Client-Side JavaScript:** 1 patterns
@@ -77,6 +77,7 @@
7777
- **headless-hardcoded-wordpress-url** 🔍 - Hardcoded WordPress API URL
7878
- **headless-nextjs-missing-revalidate** 🔍 - Next.js getStaticProps without revalidate (stale WordPress data)
7979
- **limit-multiplier-from-count** 🔍 - Query limit multiplier derived from count()
80+
- **wp-json-html-escape** 🔍 - HTML-escaping in JSON response URL fields
8081

8182
### LOW Severity Patterns
8283
- **array-merge-in-loop** 🔍 - array_merge() inside loops (potential OOM)
@@ -96,26 +97,26 @@
9697

9798
### Key Selling Points
9899

99-
1. **Comprehensive Coverage:** 28 detection patterns across 4 categories
100-
2. **Multi-Platform Support:** PHP/WordPress (17), Headless WordPress (6), Node.js (4), JavaScript (1)
100+
1. **Comprehensive Coverage:** 29 detection patterns across 4 categories
101+
2. **Multi-Platform Support:** PHP/WordPress (18), Headless WordPress (6), Node.js (4), JavaScript (1)
101102
3. **Enterprise-Grade Accuracy:** 4 patterns with AI-powered mitigation detection (60-70% false positive reduction)
102103
4. **Severity-Based Prioritization:** 9 CRITICAL + 10 HIGH severity patterns catch the most dangerous issues
103-
5. **Intelligent Analysis:** 19 definitive patterns + 9 heuristic patterns for comprehensive code review
104+
5. **Intelligent Analysis:** 19 definitive patterns + 10 heuristic patterns for comprehensive code review
104105

105106
### One-Liner Stats
106107

107-
> **28 detection patterns** | **4 with AI mitigation** | **60-70% fewer false positives** | **Multi-platform: PHP, Headless, Node.js, JS**
108+
> **29 detection patterns** | **4 with AI mitigation** | **60-70% fewer false positives** | **Multi-platform: PHP, Headless, Node.js, JS**
108109
109110
### Feature Highlights
110111

111112
-**9 CRITICAL** OOM and security patterns
112113
-**10 HIGH** performance and security patterns
113114
-**4 patterns** with context-aware severity adjustment
114-
-**9 heuristic** patterns for code quality insights
115+
-**10 heuristic** patterns for code quality insights
115116
-**Multi-platform:** WordPress, Headless, Node.js, JavaScript
116117

117118
---
118119

119-
**Generated:** 2026-01-08 20:45:21 UTC
120+
**Generated:** 2026-01-09 20:37:56 UTC
120121
**Version:** 1.0.0
121122
**Tool:** Pattern Library Manager

dist/bin/check-performance.sh

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ source "$REPO_ROOT/lib/pattern-loader.sh"
5858
# This is the ONLY place the version number should be defined.
5959
# All other references (logs, JSON, banners) use this variable.
6060
# Update this ONE line when bumping versions - never hardcode elsewhere.
61-
SCRIPT_VERSION="1.1.0"
61+
SCRIPT_VERSION="1.1.2"
6262

6363
# Get the start/end line range for the enclosing function/method.
6464
#
@@ -4775,6 +4775,71 @@ else
47754775
fi
47764776
text_echo ""
47774777

4778+
# ============================================================================
4779+
# HTML-Escaping in JSON Response URL Fields (Heuristic)
4780+
# ============================================================================
4781+
# Pattern: wp-json-html-escape
4782+
# Detects HTML escaping functions (esc_url, esc_attr, esc_html) used in JSON
4783+
# response fields with URL-like names. This can cause double-encoding where
4784+
# & becomes & breaking redirects in JavaScript.
4785+
# This is a HEURISTIC pattern - may flag intentional HTML fragments in JSON.
4786+
# ============================================================================
4787+
4788+
JSON_HTML_ESCAPE_SEVERITY=$(get_severity "wp-json-html-escape" "MEDIUM")
4789+
JSON_HTML_ESCAPE_COLOR="${YELLOW}"
4790+
4791+
text_echo "${BLUE}▸ HTML-escaping in JSON response URL fields (heuristic) ${JSON_HTML_ESCAPE_COLOR}[$JSON_HTML_ESCAPE_SEVERITY]${NC}"
4792+
4793+
# Step 1: Find files with JSON response functions
4794+
JSON_RESPONSE_FILES=$(grep -rlE \
4795+
'wp_send_json|WP_REST_Response|wp_json_encode' \
4796+
$EXCLUDE_ARGS --include='*.php' "$PATHS" 2>/dev/null || true)
4797+
4798+
JSON_HTML_ESCAPE_ISSUES=""
4799+
JSON_HTML_ESCAPE_FINDING_COUNT=0
4800+
4801+
if [ -n "$JSON_RESPONSE_FILES" ]; then
4802+
# Step 2: Check for esc_* functions in URL-like keys
4803+
while IFS= read -r file; do
4804+
[ -z "$file" ] && continue
4805+
4806+
# Look for patterns like: 'redirect_url' => esc_url($url)
4807+
# Match URL-like keys with HTML escaping functions
4808+
ESCAPE_MATCHES=$(grep -nE \
4809+
"('|\")?(url|redirect|link|href|view_url|redirect_url|edit_url|delete_url|ajax_url|api_url|endpoint)('|\")?\s*(=>|:)\s*esc_(url|attr|html)\(" \
4810+
"$file" 2>/dev/null || true)
4811+
4812+
if [ -n "$ESCAPE_MATCHES" ]; then
4813+
while IFS= read -r match; do
4814+
[ -z "$match" ] && continue
4815+
4816+
line_num=$(echo "$match" | cut -d: -f1)
4817+
code=$(echo "$match" | cut -d: -f2-)
4818+
4819+
if ! should_suppress_finding "wp-json-html-escape" "$file"; then
4820+
JSON_HTML_ESCAPE_ISSUES="${JSON_HTML_ESCAPE_ISSUES}${file}:${line_num}:${code}"$'\n'
4821+
add_json_finding "wp-json-html-escape" "warning" "$JSON_HTML_ESCAPE_SEVERITY" "$file" "$line_num" "Potential HTML-escaping in JSON response. esc_url() encodes & → & which can break redirects in JS. Prefer raw URL in JSON; escape when rendering into HTML." "$code"
4822+
((JSON_HTML_ESCAPE_FINDING_COUNT++)) || true
4823+
fi
4824+
done <<< "$ESCAPE_MATCHES"
4825+
fi
4826+
done <<< "$JSON_RESPONSE_FILES"
4827+
fi
4828+
4829+
if [ "$JSON_HTML_ESCAPE_FINDING_COUNT" -gt 0 ]; then
4830+
text_echo "${JSON_HTML_ESCAPE_COLOR} ⚠ NEEDS REVIEW - HTML-escaping in JSON URL fields (heuristic):${NC}"
4831+
((WARNINGS++))
4832+
if [ "$OUTPUT_FORMAT" = "text" ]; then
4833+
echo "$JSON_HTML_ESCAPE_ISSUES" | head -5
4834+
text_echo "${YELLOW} 💡 Fix: Remove esc_url/esc_attr/esc_html from JSON URL fields. Use raw URLs; escape in JS when rendering to HTML.${NC}"
4835+
fi
4836+
add_json_check "HTML-escaping in JSON response URL fields (heuristic)" "$JSON_HTML_ESCAPE_SEVERITY" "failed" "$JSON_HTML_ESCAPE_FINDING_COUNT"
4837+
else
4838+
text_echo "${GREEN} ✓ Passed${NC}"
4839+
add_json_check "HTML-escaping in JSON response URL fields (heuristic)" "$JSON_HTML_ESCAPE_SEVERITY" "passed" 0
4840+
fi
4841+
text_echo ""
4842+
47784843
# Transient abuse check - transients without expiration
47794844
TRANSIENT_SEVERITY=$(get_severity "transient-no-expiration" "MEDIUM")
47804845
TRANSIENT_COLOR="${YELLOW}"

0 commit comments

Comments
 (0)