Hacker

Name:
Portfolio Notification: +2.5 BTC detected. View now > https://graph.org/GRAB-FREE-BTC-07-23?hs=69785e075126563e9d17b7c6e94c5963&

Email:
[email protected]

Phone:
274301069610

How did you hear about us?
Friend or family

Other details:
fyumro

How can I lock it down to prevent this? I am already running Cloudflare Turnstile..?

Yeah-this is spam. Classic Telegraph/graph.org boiler-room lure wrapped in a Jetpack Form submission.

Here’s the quick read, then the fixes.

Why it’s spam (no sugar-coat)

  • Graph.org link with “FREE BTC” + tracking hs= param textbook funnel to a fake “wallet unlock / KYC / deposit” trap.
  • Throwaway email (dmxs8.com) disposable domain behaviour.
  • Nonsense payload (“fyumro”), vague “Friend or family”, random phone automated form filler.
  • IP 162.158.159.34 Cloudflare edge, not a real origin; you can’t meaningfully block it.

What to do now (2-minute cleanup)

  1. Mark as spam in Jetpack (it trains the filter).
  2. Do not click the link; don’t test it in a normal browser profile.

Harden your form (quick wins first)

A) Block obvious patterns at WordPress level (no plugin swap)

  • Discussion Disallowed Comment Keys (works for Jetpack Feedback too). Add these lines (one per line): graph.org telegraph t.me free btc 0.7 btc hs= bitcoin deposit Anything containing these gets auto-trashed on submit.
  • Drop posts with bad keywords via Jetpack hook (put in a small μ-plugin): <?php /* Plugin Name: Jetpack Contact Hard Blocks */ add_filter('jetpack_contact_form_is_spam', function ($is_spam, $form, $message) { // $message is an array of field => value $blob = strtolower(implode(' ', array_map('strval', $message))); $bad = '/\b(graph\.org|telegraph|t\.me|free\s*btc|bitcoin\s*deposit|http[s]?:\/\/[^ ]+hs=)\b/i'; if (preg_match($bad, $blob)) return true; return $is_spam; }, 10, 3); This silently bins anything with those strings before it hits your inbox.
  • Strip hyperlinks before store/send (optional, but reduces bait): add_filter('grunion_contact_form_field_html', function($html){ return preg_replace('#https?://\S+#i', '[link removed]', $html); });

B) Turn on an anti-spam engine

  • Jetpack Anti-spam (Akismet): if you’re not already using it, enable it-Jetpack Forms can use the Akismet brain.
  • If you prefer free: Antispam Bee helps for comments; for forms, the Jetpack hook above does the heavy lift.

C) Add a stealth honeypot + timing check

Bots don’t wait.

// Add a hidden field via render (change 'your_form_id' to match if needed).
add_action('wp_footer', function () {
    if (!is_page()) return;
    ?>
    <script>
      document.addEventListener('DOMContentLoaded', () => {
        const hp = document.createElement('input');
        hp.type = 'text'; hp.name = 'website'; hp.style.display='none';
        const forms = document.querySelectorAll('form.contact-form');
        forms.forEach(f => {
          f.appendChild(hp.cloneNode());
          const ts = document.createElement('input');
          ts.type='hidden'; ts.name='ts'; ts.value=Date.now();
          f.appendChild(ts);
        });
      });
    </script>
    <?php
});
// Reject if honeypot filled or submit too fast (<3s)
add_filter('jetpack_contact_form_is_spam', function ($is_spam) {
    $hp = isset($_POST['website']) && $_POST['website'] !== '';
    $fast = isset($_POST['ts']) && (time()*1000 - intval($_POST['ts'])) < 3000;
    return $is_spam || $hp || $fast;
}, 9, 1);

D) Cloudflare WAF: challenge the campaign, not humans

Create a rule (Security WAF Custom Rules):

  • Expression: (http.request.body contains "graph.org" or http.request.body contains "telegraph" or http.request.body contains "free btc" or http.request.body contains "hs=") and http.request.uri contains "/"
  • Action: Managed Challenge. This stings headless/post bots without annoying legit users much.

(If you’re using Cloudflare Turnstile, consider moving your contact form to a form plugin that supports it; Jetpack’s own form doesn’t natively integrate.)

Inbox triage (save your time)

  • Add a mail rule: if body contains graph.org or free btc delete or label “Scam Auto”.
  • Keep training Jetpack/Akismet by marking as spam-your future self will thank you.

SEO note (forward-looking)

These lures sometimes spray links at scale. Blocking the token patterns (hs= + graph.org) reduces your site’s risk of being used as a link amplifier in logs/emails-which keeps your domain reputation cleaner over time.

If you want, I can tailor the WAF expression to your exact Jetpack endpoint and add a few more high-signal phrases you’ve seen in your queue.

I am already running Cloudflare Turnstile – How is this Getting By?

If you have already enabled Turnstile on your Jetpack form under wp-admin\settings:

Screenshot-2025-08-15-080843 Jetpack Form Spam

If you’re already running Cloudflare Turnstile and this still got through, then one of three things is happening – and I’d bet on #2:

1. Turnstile isn’t actually protecting the Jetpack form submission

Turnstile only blocks bots that have to render and complete the protected form in the browser. If your Jetpack form endpoint (the admin-ajax.php or ?contact-form-id=xxx POST target) isn’t wrapped in Turnstile validation, a bot can post directly to it without ever seeing your form page. Many WP contact form plugins-including Jetpack’s-don’t have built-in Turnstile hooks, so unless you explicitly coded it in, it’s not checking the Turnstile token server-side.

2. The spam isn’t coming through your browser form at all – it’s hitting Jetpack’s servers directly

  • Jetpack forms are processed by Automattic’s backend, not just your WP site.
  • A bot can submit via Jetpack’s API using your site’s form ID – bypassing your Turnstile completely, because the traffic never touches your HTML page.
  • That’s why you can still get spam with Akismet disabled and a captcha in place – the spammer is essentially “spoofing” a form POST straight to Jetpack’s processor.

3. Human-assisted or semi-automated spam

  • Some campaigns use cheap human click-farms. They can solve Turnstile as easily as reCAPTCHA.
  • But in this case the random gibberish “fyumro” field + BTC bait smells 100% like automated API hits, not a farm.

How to block it

If you want Turnstile to actually block Jetpack spam, you need server-side enforcement. That means:

Option A – Verify Turnstile before Jetpack processes

You can hook into jetpack_contact_form_is_spam and reject if the Turnstile token doesn’t validate:

add_filter('jetpack_contact_form_is_spam', function ($is_spam) {
    if ($is_spam) return true;
    if (empty($_POST['cf_turnstile_token'])) return true;

<pre><code>$resp = wp_remote_post(&amp;#39;https://challenges.cloudflare.com/turnstile/v0/siteverify&amp;#39;, [
    &amp;#39;body&amp;#39; =&amp;gt; [
        &amp;#39;secret&amp;#39; =&amp;gt; &amp;#39;YOUR_TURNSTILE_SECRET_KEY&amp;#39;,
        &amp;#39;response&amp;#39; =&amp;gt; sanitize_text_field($_POST[&amp;#39;cf_turnstile_token&amp;#39;]),
        &amp;#39;remoteip&amp;#39; =&amp;gt; $_SERVER[&amp;#39;REMOTE_ADDR&amp;#39;] ?? &amp;#39;&amp;#39;,
    ],
]);
$data = json_decode(wp_remote_retrieve_body($resp), true);
return empty($data[&amp;#39;success&amp;#39;]);
</code></pre>
<p>});

…but you’d also need to add the token field to the Jetpack form HTML, which means overriding its form template.


Option B – Block at Cloudflare WAF

Since Jetpack spam never hits your HTML form, Turnstile can’t help, but WAF can. Add a Cloudflare rule:

(http.request.body contains &quot;graph.org&quot; or
 http.request.body contains &quot;free btc&quot; or
 http.request.body contains &quot;hs=&quot;)

Action: Block or Managed Challenge Apply to: POST requests


Option C – Stop using Jetpack forms for anything public

Switch to a form plugin that:

  • Processes submissions locally on your server (not via Jetpack’s cloud API)
  • Has native Turnstile integration (e.g. Fluent Forms, Gravity Forms, WPForms)

I See. The Centralization Model of Jetpack is Hurting Me

Yep. Jetpack’s “send it through our cloud” convenience is exactly what’s letting bots sidestep your Turnstile. If you want fewer rotten apples in the crate, de-centralize the form path.

Here’s a clean, staged way forward-quick patch durable fix future-proofing. No fluff.

0) Immediate tourniquet (15-30 min)

A. Block the campaign at Cloudflare (POST body match)

  • Security WAF Custom rules Create
  • Expression: (http.request.method eq &quot;POST&quot;) and (http.request.body contains &quot;graph.org&quot; or http.request.body contains &quot;telegraph&quot; or http.request.body contains &quot;free btc&quot; or http.request.body contains &quot;hs=&quot;)
  • Action: Managed Challenge (or Block if you’re confident).
  • Scope: your whole zone, or narrow to http.request.uri.path contains "/wp-admin/admin-ajax.php" and "/?contact-form-id=" if you prefer.

B. Hard-block in WordPress before Jetpack stores/sends Drop this as a tiny μ-plugin (/wp-content/μ-plugins/jetpack-hard-blocks.php):

&lt;?php
/*
 Plugin Name: Jetpack Contact Hard Blocks
*/
add_filter(&#39;jetpack_contact_form_is_spam&#39;, function ($is_spam, $form, $message) {
    if ($is_spam) return true;
    $blob = strtolower(implode(&#39; &#39;, array_map(&#39;strval&#39;, $message)));
    if (preg_match(&#39;/\b(graph\.org|telegraph|t\.me|free\s*btc|bitcoin\s*deposit|hs=)\b/i&#39;, $blob)) return true;
    return false;
}, 10, 3);

1) Durable fix (this week)

Pick one of these and be done with it:

Option A – Keep Jetpack, enforce Turnstile server-side

You must both render a Turnstile token and verify it in PHP.

Render token (enqueue on pages with your Jetpack form):

add_action(&#39;wp_enqueue_scripts&#39;, function(){
  wp_enqueue_script(&#39;cf-turnstile&#39;, &#39;https://challenges.cloudflare.com/turnstile/v0/api.js&#39;, [], null, true);
});
add_action(&#39;wp_footer&#39;, function(){
  ?&gt;
  &lt;script&gt;
    document.addEventListener(&#39;DOMContentLoaded&#39;, () =&gt; {
      document.querySelectorAll(&#39;form.contact-form&#39;).forEach(f =&gt; {
        const div = document.createElement(&#39;div&#39;);
        div.className = &quot;cf-turnstile&quot;;
        div.setAttribute(&#39;data-sitekey&#39;,&#39;YOUR_TURNSTILE_SITE_KEY&#39;);
        f.insertBefore(div, f.querySelector(&#39;input[type=&quot;submit&quot;]&#39;));
        turnstile.render(div, { sitekey: &#39;YOUR_TURNSTILE_SITE_KEY&#39; });
      });
    });
  &lt;/script&gt;
  &lt;?php
});

Verify token before Jetpack accepts:

add_filter(&#39;jetpack_contact_form_is_spam&#39;, function ($is_spam) {
  if ($is_spam) return true;
  $token = $_POST[&#39;cf-turnstile-response&#39;] ?? $_POST[&#39;cf_turnstile_token&#39;] ?? &#39;&#39;;
  if (!$token) return true; // no token = reject
  $resp = wp_remote_post(&#39;https://challenges.cloudflare.com/turnstile/v0/siteverify&#39;, [
      &#39;body&#39; =&gt; [
          &#39;secret&#39; =&gt; &#39;YOUR_TURNSTILE_SECRET_KEY&#39;,
          &#39;response&#39; =&gt; sanitize_text_field($token),
          &#39;remoteip&#39; =&gt; $_SERVER[&#39;REMOTE_ADDR&#39;] ?? &#39;&#39;,
      ],
      &#39;timeout&#39; =&gt; 5,
  ]);
  if (is_wp_error($resp)) return true;
  $ok = json_decode(wp_remote_retrieve_body($resp), true)[&#39;success&#39;] ?? false;
  return !$ok;
}, 5);

This closes the “post straight to Jetpack without passing Turnstile” hole.

Option B – Ditch Jetpack Forms for a local processor with native Turnstile

  • Good fits: Fluent Forms, Gravity Forms, WPForms (all support Turnstile out of the box).
  • Benefit: request never leaves your server; Turnstile is first-class and validated server-side.
  • Migration: recreate the fields, set the same notifications, add Turnstile in the form builder, remove/disable Jetpack Contact Form module: add_filter(&#39;jetpack_active_modules&#39;, function($mods){ return array_diff($mods, [&#39;contact-form&#39;]); });
  • Optional: redirect old contact URLs to the new page.

2) Extras that keep the garden tidy

  • Honeypot + min submit time (works regardless of provider-bots don’t wait): add_action(&#39;wp_footer&#39;, function(){ ?&gt; &lt;script&gt; document.addEventListener(&#39;DOMContentLoaded&#39;, () =&gt; { document.querySelectorAll(&#39;form.contact-form&#39;).forEach(f=&gt;{ const hp=document.createElement(&#39;input&#39;); hp.type=&#39;text&#39;; hp.name=&#39;website&#39;; hp.style.display=&#39;none&#39;; f.appendChild(hp); const ts=document.createElement(&#39;input&#39;); ts.type=&#39;hidden&#39;; ts.name=&#39;ts&#39;; ts.value=Date.now(); f.appendChild(ts); }); }); &lt;/script&gt; &lt;?php }); add_filter(&#39;jetpack_contact_form_is_spam&#39;, function($is_spam){ $hp = !empty($_POST[&#39;website&#39;]); $fast = isset($_POST[&#39;ts&#39;]) &amp;&amp; (time()*1000 - (int)$_POST[&#39;ts&#39;]) &lt; 3000; return $is_spam || $hp || $fast; }, 6);
  • Cloudflare Rate Limiting: throttle /wp-admin/admin-ajax.php POST bursts from same ASN.
  • Mail rule: auto-trash emails where body contains graph.org or hs=.

3) The why (so you can sleep at night)

  • Turnstile is a client puzzle; it only works if you check its server receipt before accepting data.
  • Jetpack’s centralized processing is convenient but gives bots another door; closing it means either validating Turnstile in a hook before Jetpack stores/sends-or avoiding Jetpack’s pipeline altogether.

Share this content:

Leave a Reply

Your email address will not be published. Required fields are marked *