~/blog/event-plugin-nonces-in-frontend-htmlPOSTED
by Shady Nathan Tawfik · September 12, 2026 · 4 min

A Nonce In The Page Is Not A Secret, And The Plugin Knew It

A business innovation network ran a patched content platform with fourteen findings. The interesting one was a feature left switched on that published its own request tokens in the page source.

Interactive[blog-2.0]

TL;DR: A nonce in the page is not a secret, and the plugin knew it: a dormant submission feature published its request tokens and made the upload endpoint reachable by reading the page source. I show the durable fix — removal.

The scenario

I ran this as a black-box review: no credentials, only the publicly visible surface. Here is what I saw before I touched anything.

A business innovation network with a public event calendar, newsletter integration and a caching layer, on a fully patched content platform. Assessment covered plugin configuration, third-party script integrity, mail authentication, header policy and user enumeration.

I removed all identifying information. The target is described only by sector and technology class so the pattern can be reused.

The pattern

The pattern I recognised — and that I keep finding in similar estates:

A request token is a good design. The next question is where it lives. Nonces are designed to be handed to the browser and returned with the request, because the browser has to prove it is the one that loaded the form. That means the value is in the page source by design, which is fine as long as it is bound to a session and expires quickly. What makes it a finding is when the token is also bound to a capability the user is not supposed to have.

An event calendar with a front-end submission feature will accept file uploads from anonymous visitors, because the calendar is public and the submission form is how speakers propose a talk. The submission endpoint needs a token to prevent spam. The token is rendered into the page. The upload directory and the validation routine are then reachable by anyone who reads the page, and the form handler for a feature nobody uses is still deployed.

The general pattern is dormant functionality. Features added for a specific event, campaign or workflow tend to outlive their purpose inside the plugin, because removing a plugin setting is nobody's ticket. The security question is not whether the feature is intended, but whether it is still enabled, still exposed and still defended.

TL;DR: A business innovation network ran a patched content platform with fourteen findings. The interesting one was a feature left switched on that published its own request tokens in the page source.

Findings

SeverityFindingEvidence
MEDIUMSubmission feature enabled with tokens published in the pageUpload endpoint reachable by reading the page source
MEDIUMContent security policy absent across the siteNo policy despite a consent plugin being installed
MEDIUMFive third-party scripts without integrity attributesNo subresource integrity on any external script
MEDIUMMail authentication set to monitoring onlySending domain spoofable
LOWUser enumeration via three separate pathsRead interface, login error text and author redirect
LOWCaching layer exposes an internal header naming the softwareCache software and configuration flags visible

The attack path

Public event calendarAnonymous submission formToken rendered into page sourceUpload endpoint reachableValidation routine exposedDormant feature becomes an entry point

Reproduction in my lab

Every command below targets a lab container I control. Nothing here is aimed at a live system.

Find published request tokens in your own page source

~/code/bash bash
$ curl -s https://example.org/events/ > /tmp/page.html

# nonce-like values in the markup
$ grep -oiE '(nonce|_wpnonce|mec[a-z_]*nonce|verification)["\x27:=\s]+[a-z0-9]{8,}' /tmp/page.html | head

# what forms and endpoints the page references
$ grep -oiE 'action=["\x27][^"\x27]+|admin-ajax\.php[^"\x27]*' /tmp/page.html | sort -u | head

Detection in your own estate

Inventory external scripts and check for integrity attributes

~/code/bash bash
$ curl -s https://example.org/ | grep -oE '<script[^>]*src="[^"]*"[^>]*>' \
  | grep -v 'src="/' \
  | sed 's/.*src="\([^"]*\)".*/\1/' | sort -u

# and count how many of those carry integrity
$ curl -s https://example.org/ | grep -oE '<script[^>]*src="https?://[^"]*"[^>]*>' \
  | grep -c integrity

Remediation

Turn the feature off if it has no owner

~/code/python python
# the durable fix for dormant functionality is removal, not hardening
import subprocess

# what is enabled on this install
$ wp plugin list --status=active --field=name
$ wp option get mec_options --format=json | python3 -c '
import json,sys
cfg = json.load(sys.stdin)
fe = cfg.get("features", {})
for name, state in fe.items():
    print(name, state)'

# disable the anonymous submission path and re-test
$ wp option patch update mec_options '{"features":{"fes_nonce":false,"fes_upload_nonce":false,"recaptcha_key":""}}'

Pin external scripts with integrity attributes

~/code/html html
<!-- every third-party script gets an integrity attribute -->
<script src="https://cdn.example.com/analytics.js"
        integrity="sha384-EXAMPLEHASHEXAMPLEHASHEXAMPLEHASHEXAMPLEHASHEXAMPLEHASH"
        crossorigin="anonymous"></script>

Once an attacker gains access, they can perform the following actions:

Submission feature enabled with tokens published in the page
Content security policy absent across the site
Five third-party scripts without integrity attributes
Mail authentication set to monitoring only

Takeaways

  • A token in the page is normal; a token guarding a capability nobody checked is a finding.
  • Dormant features outlive their purpose inside the plugin.
  • The durable fix for an unused feature is removal, not a configuration change.
  • If a consent plugin is installed, the content security policy generator should be on.

For educational purposes only. Every reproducible command targets my own lab environment (localhost), never a live system. © 2026