Live Demo: Try this and other plugins live — no installation, no risk: demo.markus-michalski.net
This page describes what the module actually processes according to its code. It is not a legal assessment for your shop.
The widget script is loaded by the visitor's browser from
cdn.jsdelivr.net, a third-party server. The provider receives at least the visitor's IP address and user agent. The module therefore does make requests to a third party.
The module includes the ALTCHA widget through the template layout/base.html.twig (block base_js) like this:
<script type="module" src="https://cdn.jsdelivr.net/npm/altcha@latest/dist/altcha.min.js"></script>
altcha@latest). The code the browser executes is therefore whatever the CDN serves at that moment, not something this module controls.If you do not want to load the script from the CDN, override the base_js block in your own theme or module and serve the file yourself. The module does not check where the script comes from.
| Data | When | What happens to it |
|---|---|---|
| Visitor IP address | When a challenge is requested and when a protected form is submitted | Read, and stored only as an HMAC-SHA256 hash; the plain address is not stored |
Action (contact_form, newsletter_subscribe, registration, challenge) and timestamp |
Together with the IP hash | One row per request in mmd_altcha_rate_limit_log |
| Hash of the solved challenge | After a solution has been verified | SHA-256 of the challenge plus expiry time in mmd_altcha_used_challenges, not personal data |
| Form contents (first name, last name, email, street, city) | During content validation | Checked in memory only and not stored by the module |
| Honeypot field value | On submit | Only checked for empty or non-empty, not stored |
The IP hash is computed from the text ip: plus the address, using the module's HMAC secret as the key. Without that key the address cannot be recovered from the hash. Depending on your assessment, such a value may still count as pseudonymised personal data, and your record of processing activities should take it into account.
The module reads the address like this: if the X-Forwarded-For header is present, its first entry is used, otherwise REMOTE_ADDR. There is no list of trusted proxies.
A visitor can set
X-Forwarded-Forthemselves if no proxy in front of the shop overwrites the header. This allows rate limiting to be bypassed. Behind a reverse proxy that does not sendX-Forwarded-For, on the other hand, all visitors share one counter.
The module's code neither sets nor reads cookies, and it stores nothing else in the browser. OXID itself sets its own cookies independently, for example for the session.
The module does not delete its data automatically. The cleanup methods (RateLimitService::cleanup(), RateLimitRepository::deleteOlderThan(), UsedChallengeRepository::deleteExpired()) exist but are not called by any cron job or hook. Both tables therefore grow without limit.
Clean them up regularly yourself, for example with a cron job running these statements:
DELETE FROM mmd_altcha_rate_limit_log WHERE requested_at < NOW() - INTERVAL 1 DAY;
DELETE FROM mmd_altcha_used_challenges WHERE expires_at < NOW();
The interval in the first statement must be at least as long as your largest configured time window (default: 60 minutes), otherwise rate limiting loses entries it needs. Expired challenges are rejected anyway, so deleting their rows in mmd_altcha_used_challenges is safe.
Deactivating or uninstalling the module leaves both tables in place. Drop them manually if you no longer need them.