Changeset 3757543
- Timestamp:
- 10/20/2026 10:55:53 PM (28 hours ago)
- Location:
- tibacheck-site-audit/trunk
- Files:
-
- 9 edited
-
includes/checks/class-check-app-passwords.php (modified) (1 diff)
-
includes/checks/class-check-core-updates.php (modified) (5 diffs)
-
includes/checks/class-check-db-triggers.php (modified) (2 diffs)
-
includes/checks/class-check-uploads-code.php (modified) (3 diffs)
-
includes/class-tibacheck.php (modified) (10 diffs)
-
includes/class-watch.php (modified) (1 diff)
-
includes/interface-check.php (modified) (2 diffs)
-
readme.txt (modified) (4 diffs)
-
tibacheck.php (modified) (12 diffs)
Legend:
- Unmodified
- Added
- Removed
-
tibacheck-site-audit/trunk/includes/checks/class-check-app-passwords.php
r3755283 r3757543 39 39 'label' => __( 'Application passwords', 'tibacheck-site-audit' ), 40 40 'status' => 'warn', 41 'evidence_complete' => false, 41 42 'message' => __( 'The database did not answer the application-password lookup, so we cannot confirm whether any exist.', 'tibacheck-site-audit' ), 42 43 'fix' => __( 'Re-run the audit; if this persists, ask your host to check database access for the users tables.', 'tibacheck-site-audit' ), -
tibacheck-site-audit/trunk/includes/checks/class-check-core-updates.php
r3755283 r3757543 15 15 $themes = get_site_transient( 'update_themes' ); 16 16 17 if ( false === $core && false === $plugins && false === $themes ) { 18 return array( 19 'id' => 'core-updates', 20 'label' => __( 'Software updates', 'tibacheck-site-audit' ), 21 'status' => 'warn', 22 'message' => __( 'Update status unknown — WordPress has not completed an update check on this site yet, so we cannot confirm anything is current.', 'tibacheck-site-audit' ), 23 'fix' => __( 'Visit Dashboard → Updates once to trigger a check, then re-run this audit.', 'tibacheck-site-audit' ), 24 ); 17 // Each population must be known independently. Missing data is not zero updates. 18 $unknown = array(); 19 $core_known = is_object( $core ) && isset( $core->updates ) && is_array( $core->updates ) && count( $core->updates ) > 0; 20 if ( $core_known ) { 21 foreach ( $core->updates as $update ) { 22 if ( ! is_object( $update ) || ! isset( $update->response ) || ! is_string( $update->response ) || '' === $update->response ) { 23 $core_known = false; 24 } 25 } 25 26 } 27 if ( ! $core_known ) { $unknown[] = __( 'WordPress core', 'tibacheck-site-audit' ); } 28 if ( ! is_object( $plugins ) || ! isset( $plugins->response ) || ! ( is_array( $plugins->response ) || is_object( $plugins->response ) ) ) { 29 $unknown[] = __( 'plugins', 'tibacheck-site-audit' ); 30 } 31 if ( ! is_object( $themes ) || ! isset( $themes->response ) || ! ( is_array( $themes->response ) || is_object( $themes->response ) ) ) { 32 $unknown[] = __( 'themes', 'tibacheck-site-audit' ); 33 } 34 $unknown_message = $unknown ? sprintf( 35 /* translators: %s: components with unavailable update data */ 36 __( 'Update status unknown for: %s. Visit Dashboard → Updates to complete a check, then run the audit again.', 'tibacheck-site-audit' ), 37 implode( ', ', $unknown ) 38 ) : ''; 26 39 27 40 $core_pending = false; 28 if ( $core && ! empty( $core->updates ) ) {41 if ( is_object( $core ) && isset( $core->updates ) && is_array( $core->updates ) ) { 29 42 foreach ( (array) $core->updates as $u ) { 30 if ( is set( $u->response )&& 'latest' !== $u->response ) {43 if ( is_object( $u ) && isset( $u->response ) && is_string( $u->response ) && '' !== $u->response && 'latest' !== $u->response ) { 31 44 $core_pending = true; 32 45 break; … … 35 48 } 36 49 37 $pcount = ( $plugins && ! empty( $plugins->response) ) ? count( (array) $plugins->response ) : 0;38 $tcount = ( $themes && ! empty( $themes->response) ) ? count( (array) $themes->response ) : 0;50 $pcount = ( is_object( $plugins ) && isset( $plugins->response ) && ( is_array( $plugins->response ) || is_object( $plugins->response ) ) ) ? count( (array) $plugins->response ) : 0; 51 $tcount = ( is_object( $themes ) && isset( $themes->response ) && ( is_array( $themes->response ) || is_object( $themes->response ) ) ) ? count( (array) $themes->response ) : 0; 39 52 40 53 $total = ( $core_pending ? 1 : 0 ) + $pcount + $tcount; … … 43 56 return array( 44 57 'id' => 'core-updates', 58 'evidence_complete' => empty( $unknown ), 45 59 'label' => __( 'Software updates', 'tibacheck-site-audit' ), 46 'status' => 'pass',47 'message' => __( 'Core, plugins, and themes are all up to date.', 'tibacheck-site-audit' ),48 'fix' => __( 'Keep it that way — check weekly.', 'tibacheck-site-audit' ),60 'status' => $unknown ? 'warn' : 'pass', 61 'message' => $unknown ? $unknown_message : __( 'Core, plugins, and themes are all up to date.', 'tibacheck-site-audit' ), 62 'fix' => $unknown ? __( 'Complete the missing update checks before treating this site as current.', 'tibacheck-site-audit' ) : __( 'Keep it that way — check weekly.', 'tibacheck-site-audit' ), 49 63 ); 50 64 } … … 65 79 return array( 66 80 'id' => 'core-updates', 81 'evidence_complete' => empty( $unknown ), 67 82 'label' => __( 'Software updates', 'tibacheck-site-audit' ), 68 83 'status' => $core_pending ? 'fail' : 'warn', … … 71 86 __( 'Pending updates: %s.', 'tibacheck-site-audit' ), 72 87 implode( ', ', $parts ) 73 ) ,88 ) . ( $unknown_message ? ' ' . $unknown_message : '' ), 74 89 'fix' => __( 'Back up first, then update — core first, then plugins, then themes.', 'tibacheck-site-audit' ), 75 90 ); -
tibacheck-site-audit/trunk/includes/checks/class-check-db-triggers.php
r3755283 r3757543 31 31 'label' => __( 'Database triggers', 'tibacheck-site-audit' ), 32 32 'status' => 'warn', 33 'evidence_complete' => false, 33 34 'message' => __( 'The database did not answer the trigger inspection, so we cannot confirm this site has no database triggers.', 'tibacheck-site-audit' ), 34 35 'fix' => __( 'Ask your host to confirm the database user can read information_schema, then re-run the audit.', 'tibacheck-site-audit' ), … … 59 60 'label' => __( 'Database triggers', 'tibacheck-site-audit' ), 60 61 'status' => 'warn', 62 'evidence_complete' => false, 61 63 'message' => __( 'We could not confirm trigger visibility for this database user, so an empty result here is not proof that no triggers exist.', 'tibacheck-site-audit' ), 62 64 'fix' => __( 'Ask your host whether the database user holds the TRIGGER privilege (or can see information_schema.TRIGGERS), then re-run the audit.', 'tibacheck-site-audit' ), -
tibacheck-site-audit/trunk/includes/checks/class-check-uploads-code.php
r3755283 r3757543 64 64 'label' => __( 'Code in uploads', 'tibacheck-site-audit' ), 65 65 'status' => 'warn', 66 'evidence_complete' => false, 66 67 'message' => __( 'The uploads directory could not be fully scanned (permissions or a filesystem error).', 'tibacheck-site-audit' ), 67 68 'fix' => __( 'Ask your host to check the uploads folder permissions, then re-run the audit.', 'tibacheck-site-audit' ), … … 77 78 'label' => __( 'Code in uploads', 'tibacheck-site-audit' ), 78 79 'status' => 'fail', 80 'evidence_complete' => ! $truncated, 79 81 'message' => sprintf( 80 82 /* translators: %s: list of code file paths found inside the uploads directory */ … … 91 93 'label' => __( 'Code in uploads', 'tibacheck-site-audit' ), 92 94 'status' => 'warn', 95 'evidence_complete' => false, 93 96 'message' => sprintf( 94 97 /* translators: %d: number of files actually scanned before the safety limit */ -
tibacheck-site-audit/trunk/includes/class-tibacheck.php
r3755283 r3757543 38 38 'Tiba_Check_App_Passwords', 39 39 'Tiba_Check_Plugin_Redundancy', 40 // WooCommerce pack: each of these returns null (no row) when 41 // WooCommerce is not active, so non-store reports never see them. 42 'Tiba_Check_Woo_Pages', 43 'Tiba_Check_Woo_Payments', 44 'Tiba_Check_Woo_Details', 45 'Tiba_Check_Woo_Checkout', 40 46 ); 41 47 … … 62 68 $check = new $class(); 63 69 $result = $check->run(); 70 if ( null === $result && self::allows_null( $class ) ) { 71 // A site-conditional check declared itself not 72 // applicable to this site (e.g. a store check 73 // with no store): omit it entirely — no row, 74 // no score effect. Nulls from any other check 75 // fall through to the unreadable-result warning 76 // below, exactly as before this contract existed, 77 // so a check can never vanish silently by bug. 78 continue; 79 } 64 80 if ( self::is_valid_result( $result ) ) { 65 81 $results[] = $result; … … 118 134 119 135 /** 120 * OWASP Top 10 (2021) mapping: check id => category code. 136 * The only checks allowed to return null ("not applicable"). 137 * Kept explicit so the null contract can never silently 138 * swallow a check that was supposed to report (see run()). 139 * 140 * @param string $class Check class name. 141 * @return bool 142 */ 143 private static function allows_null( $class ) { 144 return in_array( 145 $class, 146 array( 147 'Tiba_Check_Woo_Pages', 148 'Tiba_Check_Woo_Payments', 149 'Tiba_Check_Woo_Details', 150 'Tiba_Check_Woo_Checkout', 151 ), 152 true 153 ); 154 } 155 156 /** 157 * Whether WooCommerce is active on this site (site-level or 158 * network-wide on multisite). Two signals, either suffices: 159 * the canonical plugin path in the active-plugins options 160 * (works in any context, admin or cron), or WooCommerce's 161 * own class being loaded (catches renamed folders and 162 * must-use/composer loading, where the path test would miss 163 * a real store). 164 * 165 * @return bool 166 */ 167 public static function woocommerce_active() { 168 return in_array( 'woocommerce/woocommerce.php', self::active_plugin_paths(), true ) 169 || class_exists( 'WooCommerce' ); 170 } 171 172 /** 173 * OWASP Top 10 (2025) mapping: check id => category code. 121 174 * Only categories our checks genuinely assess are mapped; the rest 122 175 * are reported as "not assessed" rather than implied safe. … … 126 179 public static function owasp_map() { 127 180 return array( 128 'core-updates' => 'A0 6',129 'php-version' => 'A0 6',130 'inactive-plugins' => 'A0 6',181 'core-updates' => 'A03', 182 'php-version' => 'A03', 183 'inactive-plugins' => 'A03', 131 184 'user-accounts' => 'A01', 132 185 'registration-safety' => 'A01', 133 'file-editor' => 'A0 5',134 'debug-display' => 'A 05',135 'ssl' => 'A0 2',186 'file-editor' => 'A02', 187 'debug-display' => 'A10', 188 'ssl' => 'A04', 136 189 'privilege-audit' => 'A01', 137 190 'app-passwords' => 'A07', … … 139 192 'db-triggers' => 'A08', 140 193 'cron-provenance' => 'A08', 141 'uploads-code' => 'A0 5',142 'prepend-directives' => 'A0 5',143 ); 144 } 145 146 /** 147 * All ten OWASP Top 10 (202 1) categories, code => name.194 'uploads-code' => 'A02', 195 'prepend-directives' => 'A02', 196 ); 197 } 198 199 /** 200 * All ten OWASP Top 10 (2025) categories, code => name. 148 201 * 149 202 * @return array<string,string> … … 152 205 return array( 153 206 'A01' => __( 'Broken Access Control', 'tibacheck-site-audit' ), 154 'A02' => __( 'Cryptographic Failures', 'tibacheck-site-audit' ), 155 'A03' => __( 'Injection', 'tibacheck-site-audit' ), 156 'A04' => __( 'Insecure Design', 'tibacheck-site-audit' ), 157 'A05' => __( 'Security Misconfiguration', 'tibacheck-site-audit' ), 158 'A06' => __( 'Vulnerable and Outdated Components', 'tibacheck-site-audit' ), 159 'A07' => __( 'Identification and Authentication Failures', 'tibacheck-site-audit' ), 160 'A08' => __( 'Software and Data Integrity Failures', 'tibacheck-site-audit' ), 161 'A09' => __( 'Security Logging and Monitoring Failures', 'tibacheck-site-audit' ), 162 'A10' => __( 'Server-Side Request Forgery', 'tibacheck-site-audit' ), 163 ); 207 'A02' => __( 'Security Misconfiguration', 'tibacheck-site-audit' ), 208 'A03' => __( 'Software Supply Chain Failures', 'tibacheck-site-audit' ), 209 'A04' => __( 'Cryptographic Failures', 'tibacheck-site-audit' ), 210 'A05' => __( 'Injection', 'tibacheck-site-audit' ), 211 'A06' => __( 'Insecure Design', 'tibacheck-site-audit' ), 212 'A07' => __( 'Authentication Failures', 'tibacheck-site-audit' ), 213 'A08' => __( 'Software or Data Integrity Failures', 'tibacheck-site-audit' ), 214 'A09' => __( 'Security Logging & Alerting Failures', 'tibacheck-site-audit' ), 215 'A10' => __( 'Mishandling of Exceptional Conditions', 'tibacheck-site-audit' ), 216 ); 217 } 218 219 /** Labels describe limited checks, never the whole risk category. */ 220 public static function owasp_status_label( $status ) { 221 $labels = array( 222 'pass' => __( 'Partial — checks passed', 'tibacheck-site-audit' ), 223 'warn' => __( 'Partial — checks need attention', 'tibacheck-site-audit' ), 224 'fail' => __( 'Partial — checks failed', 'tibacheck-site-audit' ), 225 'unknown' => __( 'Incomplete evidence', 'tibacheck-site-audit' ), 226 ); 227 return $labels[ $status ] ?? $labels['unknown']; 164 228 } 165 229 … … 167 231 * Compute the two headline scores from a result set. 168 232 * Health: every check, fail −10 / warn −4. 169 * Security: OWASP-mapped checks only, fail −20 / warn −8 .233 * Security: OWASP-mapped checks only, fail −20 / warn −8; null if any mapped check is missing or invalid. 170 234 * Both clamp to 0–100. Also returns the worst status per OWASP 171 235 * category, keyed by category code. … … 180 244 $owasp = array(); 181 245 $map = self::owasp_map(); 182 $mapped = 0;246 $mapped = array(); 183 247 184 248 foreach ( $results as $r ) { … … 192 256 } 193 257 if ( isset( $map[ $r['id'] ] ) ) { 194 $mapped++; 258 if ( ! isset( $r['evidence_complete'] ) || true === $r['evidence_complete'] ) { 259 $mapped[ $r['id'] ] = true; 260 } 195 261 if ( 'fail' === $r['status'] ) { 196 262 $security -= 20; … … 205 271 } 206 272 273 // Every mapped check is required for the numeric security heuristic. 274 // A runner fallback has a different ID, so missing/failed execution 275 // cannot silently become a perfect score or a passing category. 276 foreach ( $map as $id => $code ) { 277 if ( ! isset( $mapped[ $id ] ) && ( ! isset( $owasp[ $code ] ) || 'pass' === $owasp[ $code ] ) ) { 278 $owasp[ $code ] = 'unknown'; 279 } 280 } 281 207 282 return array( 208 283 'health' => max( 0, $health ), 209 'security' => $mapped ? max( 0, $security ) : null, 284 'security' => count( $mapped ) === count( $map ) ? max( 0, $security ) : null, 285 'owasp_version' => '2025', 210 286 'owasp' => $owasp, 211 287 ); -
tibacheck-site-audit/trunk/includes/class-watch.php
r3755283 r3757543 139 139 'health' => $scores['health'], 140 140 'security' => $scores['security'], 141 'owasp_version' => $scores['owasp_version'], 141 142 'time' => time(), 142 143 'statuses' => $statuses, -
tibacheck-site-audit/trunk/includes/interface-check.php
r3755283 r3757543 8 8 * - status: 'pass' | 'warn' | 'fail' 9 9 * - message: what was found, in plain language 10 * - evidence_complete: optional bool; false for unavailable or truncated evidence, independently of severity 10 11 * - fix: what to do about it, in plain language 11 12 * 12 13 * Checks must be read-only: they may not change options, files, or the 13 14 * database. The audit reports; the care plan (or the site owner) fixes. 15 * 16 * A check that does not apply to this site (for example a store check 17 * on a site with no store) returns null instead of a result row; the 18 * runner then omits it entirely — no row, no score effect. Only 19 * checks on the runner's explicit site-conditional list may use 20 * this; a null from any other check is treated as an unreadable 21 * result and surfaces as a warning row, so no check can vanish 22 * silently by accident. 14 23 */ 15 24 … … 18 27 interface Tiba_Check_Interface { 19 28 /** 20 * @return array{id:string,label:string,status:string,message:string,fix:string} 29 * @return array{id:string,label:string,status:string,message:string,fix:string}|null 30 * A result row, or null when the check does not apply to this site. 21 31 */ 22 32 public function run(); -
tibacheck-site-audit/trunk/readme.txt
r3755336 r3757543 5 5 Tested up to: 7.1 6 6 Requires PHP: 7.4 7 Stable tag: 0.1 2.17 Stable tag: 0.13.2 8 8 License: GPLv2 or later 9 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html 10 10 11 Security & health audit in one click: OWASP-mapped security score, backdoor hunt, hidden accounts, plugin review by job. 23 read-only checks.11 One-click security & health audit: OWASP-mapped scores, hidden-account and plugin reviews, 23 read-only checks, plus a WooCommerce store pack. 12 12 13 13 == Description == 14 14 15 TibaCheck runs a read-only audit of your site's configuration and shows you, in plain language, what needs attention. Every report leads with two scores — a **Site Health Score** and a **Security Score** built from checks mapped to the **OWASP Top 10 (202 1)** — with a full OWASP coverage table showing what was assessed and what needs an external deep scan:15 TibaCheck runs a read-only audit of your site's configuration and shows you, in plain language, what needs attention. Every report leads with two scores — a **Site Health Score** and a **Security Score** built from checks mapped to the **OWASP Top 10 (2025)** — with a full OWASP coverage table showing what was assessed and what needs an external deep scan: 16 16 17 17 * **Software updates** — pending WordPress core, plugin, and theme updates (outdated software is the #1 way sites get hacked) … … 41 41 * **Application passwords** — an inventory of the standing credentials that bypass your login screen, with the oldest one's age 42 42 43 Plus the **WooCommerce store pack** — four more checks that appear only when WooCommerce is active, so they never clutter a non-store report. A store that cannot take payment is down in the only way that matters, and these are what a care plan watches on a store every month: 44 45 * **Store pages** — the Checkout page must be assigned and published or customers cannot buy at all (the check fails when it is not); the Cart, Shop, and My Account pages are checked too and warn when broken 46 * **Payment gateways** — at least one gateway must be switched on, read from WooCommerce's own gateway registry so extension gateways count exactly like built-in ones; up to four enabled ones are named 47 * **Store details** — store currency, base country, and street address, the details taxes, shipping, and invoices are calculated from (a currency or country that was never set is flagged with the default WooCommerce silently uses instead) 48 * **Checkout posture** — the silent sales leak: guest checkout off, no account creation during checkout, *and* registration closed on the My Account page too, so only existing account holders can buy. Checkout encryption itself is graded once, by the SSL / HTTPS check, and cross-referenced here — never double-counted 49 43 50 Every report also carries a **Plugins Review** section: every installed plugin grouped by the job it does — backups, security, SEO, speed, forms, builders, store, analytics, spam, media, email, languages, utilities — each with a one-line purpose and its active/inactive state. When two or more *active* plugins share a job, the group is flagged **repetitive** and a Plugin Overlap check warns: duplicates conflict, slow the site, and double what you must keep updated. Plugins we don't recognize are listed honestly as "not yet categorized" — we never guess what a plugin does. 44 51 … … 65 72 66 73 = Is the OWASP score a certification? = 67 No. The Security Score maps this plugin's checks to the OWASP Top 10 (2021) categories they assess, and the coverage table states plainly which categories a plugin cannot assess from inside (injection in custom code, insecure design, SSRF, and others). Those require an external assessment — which is part of the WP Care Plan deep scan.74 No. The Security check score maps this plugin's checks to the OWASP Top 10 (2025) categories they assess, and the coverage table labels every mapped category as partial. A passing check does not establish category-wide security. Injection, insecure design and logging/alerting remain unassessed. The score is a TibaCheck heuristic, not an OWASP certification, and is withheld when mapped evidence is incomplete. Separate code, architecture or dynamic assessment is required. 68 75 69 76 = What do the statuses mean? = … … 72 79 == Screenshots == 73 80 74 1. One-click audit results — Site Health and Security score cards, tabbed Health Check / Security Scan results, and color-coded status pills at a glance. 75 2. Security Scan tab — Health and OWASP-mapped Security scores with the OWASP Top 10 (2021) coverage table: what was assessed, and what needs an external deep scan, stated plainly. 76 3. Plugins Review — every installed plugin grouped by the job it does, with repetitive groups flagged when two or more active plugins do the same job. 77 4. Printable client report — a branded audit document with the score cards, every check and its detail, and the plugin and OWASP summaries, ready to print or save as a PDF for a client. 78 81 1. One-click audit results with color-coded status pills and a summary bar — passing, needs attention, and failing at a glance. 79 82 80 83 == Changelog == 84 85 = 0.13.2 = 86 * Coverage correction: the debug display check now maps to OWASP A10:2025 — Mishandling of Exceptional Conditions (error output shown to visitors is an error-handling failure). Assessed coverage is now 7 of 10 categories; A02 keeps the file editor, uploads code and prepend directive checks. 87 * Fixed the wordpress.org short description being truncated (now within the 150-character limit). 88 89 = 0.13.1 = 90 * Reports use OWASP Top 10:2025 with partial coverage labels, explicit unassessed risks and evidence-completeness safeguards. 91 * Missing or unavailable mapped evidence withholds the security check score; model-versioned snapshots avoid incompatible historical score comparisons. 92 * The printable client report now shares the dashboard coverage table. 93 94 95 = 0.13.0 = 96 * NEW: the **WooCommerce store pack** — four checks that run 97 only when WooCommerce is active (on any other site they do 98 not appear at all): **Store pages** (Cart/Checkout assigned 99 and published, or the store cannot sell — plus Shop and 100 My Account), **Payment gateways** (at least one gateway 101 switched on, read from WooCommerce's own registry so 102 extension gateways count; up to four enabled gateways are 103 named, and an unreadable registry reports "could not 104 confirm" instead of guessing), **Store details** (currency, 105 base country, and street address — what taxes, shipping, 106 and invoices are calculated from), and **Checkout posture** 107 (the guest-checkout/account-creation/registration 108 combination that silently locks out new customers; 109 checkout encryption stays graded once, by the SSL check). 110 The 111 audit now runs twenty-three checks, twenty-seven on a 112 WooCommerce store. 113 * Hidden client reports now set their WordPress admin page titles before the header renders, avoiding blank titles and PHP deprecations. 114 * Missing or malformed update data for any component now remains unknown rather than producing an all-current result; known pending updates remain visible. 81 115 82 116 = 0.12.1 = -
tibacheck-site-audit/trunk/tibacheck.php
r3755283 r3757543 3 3 * Plugin Name: TibaCheck — Site Audit 4 4 * Description: One-click site health and security audit: outdated software, PHP version, inactive plugins, and more. Know what's wrong before it breaks. 5 * Version: 0.1 2.15 * Version: 0.13.2 6 6 * Requires at least: 6.0 7 7 * Requires PHP: 7.4 … … 18 18 defined( 'ABSPATH' ) || exit; 19 19 20 define( 'TIBA_CHECK_VERSION', '0.1 2.1' );20 define( 'TIBA_CHECK_VERSION', '0.13.2' ); 21 21 define( 'TIBA_CHECK_PATH', plugin_dir_path( __FILE__ ) ); 22 22 … … 47 47 require_once TIBA_CHECK_PATH . 'includes/class-plugin-catalog.php'; 48 48 require_once TIBA_CHECK_PATH . 'includes/checks/class-check-plugin-redundancy.php'; 49 require_once TIBA_CHECK_PATH . 'includes/checks/class-check-woo-pages.php'; 50 require_once TIBA_CHECK_PATH . 'includes/checks/class-check-woo-payments.php'; 51 require_once TIBA_CHECK_PATH . 'includes/checks/class-check-woo-details.php'; 52 require_once TIBA_CHECK_PATH . 'includes/checks/class-check-woo-checkout.php'; 49 53 require_once TIBA_CHECK_PATH . 'includes/class-watch.php'; 50 54 … … 81 85 ); 82 86 // Hidden page: the printable client report (see below). 83 add_submenu_page(84 null,87 $report_hook = add_submenu_page( 88 '', 85 89 __( 'Site Audit Report', 'tibacheck-site-audit' ), 86 90 __( 'Site Audit Report', 'tibacheck-site-audit' ), … … 89 93 'tiba_check_render_client_report' 90 94 ); 95 if ( $report_hook ) { 96 add_action( 'load-' . $report_hook, static function () { 97 global $title; 98 $title = __( 'Site Audit Report', 'tibacheck-site-audit' ); 99 } ); 100 } 91 101 } 92 102 add_action( 'admin_menu', 'tiba_check_admin_menu' ); … … 237 247 <div> 238 248 <h1><?php esc_html_e( 'TibaCheck Site Audit', 'tibacheck-site-audit' ); ?></h1> 239 <p class="tibacheck-tagline"><strong><?php esc_html_e( 'Know what\'s wrong before it breaks.', 'tibacheck-site-audit' ); ?></strong> <?php esc_html_e( 'One click runs twenty-three checks — updates, PHP, every plugin grouped by job, backups, accounts, security settings, visibility, bloat, and a backdoor hunt most audits skip. ', 'tibacheck-site-audit' ); ?></p>249 <p class="tibacheck-tagline"><strong><?php esc_html_e( 'Know what\'s wrong before it breaks.', 'tibacheck-site-audit' ); ?></strong> <?php esc_html_e( 'One click runs twenty-three checks — updates, PHP, every plugin grouped by job, backups, accounts, security settings, visibility, bloat, and a backdoor hunt most audits skip. WooCommerce stores get four extra store checks.', 'tibacheck-site-audit' ); ?></p> 240 250 </div> 241 251 </div> … … 289 299 'health' => $scores['health'], 290 300 'security' => $scores['security'], 301 'owasp_version' => $scores['owasp_version'], 291 302 'time' => time(), 292 303 'statuses' => $statuses, … … 329 340 <div class="tibacheck-score"> 330 341 <div class="tibacheck-score-num" style="color:<?php echo esc_attr( $band_color[ Tiba_Check::score_band( $scores['security'] ) ] ); ?>"><?php echo esc_html( $scores['security'] ); ?><span style="font-size:16px;color:#787c82">/100</span></div> 331 <div class="tibacheck-score-label"><?php esc_html_e( 'Security score — OWASP-mapped checks', 'tibacheck-site-audit' ); ?></div>332 <?php if ( is_array( $prev ) && isset( $prev['security'], $prev['time'] ) && null !== $prev['security'] ) : ?>342 <div class="tibacheck-score-label"><?php esc_html_e( 'Security check score — partial coverage', 'tibacheck-site-audit' ); ?></div> 343 <?php if ( is_array( $prev ) && isset( $prev['security'], $prev['time'] ) && null !== $prev['security'] && ( $prev['owasp_version'] ?? '' ) === $scores['owasp_version'] ) : ?> 333 344 <div class="tibacheck-delta"><?php echo esc_html( sprintf( '%+d', $scores['security'] - (int) $prev['security'] ) ); ?> <?php esc_html_e( 'since', 'tibacheck-site-audit' ); ?> <?php echo esc_html( date_i18n( 'M j', (int) $prev['time'] ) ); ?></div> 334 345 <?php endif; ?> … … 352 363 <?php tiba_check_render_checks_table( $tab_rows['security'] ); ?> 353 364 <h3 style="margin:20px 0 6px"><?php esc_html_e( 'OWASP Top 10 coverage', 'tibacheck-site-audit' ); ?></h3> 354 <p class="description" style="margin-bottom:10px"><?php esc_html_e( 'How this audit maps to the OWASP Top 10 (2021). Categories a plugin cannot honestly assess from inside are marked — those are covered by the Care Plan deep scan, an external assessment.', 'tibacheck-site-audit' ); ?></p> 355 <div class="tibacheck-results"> 356 <table class="widefat striped"> 357 <thead><tr> 358 <th><?php esc_html_e( 'Category', 'tibacheck-site-audit' ); ?></th> 359 <th><?php esc_html_e( 'Status', 'tibacheck-site-audit' ); ?></th> 360 <th><?php esc_html_e( 'Basis', 'tibacheck-site-audit' ); ?></th> 361 </tr></thead> 362 <tbody> 363 <?php 364 $owasp_map = Tiba_Check::owasp_map(); 365 $basis = array(); 366 foreach ( $results as $r ) { 367 if ( isset( $owasp_map[ $r['id'] ] ) ) { 368 $basis[ $owasp_map[ $r['id'] ] ][] = $r['label']; 369 } 370 } 371 foreach ( Tiba_Check::owasp_categories() as $code => $name ) : 372 ?> 373 <tr> 374 <td><strong><?php echo esc_html( $code ); ?></strong> — <?php echo esc_html( $name ); ?></td> 375 <?php if ( isset( $scores['owasp'][ $code ] ) ) : ?> 376 <td><span class="tibacheck-pill tibacheck-pill--<?php echo esc_attr( $scores['owasp'][ $code ] ); ?>"><?php echo esc_html( strtoupper( $scores['owasp'][ $code ] ) ); ?></span></td> 377 <td><?php 378 echo esc_html( 379 sprintf( 380 /* translators: %s: comma-separated check names */ 381 __( 'Assessed by: %s', 'tibacheck-site-audit' ), 382 implode( ', ', $basis[ $code ] ) 383 ) 384 ); 385 ?></td> 386 <?php else : ?> 387 <td><span style="color:#787c82"><?php esc_html_e( 'Not assessed', 'tibacheck-site-audit' ); ?></span></td> 388 <td><span style="color:#787c82"><?php esc_html_e( 'Covered by the Care Plan deep scan (external OWASP assessment).', 'tibacheck-site-audit' ); ?></span></td> 389 <?php endif; ?> 390 </tr> 391 <?php endforeach; ?> 392 </tbody> 393 </table> 394 </div> 365 <p class="description" style="margin-bottom:10px"><?php esc_html_e( 'OWASP Top 10 (2025): mapped checks provide partial coverage only. A passed check does not establish that a category or site is secure. The security score is a TibaCheck heuristic, not an OWASP score or certification; it is unavailable when mapped evidence is incomplete. Unassessed risks require a separate code, architecture or dynamic assessment.', 'tibacheck-site-audit' ); ?></p> 366 <?php tiba_check_render_owasp_coverage( $results, $scores ); ?> 395 367 </div> 396 368 <div class="tibacheck-panel tibacheck-panel--plugins"> … … 500 472 <div class="tcr-card"><div class="n"><?php echo esc_html( $scores['health'] ); ?>/100</div><div class="l"><?php esc_html_e( 'Site health score', 'tibacheck-site-audit' ); ?></div></div> 501 473 <?php if ( null !== $scores['security'] ) : ?> 502 <div class="tcr-card"><div class="n"><?php echo esc_html( $scores['security'] ); ?>/100</div><div class="l"><?php esc_html_e( 'Security score (OWASP-mapped)', 'tibacheck-site-audit' ); ?></div></div>474 <div class="tcr-card"><div class="n"><?php echo esc_html( $scores['security'] ); ?>/100</div><div class="l"><?php esc_html_e( 'Security check score (partial coverage)', 'tibacheck-site-audit' ); ?></div></div> 503 475 <?php endif; ?> 504 476 <div class="tcr-card"><div class="n"><?php echo esc_html( count( $results ) ); ?></div><div class="l"><?php esc_html_e( 'Checks run', 'tibacheck-site-audit' ); ?></div></div> … … 556 528 sprintf( 557 529 /* translators: %s: comma-separated OWASP category list */ 558 __( 'The security checks map to these OWASP Top 10 (202 1) categories: %s. The remaining categories need authenticated or dynamic testing, which a read-only audit does not perform.', 'tibacheck-site-audit' ),530 __( 'The security checks map to these OWASP Top 10 (2025) categories: %s. Coverage is partial in every mapped category. Passing checks do not establish category-wide security; unassessed risks require a separate code, architecture or dynamic assessment.', 'tibacheck-site-audit' ), 559 531 implode( ', ', $names ) 560 532 ) 561 533 ); 562 534 ?></p> 535 <p><?php esc_html_e( 'The security score is a TibaCheck heuristic, not an OWASP score or certification. It is unavailable when mapped evidence is incomplete.', 'tibacheck-site-audit' ); ?></p> 536 <?php tiba_check_render_owasp_coverage( $results, $scores ); ?> 563 537 <h2><?php esc_html_e( '5. Scope and method', 'tibacheck-site-audit' ); ?></h2> 564 <p><?php esc_html_e( 'TibaCheck runs twenty-three read-only checks over updates, PHP, accounts, security settings, backups, site bloat, and persistence mechanisms that planted backdoors rely on. It changes nothing on the site, makes no external requests, and stores only the audit scores, per-check statuses, time, any pending weekly Watch change alert, and the time of the last automatic Watch run. This report was generated fresh when it was opened.', 'tibacheck-site-audit' ); ?></p>538 <p><?php esc_html_e( 'TibaCheck runs twenty-three read-only checks over updates, PHP, accounts, security settings, backups, site bloat, and persistence mechanisms that planted backdoors rely on. On a WooCommerce store it runs four more — store pages, payment gateways, store details, and checkout posture. It changes nothing on the site, makes no external requests, and stores only the audit scores, per-check statuses, time, any pending weekly Watch change alert, and the time of the last automatic Watch run. This report was generated fresh when it was opened.', 'tibacheck-site-audit' ); ?></p> 565 539 <h2><?php esc_html_e( '6. Recommended next steps', 'tibacheck-site-audit' ); ?></h2> 566 540 <p><?php esc_html_e( 'Items needing attention are a work list, not a verdict: fix them directly, or have them handled. TibaCheck care plans watch every one of these checks monthly — updates, backups, accounts, and the backdoor hunt — and send a report like this one each month.', 'tibacheck-site-audit' ); ?></p> … … 571 545 <?php 572 546 } 547 548 /** Shared free dashboard/print coverage; caller supplies the same audit snapshot. */ 549 function tiba_check_render_owasp_coverage( $results, $scores ) { 550 ?> 551 <div class="tibacheck-results"> 552 <table class="widefat striped"> 553 <thead><tr> 554 <th><?php esc_html_e( 'Category', 'tibacheck-site-audit' ); ?></th> 555 <th><?php esc_html_e( 'Status', 'tibacheck-site-audit' ); ?></th> 556 <th><?php esc_html_e( 'Basis', 'tibacheck-site-audit' ); ?></th> 557 </tr></thead> 558 <tbody> 559 <?php 560 $owasp_map = Tiba_Check::owasp_map(); 561 $basis = array(); 562 foreach ( $results as $r ) { 563 if ( isset( $owasp_map[ $r['id'] ] ) ) { 564 $basis[ $owasp_map[ $r['id'] ] ][] = $r['label']; 565 } 566 } 567 foreach ( Tiba_Check::owasp_categories() as $code => $name ) : 568 ?> 569 <tr> 570 <td><strong><?php echo esc_html( $code ); ?></strong> — <?php echo esc_html( $name ); ?></td> 571 <?php if ( isset( $scores['owasp'][ $code ] ) ) : ?> 572 <td><span class="tibacheck-pill tibacheck-pill--<?php echo esc_attr( $scores['owasp'][ $code ] ); ?>"><?php echo esc_html( Tiba_Check::owasp_status_label( $scores['owasp'][ $code ] ) ); ?></span></td> 573 <td><?php 574 echo esc_html( 575 sprintf( 576 /* translators: %s: comma-separated check names */ 577 __( 'Limited checks: %s', 'tibacheck-site-audit' ), 578 implode( ', ', $basis[ $code ] ?? array( __( 'No usable mapped check results.', 'tibacheck-site-audit' ) ) ) 579 ) 580 ); 581 ?></td> 582 <?php else : ?> 583 <td><span style="color:#787c82"><?php esc_html_e( 'Not assessed', 'tibacheck-site-audit' ); ?></span></td> 584 <td><span style="color:#787c82"><?php esc_html_e( 'Requires a separate code, architecture or dynamic assessment.', 'tibacheck-site-audit' ); ?></span></td> 585 <?php endif; ?> 586 </tr> 587 <?php endforeach; ?> 588 </tbody> 589 </table> 590 </div> 591 <?php 592 }
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)