Skip to content

CRM: Improve string sanitization and escaping#48390

Merged
tbradsha merged 21 commits intotrunkfrom
fix/crm/harden_admin_rendering
May 4, 2026
Merged

CRM: Improve string sanitization and escaping#48390
tbradsha merged 21 commits intotrunkfrom
fix/crm/harden_admin_rendering

Conversation

@tbradsha
Copy link
Copy Markdown
Contributor

Proposed changes

This improves string sanitization and escaping.

Related product discussion/links

  • pgvhYc-BV-p2#comment-666
  • pgvhYc-BV-p2#comment-667

Does this pull request change what data or activity we track or use?

Testing instructions

  • Go to '..'

@tbradsha tbradsha requested a review from a team April 29, 2026 17:56
@tbradsha tbradsha self-assigned this Apr 29, 2026
@tbradsha tbradsha added the [Status] Needs Review This PR is ready for review. label Apr 29, 2026
@github-actions
Copy link
Copy Markdown
Contributor

Thank you for your PR!

When contributing to Jetpack, we have a few suggestions that can help us test and review your patch:

  • ✅ Include a description of your PR changes.
  • ✅ Add a "[Status]" label (In Progress, Needs Review, ...).
  • ✅ Add testing instructions.
  • ✅ Specify whether this PR includes any changes to data or privacy.
  • ✅ Add changelog entries to affected projects

This comment will be updated as you work on your PR and make changes. If you think that some of those checks are not needed for your PR, please explain why you think so. Thanks for cooperation 🤖


Follow this PR Review Process:

  1. Ensure all required checks appearing at the bottom of this PR are passing.
  2. Make sure to test your changes on all platforms that it applies to. You're responsible for the quality of the code you ship.
  3. You can use GitHub's Reviewers functionality to request a review.
  4. When it's reviewed and merged, you will be pinged in Slack to deploy the changes to WordPress.com simple once the build is done.

If you have questions about anything, reach out in #jetpack-developers for guidance!

@jp-launch-control
Copy link
Copy Markdown

jp-launch-control Bot commented Apr 29, 2026

Code Coverage Summary

Coverage changed in 6 files. Only the first 5 are listed here.

File Coverage Δ% Δ Uncovered
projects/plugins/crm/modules/woo-sync/includes/class-woo-sync-my-account-integration.php 0/290 (0.00%) 0.00% 2 ❤️‍🩹
projects/plugins/crm/admin/settings/client-portal.page.php 0/230 (0.00%) 0.00% 1 ❤️‍🩹
projects/plugins/crm/admin/settings/locale.page.php 0/209 (0.00%) 0.00% 1 ❤️‍🩹
projects/plugins/crm/admin/settings/mail.page.php 0/123 (0.00%) 0.00% 1 ❤️‍🩹
projects/plugins/crm/modules/portal/class-client-portal-render-helper.php 0/58 (0.00%) 0.00% -1 💚

Full summary · PHP report

if ( SHOW_FUNNEL_LEGEND ) {
funnel_html += '<br>' + legend_html;
}
funnel_element.innerHTML = funnel_html + '<br>';
Copy link
Copy Markdown
Contributor

@anomiex anomiex Apr 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even better would be to construct the contents using DOM functions instead of assigning innerHTML. But the above seems to cover everything.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally I prefer innerHTML (less verbose and more performant), but a refactor would be out of scope here.

@@ -767,7 +767,7 @@ function zeroBSCRMJS_validateSettings() {
resHTML =
window.zeroBSCRMJS_globViewLang( 'settingsValidatedSMTP' ) +
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be escaped too?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'<div class="email-avatar avatar-' +
jpcrm.esc_attr( v.in_or_out ) +
'">' +
v.avatar +
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is v.avatar sanitized server-side too?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

billTo +
jpcrm.esc_attr( billTo ) +
'" placeholder="' +
zbscrm_JS_invoice_lang( 'bill_to' ) +
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be escaped too? If so, I see a lot of them in this file.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

break;
case 'email':
$new_contact_data['email'] = $v;
$new_contact_data['email'] = sanitize_text_field( $v );
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you're going to use WordPress's "sanitize" functions, this should probably be

Suggested change
$new_contact_data['email'] = sanitize_text_field( $v );
$new_contact_data['email'] = sanitize_email( $v );

Same everywhere else you process email addresses.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@github-actions github-actions Bot added [CRM] API Admin Page React-powered dashboard under the Jetpack menu labels May 1, 2026
title: window.zeroBSCRMJS_globViewLang( 'deleteMailDeliverySureTitle' ),
text: window.zeroBSCRMJS_globViewLang( 'deleteMailDeliverySureText' ),
title: jpcrm.esc_html( window.zeroBSCRMJS_globViewLang( 'deleteMailDeliverySureTitle' ) ),
text: jpcrm.esc_html( window.zeroBSCRMJS_globViewLang( 'deleteMailDeliverySureText' ) ),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like using text rather than html doesn't need escaping.

Looks like there's also titleText to use instead of title to do the same for that field.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like using text rather than html doesn't need escaping.

Can you clarify what you mean by that? If you mean jQuery's text(), I did switch to that several places in this branch.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, in the SweetAlert params, I suppose.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is about the sweetalert2 things (function swal()). https://sweetalert2.github.io/#configuration

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: window.zeroBSCRMJS_globViewLang( 'deleteMailDeliverySureConfirm' ),
confirmButtonText: jpcrm.esc_html(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oddly, despite the name, confirmButtonText appears to take HTML and so still probably needs escaping.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

e.preventDefault();
var image = wp.media({
title: '<?php esc_html_e( 'Upload Image', 'zero-bs-crm' ); ?>',
titleText: '<?php esc_html_e( 'Upload Image', 'zero-bs-crm' ); ?>',
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably drop the esc_html then. And really, probably switch to json_encode() for outputting the string to JS.

OTOH, in practice it probably doesn't much matter, because "Upload Image" or any reasonable translation is unlikely to wind up with characters that get encoded as HTML entities anyway. I see some below that were already passing esc_html to text: and no one has noticed.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I introduced a bug here (it's wp.media(), not swal()). Fixed (along with escape) in a58bfab.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Properly escaped swal() instances here: 644ef0f

);
swal( {
titleText: 'Twilio Extension Needed!',
text: 'To SMS your contacts you need the <a target="_blank" style="font-weight:900;text-decoration:underline;" href="https://jetpackcrm.com/extension-bundles/">Twilio extension</a> (included in our Entrepreneurs Bundle)',
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one would need to stay as html, there's an HTML link in there.

On the plus side, this is the only one I saw like this. 🙂

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, not sure how I missed that one. It's a literal string, so should be safe to leave as unescaped at this stage: 38367c7

html: '<div>' + zeroBSCRMJS_listViewLang( 'acceptareyousurequotes' ) + '</div>',
titleText: zeroBSCRMJS_listViewLang( 'areyousure' ),
html:
'<div>' + jpcrm.esc_html( zeroBSCRMJS_listViewLang( 'acceptareyousurequotes' ) ) + '</div>',
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder why this wraps it in a div while most others don't.

anomiex
anomiex previously approved these changes May 4, 2026
Copy link
Copy Markdown
Contributor

@anomiex anomiex left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks reasonable; I'm not too worried about the other two comments when there's so much existing debt already.

Copy link
Copy Markdown
Contributor

@anomiex anomiex left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quick, let's merge before we see more stuff that needs fixing! 😅

@tbradsha tbradsha merged commit e49a400 into trunk May 4, 2026
72 checks passed
@tbradsha tbradsha deleted the fix/crm/harden_admin_rendering branch May 4, 2026 18:47
@github-actions github-actions Bot removed the [Status] Needs Review This PR is ready for review. label May 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants