Skip to content

Disclose external services and remove ip-api.com lookup - #165

Closed
alimuzzaman wants to merge 2 commits into
masterfrom
fix/164-external-services
Closed

alimuzzaman wants to merge 2 commits into
masterfrom
fix/164-external-services

Conversation

@alimuzzaman

Copy link
Copy Markdown
Member

Summary

Closes the WordPress.org Guidelines 6/7 disclosure gap reported in #164. The opt-in usage tracker sent the admin's IP to ip-api.com over plain HTTP, and neither the readme nor the opt-in notice mentioned it or the WPInsight endpoint.

Changes

  • Remove the ip-api.com lookup from the tracker's first send. Its result only filled a country field in the WPInsight report. Nothing in the plugin reads that field, and the report already went out without it whenever the lookup failed or the IP was 127.0.0.1.
  • Add an == External services == section to readme.txt for WPInsight (send.wpinsight.com). It covers what is sent, when (opt-in only: on consent, about daily by cron with only changed fields, and on deactivation), and links the Terms and Privacy Policy.
  • Rewrite the opt-in notice to name the host and every field the tracker sends. That includes the current admin's account email, the plugin's server path, the deactivation reason and note, and the server IP the service sees. One translatable string with placeholders and a translators comment, rendered through the existing wp_kses_post().
  • New smoke Scenario 23 (tests/smoke/scenario-external-services.php) intercepts every tracker request. It checks:
    • nothing is sent before consent, on both the cron path and the deactivation path;
    • after consent, only https://send.wpinsight.com is contacted;
    • the deactivation report carries the reason, note and email the readme discloses;
    • the shipped code has no http:// remote call;
    • the notice and readme disclose the service.

Outbound hosts swept in shipped PHP and JS: only send.wpinsight.com and the removed ip-api.com. The theme conflict scanner requests the site's own pages, and the readme says so.

Verification

Head: 146c67f2d78e92f71535a84a9482997850a6eafe

  • Scenario 23 against the old code (99728ee): 12 failures, including a real http://ip-api.com/json/… request.
  • Live WordPress smoke, PHP 8.4: all scenarios passed (761 PASS, 0 FAIL).
  • PHP syntax: 7.4 and 8.5 passed locally; 5.6 left to PR Checks.
  • An independent code review was run. Its findings on the email wording and on test cleanup were fixed in the second commit.

Review note

This changes what personal data the plugin discloses and sends: admin email, server IP and site details. Human review is required before merge.

Open items:

  • wpinsight.com does not name its operator. Calling it WPDeveloper's service, and linking wpdeveloper.com's Terms and Privacy Policy, comes from this plugin's own links and other WPDeveloper plugins. Please confirm those policies cover WPInsight.
  • No changelog line yet; it usually arrives with the release sync.
  • languages/disable-comments.pot still holds the old notice string until the release build regenerates it.
  • WordPress.org compliance audit: usage tracker and ip-api lookup not disclosed in readme #164's Definition of Done also asks for a Plugin Check run against the built zip, which has not been done yet.

Refs #164

🤖 Generated with Claude Code

alimuzzaman and others added 2 commits October 12, 2026 13:51
The opt-in usage tracker looked up the requesting admin's IP at
ip-api.com over plain HTTP on its first send, and neither the readme
nor the opt-in notice mentioned it. The country it returned was only
forwarded to WPInsight, which already tolerates reports without one,
so the lookup is removed rather than moved to HTTPS.

- readme.txt: add an External services section for WPInsight
  (send.wpinsight.com): what is sent, when, and the Terms and Privacy
  links.
- Opt-in notice now lists every field the tracker sends, the host, the
  deactivation feedback and the server IP, with a Privacy Policy link.
- Smoke scenario 23 intercepts the tracker's requests and checks
  nothing goes out before consent, only send.wpinsight.com over HTTPS
  after it, and that the notice and readme disclose it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The admin email is read from the current user on every send, so the
daily cron report carries none and the deactivation report carries the
email of whoever deactivates. Say so in the readme and the notice, add
text direction to the notice, and note that daily reports send only
changed fields.

The smoke scenario now also covers the deactivation report (nothing
without consent, then the reason, note and email it discloses), removes
the payload the stubbed send stores, restores wpins_block_notice, and
skips in-repo sandboxes in its source scan.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@alimuzzaman alimuzzaman added the Ready For Testing Ready for QA testing label Oct 12, 2026
@ShahrearMSf

ShahrearMSf commented Oct 12, 2026 •

Copy link
Copy Markdown

❌ Heads-up @alim (Tufan) bhai on disable-comments PR #165 (the #164 external-services / ip-api.com disclosure fix)

It's opened on the public repo (WPDevelopers/disable-comments → master), but our dev flow for Disable Comments is agent-ready → dev, with public being sync-only (dev → public on release, internal files stripped).

The catch 👉 the fix currently lives only on public. agent-ready/dev still has the ip-api.com HTTP call, no == External services == section, and no Scenario 23. So the next dev → public sync will overwrite #165 and re-introduce the issue — the #164 fix would silently disappear.

✅ Fix: Please land this in agent-ready dev (re-do it as a PR there, or mirror #165 across) so it ships durably and survives the sync.

What has been verified

Reviewed and verified — a solid, correct fix for #164. I checked the claims independently rather than taking them on trust. ✅

Verified

  • ip-api.com removal is safe — swept the whole shipped tree: country is referenced nowhere, so dropping $body['country'] loses nothing client-side (and, as noted, the report already went out without it whenever the lookup failed or the IP was local). The removed guard also had a latent precedence bug (! empty( $_SERVER['REMOTE_ADDR'] && … )), so good riddance.
  • External-service sweep is complete — the only outbound remote calls in shipped PHP/JS are send.wpinsight.com (tracker, API_URL = https://send.wpinsight.com/process-plugin-data, HTTPS) and the theme scanner's wp_remote_get to the site's own pages; the admin JS jQuery.ajax targets admin-ajax. The other hosts that show up (wpdeveloper.com, youtu.be) are UI/readme links, and sweetalert2.github.io/pagination.js.org are bundled-library source comments — not calls. Matches the readme.
  • Disclosure matches reality — deactivation attaches $current_user->user_email (the deactivating admin, as the readme says) plus reason + note; email is guarded by is_email() and the marketing flag.
  • Escaping is fine — the notice renders through wp_kses_post() and the Privacy-Policy URL is esc_url()'d before sprintf.
  • Tests — ran the suite on 146c67f: 761 PASS / 0 FAIL, and Scenario 23 is genuinely adversarial (nothing before consent on both the cron and deactivation paths, a host allow-list, HTTPS-only, notice + readme field coverage, the deactivation payload, and a shipped-tree http:///ip-api.com grep). Nice to have it guarding the disclosure going forward.

Minor notes (non-blocking)

  1. Email on the daily send — email is attached in get_data() whenever $this->marketing is set and there's a logged-in admin with a valid email. On pure WP-Cron there's no user, so it's omitted (correct). But if a "daily" send ever fires during an admin page load, that admin's email could ride along too. The readme ties email to "the admin who clicks opt-in" / "who deactivates" — worth a one-line tweak if you want it airtight, or just confirm cron is the only daily path.
  2. UX — the opt-in notice is now one long paragraph. Justified for a disclosure, but it's a sizeable admin notice; flagging, no change needed.
  3. Your own open items still stand and are the main gates: confirm wpdeveloper.com's Terms/Privacy actually cover WPInsight, the .pot/changelog land at release build, and — part of WordPress.org compliance audit: usage tracker and ip-api lookup not disclosed in readme #164's DoD — Plugin Check against the built zip hasn't been run yet. Worth doing before merge since this touches the shipped readme and a privacy-sensitive path.

Net: the compliance gap is genuinely closed and well-guarded. 👍

@alimuzzaman alimuzzaman removed the Ready For Testing Ready for QA testing label Oct 12, 2026
@alimuzzaman

Copy link
Copy Markdown
Member Author

Closing: this repo is the public mirror, and the next release sync would overwrite this change. The same fix for #164 is going through the development repo and will land here with the next release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants