Tag: WordPress

  • OpenPorte 1.30.3: a security release, please update

    OpenPorte 1.30.3 is out, and it is a security release. If your WordPress site runs OpenPorte together with Contact Form 7 or HTML Forms, please update now.

    What was wrong

    To place the OpenPorte widget inside Contact Form 7 and HTML Forms forms, the plugin expanded every shortcode in the form just before it was displayed. The trouble is what that form contains by then: the values a visitor typed into its fields, or put in the page’s URL. A visitor could therefore make your site run any shortcode registered on it, without logging in.

    What that allows depends on your site. WordPress’s own shortcodes can list media attached to private or draft posts. Shortcodes from other plugins can carry their own flaws, which normally need a logged-in author to reach and here became reachable by anyone. Neither the integration settings nor the CAPTCHA itself stopped it.

    The flaw is old: OpenPorte inherited it from ALTCHA Spam Protection, where it arrived in 1.6.0 (Contact Form 7) and 1.7.0 (HTML Forms). It is tracked as GHSA-hvr5-q69x-jp62 and rated high (CVSS 7.3).

    Still on ALTCHA Spam Protection? Every release up to its last GPL version, 1.26.3, is affected, and that plugin is no longer maintained, so no fix will come there. Switch to OpenPorte 1.30.3: it imports your ALTCHA Spam Protection 1.x settings and keeps its free, self-hosted features, including the [altcha] shortcode. Only the paid altcha.org SaaS mode was not carried over; sites that used it fall back to self-hosted challenges.

    What changed

    OpenPorte now renders only its own [openporte] and [altcha] tags, and only from the form as you wrote it, before any visitor input is added. Visitor input is never run as a shortcode any more.

    One side effect: shortcodes from other plugins placed inside a Contact Form 7 or HTML Forms form may stop rendering. Neither form plugin renders shortcodes in its forms on its own. If yours still render after the update, another plugin is expanding them, and it may be open to the same kind of flaw: check with its author.

    I chose not to offer a switch to bring the old behaviour back: it would re-open the hole on every site that flips it, and nothing in the admin would remind anyone that it is on. If one of your forms relied on such a shortcode, ask in the support forum and we will find a safe way together.

    Contact Form 7 users can now write the widget language as [openporte language:de_DE]. The old [openporte language="de_DE"] keeps working.

    Thanks

    Thanks to Erik Debye, who reported the issue privately through GitHub. That gave us the time to fix it properly, test it against real Contact Form 7 and HTML Forms installs, and release the fix together with the advisory.

    The analysis of the vulnerability, the fix and its release were AI-assisted: I worked through them with Claude (Anthropic’s AI assistant), and reviewed, tested and signed off every change myself.

    Links


    This post was written with the assistance of Claude, an AI assistant by Anthropic.

    Made with πŸ’˜ in the Ruhr area, Germany.

  • OpenPorte 1.30.0: closing the revolving porte

    OpenPorte 1.30.0 is out on GitHub and WordPress.org. This is a security release, so please update: it fixes two published security advisories, GHSA-vwx9-x8p5-xvmp and GHSA-8g7w-538v-w54x, both rated medium, plus three smaller hardening fixes.

    It all started with the release of Qwen3.8, an open-weight large language model, and I wanted to test its actual capabilities on my codebase. So I gave it a task to perform a security review of the code (at the time v1.29.1). It was able to detect minor security or robustness issues which Opus 4.8 missed when it reviewed the release v1.27.1. I decided to include them in our current release cycle which included some new features.

    And before shipping, I had the development branch reviewed again for security, this time with the help of two other AI code reviewers, Anthropic Claude Opus-5.5 and OpenAI Codex GPT-6-Astra. They found several ways a bot could skip the proof-of-work, or use less resources for it, on some forms and setups. Most of them were inherited from ALTCHA Spam Protection v1, some from its very first release. None of them exposed data, credentials or admin access, and passwords were always checked. What a bot could skip was the cost the proof-of-work provided by ALTCHA is there to add.

    The two security advisories

    AdvisorySeverityAffectedFixed in
    GHSA-vwx9-x8p5-xvmp: Solved CAPTCHA challenges accepted after their expiryMediumOpenPorte ≀ 1.29.1, ALTCHA Spam Protection ≀ 1.26.3OpenPorte 1.30.0
    GHSA-8g7w-538v-w54x: Login CAPTCHA checked only after the passwordMediumOpenPorte ≀ 1.29.1, ALTCHA Spam Protection ≀ 1.26.3OpenPorte 1.30.0
    • Expired challenges (GHSA-vwx9-x8p5-xvmp): a solved challenge could be altered so that its expiry was ignored, and reused long after it should have been refused. The Replay limit from 1.29.0 still capped the reuse, but expiry is meant to be the first line of defence. In Custom API Mode, a backend issuing challenges in an outdated format had the same problem (more on that below).
    • Login order (GHSA-8g7w-538v-w54x): on the login forms, the challenge was checked only after WordPress had compared the password. Guessing passwords cost nothing, and the error message even told a correct guess apart from a wrong one. Now the challenge comes first: without it, every attempt gets the same error.

    CVE IDs have been requested and will be added to the advisories when they are assigned.

    Still running ALTCHA Spam Protection 1.x?Β Both flaws are in it too, and it is no longer maintained, so there will be no fix there. OpenPorte imports your 1.x settings and keeps the free, self-hosted features backward compatible,Β the altcha shortcode included; only the paid altcha.org SaaS mode and its spam filter were not carried over. If you rely on those, the official ALTCHA plugin, now a new generation that is no longer GPL-licensed, offers them: seeΒ altcha.org.

    The other fixes

    On sites running WooCommerce, a forged form field could skip the WordPress login and password-reset checks. With the CoBlocks integration switched off, OpenPorte still overrode CoBlocks’ own reCAPTCHA (that one was discovered by Qwen3.8-27B). And in Custom API Mode, the site kept issuing challenges of its own, which let bots go around the backend’s rules. The full list is in issue #126.

    If you use Custom API Mode, open the OpenPorte settings page once after updating. The backend check now also warns when your backend issues challenges in an outdated format, the case behind CVE-2025-68113 and the second cause of GHSA-vwx9-x8p5-xvmp. Purge your page caches too.

    Release v1.30.0 not only contains fixes, but two new settings/features:

    • OpenPorte now supports an Ajax transport next to the existing REST API. A new setting allows for self-hosted mode switching the transport serving challenges through admin-ajax.php instead of the REST API. The intended use case is for sites whose security plugin blocks the REST API for visitors. OpenPorte still defaults to using the REST API transport, which we recommend using. Thanks to factor11 for the report and the workaround.
    • And “Keep settings when the plugin is deleted” lets you remove and reinstall OpenPorte without losing its configuration. It is off by default, so the plugin’s settings are removed when uninstalling it.

    Developers: the openporte_replay_limit filter now also receives the form the token was submitted on, so you can be stricter on replay limit for a login page than on comments. Existing callbacks keep working unchanged.

    If you allowed automatic updates from WordPress.org, you most likely already have 1.30.0. Your settings are kept.

    Known issue: LiteSpeed Cache

    Since the release, a user reported that they could not log in on a site running LiteSpeed Cache. With its default settings, LiteSpeed Cache stores REST API responses for seven days and ignores the “do not cache” headers OpenPorte sends. So every visitor gets the same challenge: logins and protected forms fail after five uses (the Replay limit) and for everyone once that challenge expires. This is not new in 1.30.0: it goes back to the first ALTCHA Spam Protection release, and the Replay limit added in 1.29.0 only makes it show sooner. The fix is ready and will ship in 1.30.1. Until then, if you use LiteSpeed Cache, pick one of these workarounds:

    1. In Settings β†’ OpenPorte, set Self-hosted transport to Ajax, or
    2. in LiteSpeed Cache β†’ Cache β†’ Excludes β†’ Do Not Cache URIs, add /wp-json/openporte/.

    Then run LiteSpeed Cache β†’ Purge All once: the stale challenge stays cached until it is purged. Already locked out? Purge the cache from your hosting panel or with WP-CLI (wp litespeed-purge all); the next challenge is fresh, so you can log in and apply a workaround. Thanks to Nico for the report and the quick feedback.

  • OpenPorte – 500+ installs, thank you

    OpenPorte just crossed 500 active installations on WordPress.org. That’s about five times what we had when I wrote the 100-installs post barely two months ago. Still, that’s just a number. What it tells me is that there are sites that decided to put OpenPorte in front of their contact forms, comments or logins, and that’s a level of trust I know how to appreciate. So thank you to everyone who installed it, to the five of you who left a review, and to those who reported an issue or a rough edge. That’s how it gets better.

    It’s worth looking back at where we started. In June the plugin was forked from the open-source project ALTCHA Spam Protection v1.26.3. Four and a half months later, there is no paid tier at all, a security hardening pass and replay protection are in, the settings page health-checks its own configuration, a browser end-to-end test suite runs across the supported form plugins, and 14 languages are fully translated and kept in sync.

    There is still plenty to do, and more to share soon.


    Made with πŸ’˜ in the Ruhr area, Germany.

  • OpenPorte 1.29.0: a solved challenge is no longer playing on repeat

    OpenPorte 1.29.0 is out on GitHub and WordPress.org. It resolves a weakness inherited from ALTCHA v1: a solved proof-of-work challenge could be reused without limit.

    Verification itself was never broken. The gap was that nothing counted how often a token had already been consumed, so one solved challenge kept working until it expired. With Expiration set to “None”, that meant forever.

    Each solved challenge is now accepted a limited number of times, counted server-side. The new Replay limit setting defaults to 5, with options for unlimited (old behaviour), strict single use, 10, or a custom value. Five rather than one because a form can bounce back due to legit reasons – a missing field, a mistyped password – and the visitor would resubmit the same challenge. A non-strict default keeps those humans in. Custom API Mode is covered too, with no change needed on your backend.

    It never locks visitors out, OpenPorte follows here again a fail-open strategy. If the counter cannot be stored, submissions are accepted as before and the settings page tells you so.

    This is the first iteration of issue #99, not all of it. Very short expiration (which is an issue for old hardware) and 0 (was “None” before) are still selectable, for now. The settings page warns, but rejects nothing now.

    Contact Form 7 forms with a manually placed widget (using a shortcode) are verified server-side even when the integration toggle is off. If for whatever reason you relied on the widget being just decorative, it is no longer possible and unsolved submissions will now fail.

    Developers: call `verify()`, and do not use the public `verify_solution()` or `verify_server_signature()` methods. Both are now deprecated and will be made private in 2.0.

    One more thing. OpenPorte was verified to work with the new WordPress 7.1, while still supporting older releases down to WordPress 5.6.


    If you allowed automatic update from WordPress.org, you have nothing to do. OpenPorte keeps your settings and provides safe new defaults.

  • OpenPorte – 100 installs, 4 reviews! Thank you!

    Icon for the OpenPorte project. Depict a gate with a lock in the middle.

    OpenPorte just crossed 100 active installations on WordPress.org, and has already four encouraging reviews left so far. For a one-person fork that’s about three months old, this is motivating.

    If you’re wondering what OpenPorte is, check the announcement post.

    It is exciting to feel this is being useful also to others. So, thank you to everyone who installed it, and to the four of you who took the time to leave a review.

    The road since the fork

    It’s been about three months, so here’s the short version of how we got here:

    • June 2026 β€” 1.27.0, the fork itself. Picked up from ALTCHA Spam Protection v1’s last open-source release, rebranded as OpenPorte and still open-source. Existing ALTCHA v1 settings migrate automatically, and backward compatibility was implemented. The point was that switching over should be transparent and easy.
    • 1.27.1–1.27.3. Fixes requested by the WordPress.org review team, then a dedicated security-hardening release (timing-safe signature checks, stronger key generation, tighter input validation), no behaviour change, just a harder shell.
    • 1.28.0, the big one. Removed the last remnants of the old paid-SaaS tier. OpenPorte is now free, full stop, nothing gated or premium. Among many things, retuned the difficulty presets for modern hardware, and gave the settings page more explanation and live health checks so misconfiguration gets caught before visitors notice. Plus four new translations.
    • 1.28.1. Housekeeping and a new GitHub home.
    • Translations. from 1 to 14 languages today, including isiXhosa (one of the South-African languages), Ukrainian, with help from open-weight local LLMs.

    Without local open-weight and frontier LLMs, this feat would not have been possible.

    What’s cooking for 1.29.0

    Still in testing, no ship date yet, but here’s a preview of the headline items: replay protection and compatibility with WordPress 7.1.

    Right now, a solved challenge stays valid until it expires… and if you’d set Expiration to “None,” that meant forever! In practice that’s a gap: a bot only has to solve one proof-of-work once, then can replay that same solved token indefinitely. 1.29.0 closes it with a new Replay limit setting (presets from single-use to unlimited, default 5, a small allowance so a visitor whose form bounces back for an unrelated reason, a typo, a missing field, isn’t punished for resubmitting). It applies whether you’re running self-hosted or pointing at your own Custom API backend, and the settings page will report its status alongside the existing endpoint health check.

    The current stable release of OpenPorte does seem to work nicely with the newly released WordPress 7.1. But we will do a full non-regression testing to make sure it is 100% compatible.

    That’s the short version β€” there’s a more technical writeup coming once it ships. A big thank you to qodop.com who remind me about the unsolved replay protection issue. This was an interesting journey to fix that, one that I might talk about in a future post.

    If you’re using OpenPorte

    A review, any review genuinely helps. It can be a motivation to continue the effort, new ideas or new perspectives for the project. So they aren’t good or bad reviews, they maybe easy or difficult to hear, but they all help me and the project. It also increases OpenPorte visibility on WordPress.org. And if you hit something odd, open an issue on GitHub, that’s exactly how the fixes above got found.


    Made with πŸ’˜ in the Ruhr area, Germany.


    Credits: The draft of this post was developed in conversation with Claude Sonnet 5 (Anthropic). Any errors of judgement remain mine πŸ˜‰.

  • Introducing OpenPorte: a free, open-source CAPTCHA for WordPress

    If you’ve ever used ALTCHA Spam Protection on your WordPress site, I have some news: that plugin now lives on as OpenPorte.

    What is OpenPorte?

    OpenPorte is a free/libre, open-source anti-spam plugin for WordPress. It protects your comment forms, contact forms, login pages, and more from bots, without cookies, without tracking, and without sending your visitors’ data anywhere. Everything runs on your own site.

    It’s built on the same friction-less, tick-a-box proof-of-work approach that made the original ALTCHA Spam Protection plugin popular: no distorted-letter puzzles, no picking out traffic lights, just a quick, invisible check that’s easy for humans and expensive for bots.

    Schematic animation of the ALTCHA widget in action. It shows a cursor clicking the checkbox and being verified.

    That’s the entire interaction1: one tick, a moment’s work in the background, done.

    Why a fork?

    ALTCHA Spam Protection (v1) was open-source software, free for anyone to use, inspect, and improve. Its original authors have since moved on to build a newer version, which is no longer fully open-source and puts some previously-free features behind a paywall, and they’ve retired the original v1 line.

    I’d been a happy user of that original plugin for a while, so rather than lose it, I picked up the open-source project and kept it going under a new name, OpenPorte: a continuation of the v1 line, staying free/libre, open-source, and self-hosted, for anyone who wants to keep it that way.

    If you are – or were – using ALTCHA v1, switching over is meant to be painless: install OpenPorte, and your existing settings come along automatically. Nothing you’ve already set up gets lost, and you can roll back if you ever want to. The only constraint is that you can’t run both plugins at the same time: it’s one or the other.

    What’s new in the first releases (1.27.0 β†’ 1.28.0)

    The last open-source version of the ALTCHA plugin was 1.26.3. I picked up from there, and a few months in, here’s what’s landed:

    • ⛓️‍πŸ’₯ Fully free, no paid tier at all. The old paid add-on for spam classification has been removed. Every feature in OpenPorte is free and self-hosted.
    • A friendlier settings page. Clearer wording, helpful hints next to every option, and a show/hide toggle for the shared secret key field.
    • ⚑️ Snappier verification. The small pause visitors used to see while the check ran has been cut from 1.5 seconds down to 0.5. That pause only ever changed how the check felt, it never made the plugin any better at stopping bots. What does help is the difficulty of the challenge itself, so there’s now a choice of algorithm, and the complexity levels have been retuned for modern hardware.
    • Several small but annoying bugs fixed, including a WooCommerce login/registration hiccup, a contact form that could show its widget twice, and a click that could get lost while a challenge was still verifying.
    • πŸ’¬ New languages. OpenPorte now speaks 14 languages, including isiXhosa πŸ‡ΏπŸ‡¦, German πŸ‡©πŸ‡ͺπŸ‡¦πŸ‡ΉπŸ‡¨πŸ‡­…, Ukrainian πŸ‡ΊπŸ‡¦, Czech πŸ‡¨πŸ‡Ώ, Polish πŸ‡΅πŸ‡±, Romanian πŸ‡·πŸ‡΄, Turkish πŸ‡ΉπŸ‡· and Chinese πŸ‡¨πŸ‡³.
    • Extra security hardening, tightened under the hood. I believe in frictionless security, so there’s nothing you need to do. I also believe in transparency, so you can read the code, audit it, or report anything you find on the project’s GitHub.
    • A refreshed look, with a new logo and banner art.

    One more thing, transparency

    OpenPorte is a one-person project, and I’m opinionated about how it gets built: AI tools (Claude, Mistral, locally-run LLMs and others) help with drafting code, tests, translations, and documentation. The architecture, security decisions, and final review are mine. Without that help, keeping this fork alive wouldn’t be realistic for one person β€” so it felt right to just say so.

    This post is a case in point: I keep notes from every working session, then asked the AI to pick out the parts that fitted what I wanted this post to be, and to help me draft it.

    What’s next

    This post is meant to be a friendly hello world. There’s a livelier, more technical follow-up coming later, with some of the more interesting (and occasionally eyebrow-raising) stories from behind the scenes of taking over an abandoned plugin. Stay tuned.

    If you want to try OpenPorte, or peek at the code, it’s all on GitHub.


    Made with πŸ’˜ in the Ruhr area, Germany.


    1. The SVG animated image was created with AI and Inkscape. β†©οΈŽ

    Credits: The draft of this post was developed in conversation with Claude Opus 4.8 (Anthropic). Any errors of judgement remain mine πŸ˜‰.

  • How WordPress.org decides that a plugin is a “Community plugin”

    While working on my WordPress plugin, I noticed that some plugins on wordpress.org display an additional “Community plugin” section in their developer sidebar, including a link to their source repository.

    I initially assumed this was controlled by readme.txt, the plugin header, or some SVN convention. It turns out it is none of those.

    Assisted by an AI Agent1, a little source-code archaeology revealed that WordPress.org uses an internal taxonomy plugin_business_model with terms including:

    community
    commercial
    canonical

    The taxonomy is registered by the Plugin Directory code and rendered by checking the assigned term.

    The important detail for me turned out that this is not an author-controlled setting.

    The taxonomy is available in the WordPress.org internal admin UI, but assigning it requires a special capability (plugin_set_category) that is only available to Plugin Team reviewers and administrators.

    Once assigned, additional metadata becomes available (for example, a repository URL for Community plugins), but those fields only describe the classification; they do not create it.

    So the answer is:

    Plugin authors cannot enable the “Community plugin” badge themselves. It is an editorial classification assigned manually by the WordPress.org Plugin Team.

    Use of AI

    An AI writing assistant was used to create this article. It mainly supported me summarising the long investigation that was conducted.

    1. For this task I used Codex + ChatGPT Terra 5.6 and the all mighty grep. β†©οΈŽ
  • Photon – A WordPress plug-in for PhpWebGallery 1.7

    Photon 4.2.1 (non official release) by @jcberthon

    You can find an updated (and non official version) of Jillij Photon plug-in for WordPress. It now works with PhpWebGallery 1.7.0.
    This plug-in is licensed under the same condition as the original one: GPL
    Instructions are included in a readme.txt file in the package.

    If you are on Windows (XP or Vista), you might want to try 7-zip to open the previous archives. 7-zip is free of charge and is free (as in freedom). It has many advantages compare to the built in archiving facility of recent Windows release.