Scan time: 2026-09-08 14:45:44
Overall Score
Compared with scan from 08.09.2026 10:55 (Score 83 → 86) · View full history
✓ Protections gained: csp_script_ok, csp_nonce_hash
⚠ This website has serious GDPR deficiencies. Immediate action is required.
GDPR Issues Detected (1):
❌ No privacy policy found — required under Art. 13 GDPR.
Note: This automated analysis does not replace legal advice. For a complete GDPR assessment, consult a data protection officer.
↓ See detailed results for each category below.
The website uses an encrypted connection (HTTPS).
Latest encryption active (TLS 1.3 — TLSv1.3).
The security certificate is valid (expires 2026-11-29).
Adequate encryption method (TLS_AES_128_GCM_SHA256, 128 bit).
HSTS is enabled — the browser is instructed to always use the encrypted connection.
HSTS duration: 31536000 seconds (at least 1 year) — very good.
HSTS also applies to all subdomains (includeSubDomains).
HSTS preload is enabled — browsers know about the encryption before the first visit.
Content Security Policy present (via HTTP-Header).
Script sources are properly restricted.
Additional protection through nonce or hash for scripts.
Embedding protection (frame-ancestors) is configured — protects against clickjacking.
Good base rule: only own content is allowed by default (default-src: self).
Referrer-Policy: strict-origin-when-cross-origin (via HTTP-Header).
Strict setting "strict-origin-when-cross-origin" — no path leak, no HTTP downgrade leak. Best practice.
MIME type protection active (nosniff) — browsers will not misinterpret files.
Clickjacking protection active via CSP frame-ancestors.
Permissions-Policy is configured — access to sensitive device APIs is controlled.
4 of 6 sensitive APIs restricted — very good.
2 first-party and 0 third-party cookie(s).
1 of 2 cookie(s) without HttpOnly flag — could be read by malicious code.
Cookies without the "HttpOnly" flag can be read by JavaScript — an XSS attacker can steal session cookies and impersonate the logged-in user. Set HttpOnly for all cookies JavaScript doesn’t actively need.
File: .htaccess in the web root
<IfModule mod_headers.c>
Header always edit Set-Cookie "^(.*)$" "$1; HttpOnly" "expr=!(resp('Set-Cookie') -strmatch '*HttpOnly*')"
</IfModule>⚠ Cleaner: set cookies with HttpOnly directly (PHP: setcookie(..., [..., 'httponly'=>true])). Exception: cookies that JS actively reads (e.g. some consent cookies).
File: functions.php of your CHILD theme (or better wp-config.php)
@ini_set('session.cookie_httponly', '1');
@ini_set('session.cookie_secure', '1');⚠ WordPress login cookies have been HttpOnly since 2.x. If you use a plugin that sets session cookies (e.g. WooCommerce cart pre-login), check its settings.
✓ How to verify it works: F12 → Application → Cookies → "HttpOnly" column shows checkmarks everywhere (except for deliberately JS-readable cookies like the consent cookie).
| Name | Domain | Encrypted | Server only | SameSite |
|---|---|---|---|---|
| XSRF-TOKEN | acs-it.fr | Yes | No | Lax |
| octopus-session | acs-it.fr | Yes | Yes | Lax |
No local storage (Web Storage) used — no tracking risk.
No third-party requests detected — all content comes from the website's own server.
No known trackers detected.
No external scripts or stylesheets loaded.
No CAA records. Any certificate authority could issue a certificate for this domain.
CAA records (Certification Authority Authorization) define in DNS which Certificate Authorities are allowed to issue certificates for your domain. Without a CAA record an attacker could request a fraudulent certificate for your domain at any CA. CAA is pure DNS configuration — set in your registrar/DNS-panel, NOT in WordPress.
Find your host in the table, copy the values to your DNS panel. For multi-CA hosts: one separate CAA record per CA (all with tag issue, flag 0, name @). Additionally recommended: an iodef record with a contact email for abuse reports.
| # | Host | CA(s) used | CAA value(s) — tag issue |
|---|---|---|---|
| 1 | Hetzner Webhosting (basic certificate, free in package) | DigiCert (programme „Encryption Everywhere") | digicert.com |
| 1 | Hetzner Webhosting (Let’s Encrypt, free) | Let’s Encrypt (ISRG) | letsencrypt.org |
| 2 | All-Inkl | Let’s Encrypt + Sectigo (Pro) | letsencrypt.orgsectigo.com |
| 3 | IONOS (1&1) | DigiCert (GeoTrust) + Let’s Encrypt | digicert.comletsencrypt.org |
| 4 | STRATO | Sectigo + Let’s Encrypt | sectigo.comletsencrypt.org |
| 5 | Cloudflare (Universal SSL) | Google Trust Services + DigiCert + Let’s Encrypt | pki.googdigicert.comletsencrypt.org |
| 6 | AWS (ACM / CloudFront) | Amazon Trust Services | amazon.comamazontrust.comawstrust.comamazonaws.com |
| 7 | Mittwald | Let’s Encrypt + Sectigo | letsencrypt.orgsectigo.com |
| 8 | Webgo | Let’s Encrypt + Sectigo | letsencrypt.orgsectigo.com |
| 9 | raidboxes (Managed WordPress) | Let’s Encrypt | letsencrypt.org |
| 10 | Host Europe / DomainFactory | Sectigo + Let’s Encrypt | sectigo.comletsencrypt.org |
Name Type Flag Tag Value
@ CAA 0 issue "digicert.com"
@ CAA 0 issue "letsencrypt.org"
@ CAA 0 iodef "mailto:security@your-domain.com"
The iodef line (last line) is optional but recommended: CAs report abuse attempts to that address. For subdomains (e.g. shop.your-domain.com) create separate records with the subdomain name instead of @ — modern CAs check parent CAA automatically though.
If your host is not on the list: open your current certificate in the browser (padlock → certificate → issuer). The CA name is shown there (e.g. "Sectigo RSA Domain Validation Secure Server CA" → value sectigo.com). Add that as a CAA record, done.
WordPress plugin: CAA records are NOT created in WordPress but in your domain registrar / DNS provider panel (e.g. Hetzner-Robot, IONOS Domains, Cloudflare Dashboard, INWX, etc.). Common label: "CAA record" or under "TXT records" with type selector "CAA". One separate record per CA.
✓ How to verify it works: On https://www.ssllabs.com/ssltest/analyze.html?d=your-domain.com → "DNS CAA" section → all your CAs should be listed. Or via dig: dig CAA your-domain.com.
2 nameservers present — good redundancy.
No IPv6 support (no AAAA record).
Your domain has no IPv6 address (AAAA record). Over 40% of users (especially mobile) reach the internet via IPv6 — they must take the slower IPv4 gateway detour.
WordPress plugin: Pure DNS + server matter. Step 1: check if your host has an IPv6 address for you (hosting panel or support ticket). Step 2: in the DNS panel create an AAAA record pointing to that IPv6. Step 3: test.
✓ How to verify it works: dig AAAA your-domain.com — or online https://ipv6-test.com/validate.php?url=your-domain.com.
SPF record present: v=spf1 ip4:147.78.173.9 ip4:147.78.173.18 ip4:147.78.174.6 ip4:194.156.160.2 include:spf.protection.outlook.com include: — protects against email spoofing.
DMARC record present: v=DMARC1;p=reject;pct=100;rua=mailto:dmarc@acs-it.fr;ruf=mailto:dmarc@acs-it.fr;aspf=s; — email authentication active.
No security.txt file found (RFC 9116). Security researchers don't know how to report vulnerabilities.
A security.txt (RFC 9116) tells security researchers how to responsibly report vulnerabilities to you. Without it, reports may go to spam or never be sent. A plain text file at the correct path is enough.
File: /.well-known/security.txt (create the folder if it doesn’t exist)
Contact: mailto:security@your-domain.com
Expires: 2027-12-31T23:59:59.000Z
Preferred-Languages: en, de
Canonical: https://your-domain.com/.well-known/security.txt⚠ Replace "security@your-domain.com" with your actual security contact (or a generic info@). "Expires" must be a future date and should be renewed regularly. The file is plain .txt, not PHP.
File: security.txt file in /.well-known/ under your WordPress root
Contact: mailto:security@your-domain.com
Expires: 2027-12-31T23:59:59.000Z
Preferred-Languages: en, de
Canonical: https://your-domain.com/.well-known/security.txt⚠ Via FTP/SFTP create a folder ".well-known" in the WordPress root (the leading dot matters — some FTP tools need "show hidden files" enabled), inside save the file security.txt with the content above. If WordPress redirects the URL: add to .htaccess: RewriteRule ^\.well-known/ - [L]
WordPress plugin: Plugin "security.txt" (search the plugin directory) lets you configure this in the WordPress backend without FTP.
✓ How to verify it works: Open https://your-domain.com/.well-known/security.txt in a browser — content must be visible (no 404).
No external reporting endpoints detected.
Cookie consent system detected: Unbekannt.
Consent banner is visible to visitors.
No privacy policy found! Required under Art. 13 GDPR.
No privacy policy found — mandatory under Art. 13 GDPR. Violations risk warnings and fines. The privacy policy must be reachable from EVERY page with a single click (typical: footer link).
WordPress plugin: Step 1: create a privacy policy. Generators (legally reviewed, in German): https://datenschutz-generator.de (Dr. Schwenke, free), https://www.e-recht24.de (paid premium). Mandatory contents include: name + address of data controller, DPO if applicable, purpose and legal basis of each processing, recipients / third-country transfers, retention periods, data subject rights, right to lodge complaint with supervisory authority. Step 2: in WordPress create a Page with the content. Step 3: under Settings → Privacy mark it as the privacy policy page. Step 4: create a footer menu (Appearance → Menus → new menu → assign to "Footer" position) and link the privacy policy.
✓ How to verify it works: From the home page: scroll down → footer → link "Privacy" or "Privacy Policy" visible → click → opens the policy. Works from ALL pages.
No legal notice (Impressum) found — required under German law (§ 5 DDG).
No imprint (legal notice) found — mandatory in Germany under § 5 DDG for all business-grade websites (and effectively for many other commercial sites in the EU). Even private blogs with ad or affiliate revenue typically require one. Violations are commonly targeted by warning letters.
WordPress plugin: Step 1: create an imprint. Free generator (German law): https://www.e-recht24.de/impressum-generator.html. Mandatory information includes: full legal name, postal address (no P.O. box), phone OR another second contact, email, for companies: trade register + VAT ID, supervisory authority if applicable, professional liability insurance if applicable. Step 2: in WordPress → Pages → Add New → title "Imprint" → publish. Step 3: footer menu → add "Imprint". IMPORTANT: the imprint must be "easily recognizable, directly accessible, permanently available" — a footer link satisfies this, an "About us" → "then imprint" does NOT.
✓ How to verify it works: Footer on every page → link "Imprint" or "Legal notice" visible → opens the imprint page with all mandatory information.
All missing security headers combined into one block. Append this block to the end of your .htaccess — done. 1 headers will be set.
On Hetzner-Konsoleh webhosting (and comparable shared hosts like All-Inkl, IONOS, Strato, 1blu, …), Apache throws a 500 Internal Server Error as soon as Header always edit Set-Cookie … expr=… appears in .htaccess. The Apache error log says:
Can't parse envclause/expression: syntax error, unexpected T_OP_STR_EQ, expecting $end
This is not a WebForensik bug and not a typo — the shared host has blocked the mod_headers expr= subset via AllowOverride limits (for security, because Header edit could also manipulate cookies of other tenants).
☛ For Hetzner-Konsoleh users: use the variant below marked with the red "Hetzner / Shared" badge. It consists of two files (.htaccess + wp-config.php) instead of one, but avoids the 500 error reliably. Cookie flags go into wp-config.php instead of .htaccess.
Append this block to the end of your .htaccess in the web root — done.
<IfModule mod_headers.c>
# Fehlende Cookie-Flags konditional ergänzen (nur wenn nicht schon gesetzt)
Header always edit Set-Cookie "^(.*)$" "$1; HttpOnly" "expr=!(resp('Set-Cookie') -strmatch '*HttpOnly*')"
</IfModule>
Insert this block ABOVE the "# BEGIN WordPress" line, otherwise WP overwrites it on permalink changes.
# BEGIN WebForensik Security
<IfModule mod_headers.c>
# Fehlende Cookie-Flags konditional ergänzen
Header always edit Set-Cookie "^(.*)$" "$1; HttpOnly" "expr=!(resp('Set-Cookie') -strmatch '*HttpOnly*')"
</IfModule>
# END WebForensik Security
If your host disallows .htaccess changes: append this PHP snippet to the end of your CHILD theme's functions.php. Back up first — NEVER edit the parent theme, it gets overwritten on updates.
add_action('send_headers', function () {
});
// Cookie-Flags für PHP-Session-Cookies — wirkt nur auf $_SESSION,
// NICHT auf von Plugins/Themes per setcookie() gesetzte Cookies.
// Für umfassende Cookie-Absicherung die .htaccess-Variante oben verwenden.
add_action('init', function () {
if (headers_sent()) return;
@ini_set('session.cookie_httponly', '1');
}, 1);
| Header | Value |
|---|---|
| cache-control | no-cache, private |
| content-encoding | zstd |
| content-security-policy | default-src 'self'; base-uri 'self'; form-action 'self'; frame-ancestors 'none'; object-src 'none'; script-src 'self' 'nonce-KSWwx5nWvtZWXQaZ3xgy+w=='; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self'; frame-src https://www.google.com https://maps.google.co |
| content-type | text/html; charset=utf-8 |
| cross-origin-opener-policy | same-origin |
| cross-origin-resource-policy | same-origin |
| date | Tue, 08 Sep 2026 12:45:40 GMT |
| origin-agent-cluster | ?1 |
| permissions-policy | accelerometer=(), autoplay=(), bluetooth=(), camera=(), display-capture=(), encrypted-media=(), fullscreen=(self), gyroscope=(), magnetometer=(), microphone=(), midi=(), payment=(), screen-wake-lock=(), serial=(), usb=(), xr-spatial-tracking=(), geolocation=(self "https://www.google.com") |
| referrer-policy | strict-origin-when-cross-origin |
| server | FrankenPHP Caddy |
| set-cookie | XSRF-TOKEN=eyJpdiI6IkEzVDdDbDlxWmd0OVA4RXhRYVlZelE9PSIsInZhbHVlIjoiTmtiMUhtNlp3bzdXZXNLbDBnem9VYlIvR2MrOGZXZkw5TkloaHFsb0diRkhvU01RVS85dWJiemNqOXgyaVdMOGVIYzhpNHlOZEZvcWtjdVloa2IxaXQ4Z3I5YTNPMEJDOU1iTjB0djBHTFF3TWNDZG5kdzFaYlIxYnZXOTEzK0oiLCJtYWMiOiJiOTkzYjA0ZDcyOTY4MDUzODE3NmZjYjY1NTM5YjBlNTA2NTZmY |
| strict-transport-security | max-age=31536000; includeSubDomains; preload |
| vary | Accept-Encoding |
| x-content-type-options | nosniff |
| x-frame-options | DENY |
| x-permitted-cross-domain-policies | none |
| x-xss-protection | 0 |