All checks
Every rule has a fixed id, so you can refer to it in tickets. Open a card to see how it is checked, how to fix it and where the code lives.
Results
- passNothing to do.
- failrechtzeitig is sure something is missing or wrong.
- warnA pattern matched that a person should look at.
- infoA list of things to judge yourself.
- skipThe check does not apply, for example no URL was given.
The severity says how much a finding matters, from info to critical. Website checks run when you give a URL. Repository checks run when the workflow checks out your repository first. Lockfiles read: package-lock.json, pnpm-lock.yaml, yarn.lock, composer.lock, pubspec.lock, Cargo.lock, uv.lock, poetry.lock, requirements*.txt, go.mod.
Sources are primary sources only: laws, courts, authorities, standards bodies, and vendor documentation for technical facts. Blogs and law firm articles are never cited. Each card shows when its sources were last reviewed; a rule not reviewed for a year fails the project's tests.
What runs when
Checks that are off show as skip, with the reason and the setting that turns them on. A check marked Sends data asks an outside service; the badge links to what is sent.
| Check | Runs when |
|---|---|
| All website checks | Only with a url. |
| All repository checks | Only when actions/checkout runs before rechtzeitig (folder: input repository). |
| A group of checks | modules picks groups: legal, privacy, security, sustainability, accessibility, repo. Empty runs all. |
| Cancellation button for subscriptions LEG-DE-BTN-001 | Opt-in: only with subscriptions: true. |
| Withdrawal button for online contracts LEG-DE-BTN-002 | Opt-in: only with sales: true. |
| Privacy policy names transfers outside the EU LEG-EU-DSE-005 | Opt-in: only when the secret IPINFO_TOKEN is set (input ipinfo-token, token from ipinfo.io). Without it the check is skipped and nothing is sent.Sends data to ipinfo.io (opt-in) |
| No dependencies with known vulnerabilities SEC-DEPS-001 | On by default; sends data to api.osv.dev. Turn it off with vulnerabilities: false.Sends data to api.osv.dev |
The rules
Legal 9 rules
LEG-DE-BTN-001high Cancellation button for subscriptions § 312k BGB (German Civil Code) How it is checked
- How it is checked
- Finds a button labeled "Verträge hier kündigen" on the start page (
cancelinlang/*.yml, elsecancel_similaron the visible text, which warns) and "jetzt kündigen" (cancel_confirm) on its target page; info when it cannot be followed. - Runs when
- Opt-in: only with
subscriptions: true. - How to fix
- Offer an always available link "Verträge hier kündigen", without login, that leads to a page with a "jetzt kündigen" button.
- Sources
- gesetze-im-internet.de
- Reviewed
LEG-EU-DSE-003medium Forms link to the privacy policy Art. 13(1) GDPR How it is checked
- How it is checked
- For every form with email, name, phone, address or birth date fields, looks for a privacy link or wording (
privacyinlang/*.yml) inside the form or its container. Ignores login forms. - How to fix
- Explain next to the form what the data is used for and link the privacy policy.
- Sources
- eur-lex.europa.eu
- Reviewed
LEG-DE-IMP-002high Imprint contains the required details § 5(1) DDG How it is checked
- How it is checked
- Searches the imprint text for email, phone or contact form (IBANs ignored), German postcode (register numbers ignored), VAT ID and register number.
- How to fix
- Give name, postal address, email address and a second fast way of contact, plus register entry and VAT ID if you have them.
- Sources
- gesetze-im-internet.de
- Reviewed
LEG-DE-IMP-001high Imprint is linked and reachable § 5 DDG (German Digital Services Act) How it is checked
- How it is checked
- Finds the imprint link on the start page (
imprint), loads it and checks HTTP status and that it has text. - How to fix
- Link the imprint from every page, for example in the footer, labeled "Impressum".
- Sources
- gesetze-im-internet.de
- Reviewed
LEG-DE-IMP-003medium Imprint and privacy policy are linked on every page § 5 DDG, Art. 12 GDPR How it is checked
- How it is checked
- Looks for imprint and privacy links on every visited page of the site.
- How to fix
- Put both links in a shared layout (footer) that every page uses, including apps and sub-sections.
- Reviewed
LEG-EU-ODR-001medium No link to the closed EU dispute platform Regulation (EU) 2024/3228 How it is checked
- How it is checked
- Looks for links to or mentions of the closed EU dispute platform (
odrindata/outdated-links.yml) on every visited page. - How to fix
- Remove the link and the notice. The platform closed on 20 July 2025. The statement under § 36 VSBG on whether you take part in consumer dispute resolution stays required, unless you have 10 employees or fewer.
- Reviewed
LEG-EU-DSE-002medium Privacy policy covers the required topics Art. 13 GDPR How it is checked
- How it is checked
- Searches the privacy policy for 11 topics (
controller,storage_period,right_*... inlang/*.yml). - How to fix
- Add the missing topics: controller, legal basis, storage period, data subject rights, right to complain.
- Sources
- eur-lex.europa.eu
- Reviewed
LEG-EU-DSE-001high Privacy policy is linked and reachable Art. 12, 13 GDPR How it is checked
- How it is checked
- Finds the privacy link on the start page (
privacy), loads it and checks HTTP status and that it has text. - How to fix
- Link the privacy policy from every page, for example in the footer, labeled "Datenschutz".
- Sources
- eur-lex.europa.eu
- Reviewed
LEG-DE-BTN-002high Withdrawal button for online contracts § 356a BGB (German Civil Code, since 19 June 2026) How it is checked
- How it is checked
- Finds a button labeled "Vertrag widerrufen" on the start page (
withdrawinlang/*.yml, elsewithdraw_similaron the visible text, which warns) and "Widerruf bestätigen" (withdraw_confirm) on its target page; info when it cannot be followed. - Runs when
- Opt-in: only with
sales: true. - How to fix
- Offer an always available, prominent "Vertrag widerrufen" function leading to a form with a "Widerruf bestätigen" button; confirm receipt electronically.
- Sources
- gesetze-im-internet.de
- Reviewed
Privacy and consent 6 rules
LEG-EU-CNS-004high Optional cookie categories are not preselected § 25 TDDDG, ECJ C-673/17 (Planet49) How it is checked
- How it is checked
- Finds ticked, enabled checkboxes whose label is an optional category (
consent_optional), also in shadow roots. - How to fix
- Leave statistics, marketing and similar categories unticked by default.
- Reviewed
LEG-EU-CNS-003high Consent banner can be rejected on the first layer § 25 TDDDG, Art. 7(3) GDPR How it is checked
- How it is checked
- In dialogs, cookie containers and shadow roots of the start page, looks for an accept button (
consent_accept) without a reject button (consent_reject). - How to fix
- Offer an equal "Reject all" button right next to "Accept all".
- Reviewed
LEG-EU-CNS-002high No cookies before consent § 25 TDDDG (German Telecommunications Digital Services Data Protection Act), BGH I ZR 7/16 (Cookie-Einwilligung II) How it is checked
- How it is checked
- Lists cookies and localStorage set while loading the site without clicks; matches names against
data/third-parties.yml. - How to fix
- Set only strictly necessary cookies right away, all others only after consent.
- Reviewed
LEG-EU-DSE-005medium Privacy policy names transfers outside the EU Sends data to ipinfo.io (opt-in) Art. 13(1)(f), Art. 44 ff. GDPR, ECJ C-311/18 (Schrems II) How it is checked
- How it is checked
- Gets the country of each third-party service (
countryindata/third-parties.yml, else IPinfo) and, for countries outside the EEA (data/countries.yml), looks forthird_countrywording in the privacy policy; info when no country is known. - Runs when
- Opt-in: only when the secret
IPINFO_TOKENis set (inputipinfo-token, token from ipinfo.io). Without it the check is skipped and nothing is sent. - How to fix
- Name the country and the safeguard for each service outside the EU/EEA (for example Data Privacy Framework, standard contractual clauses).
- Reviewed
LEG-EU-CNS-001high No third-party servers before consent Art. 6(1) GDPR, § 25 TDDDG, LG München I 3 O 17493/20 (Google Fonts) How it is checked
- How it is checked
- Records every request to another site while loading pages without clicks, groups hosts by vendor from
data/third-parties.yml(else by domain);consent: requiredvendors fail, others warn. - How to fix
- Host fonts, scripts and libraries yourself; load embeds (videos, maps) only after a click or consent.
- Reviewed
LEG-EU-DSE-004medium Privacy policy names the services the site uses Art. 13(1)(e) GDPR How it is checked
- How it is checked
- For every contacted third-party service, looks for its name (
namesindata/third-parties.yml, else its domain) as a whole word in the privacy policy. - How to fix
- List every embedded service with purpose and legal basis in the privacy policy.
- Sources
- eur-lex.europa.eu
- Reviewed
Security 9 rules
SEC-HDR-002medium Cookies use secure flags Art. 32 GDPR How it is checked
- How it is checked
- Checks Secure on every cookie set without login (HTTPS sites, and always with
SameSite=None) and HttpOnly on cookies whose name looks like a session (data/cookies.yml); cookies of other sites only give info. - How to fix
- Set cookies with Secure; session cookies also with HttpOnly and SameSite=Lax.
- Sources
- eur-lex.europa.eu
- Reviewed
SEC-DNS-001medium Domain is protected against email spoofing Art. 32 GDPR How it is checked
- How it is checked
- Reads the SPF TXT record of the registrable domain and the DMARC record at
_dmarc.; flags missing ones, SPF that allows every server (+all,?all) and DMARCp=none. - How to fix
- Publish SPF and DMARC records; a domain without mail needs only "v=spf1 -all" and "v=DMARC1; p=reject".
- Sources
- eur-lex.europa.eu
- Reviewed
SEC-EXP-002medium Error pages reveal no internals Art. 32 GDPR How it is checked
- How it is checked
- Requests the error paths from
data/probes.yml, searches their visible text for the traces indata/leaks.ymland the headers of the start page and error pages for version headers. - How to fix
- Turn off error output in production (for example display_errors=0, DEBUG=false) and remove version headers.
- Sources
- eur-lex.europa.eu
- Reviewed
SEC-EXP-001critical No private files are public Art. 32 GDPR How it is checked
- How it is checked
- Requests the file paths from
data/probes.yml; a 200 whose body matchesexpectfails. - How to fix
- Remove the files from the web server or block access to dot files and backups; change any credentials they contain.
- Sources
- eur-lex.europa.eu
- Reviewed
SEC-HDR-001low Security headers are set Art. 32 GDPR How it is checked
- How it is checked
- Reads the response headers of the start page (HSTS, CSP, X-Content-Type-Options, Referrer-Policy, frame protection) and accepts CSP and Referrer-Policy from <meta> tags, which browsers apply too.
- How to fix
- Set the missing headers in the web server or hosting. CSP and Referrer-Policy also work as <meta> tags; frame-ancestors and nosniff only work as headers.
- Sources
- eur-lex.europa.eu, w3.org
- Reviewed
SEC-DNS-002low www and non-www addresses both work Art. 32 GDPR How it is checked
- How it is checked
- Requests the domain with
www.added or removed and follows redirects. - How to fix
- Get a valid certificate for both addresses and redirect one to the other.
- Sources
- eur-lex.europa.eu
- Reviewed
SEC-TLS-001high Site uses HTTPS Art. 32 GDPR How it is checked
- How it is checked
- Checks that the start page is HTTPS and that plain
http://redirects to HTTPS. - How to fix
- Enforce HTTPS and redirect http:// to https:// with a 301.
- Sources
- eur-lex.europa.eu
- Reviewed
SEC-TLS-003medium No unencrypted resources on HTTPS pages Art. 32 GDPR How it is checked
- How it is checked
- Lists
http://requests made by pages of an HTTPS site. - How to fix
- Load every resource over https://.
- Sources
- eur-lex.europa.eu
- Reviewed
SEC-TLS-002high TLS certificate is valid and current Art. 32 GDPR How it is checked
- How it is checked
- Opens a TLS connection to the host and reads protocol, trust and expiry date of the certificate.
- How to fix
- Renew the certificate automatically (for example Let's Encrypt) and allow only TLS 1.2 and 1.3.
- Sources
- eur-lex.europa.eu
- Reviewed
Sustainability 2 rules
SUS-JS-002low Start page shows content without JavaScript Technical, no single law How it is checked
- How it is checked
- Compares the visible text of the start page with JavaScript off and on and warns when less than 20 % of it is shown without JavaScript.
- How to fix
- Deliver content as HTML from the server or at build time.
- Reviewed
SUS-JS-001medium Imprint and privacy policy work without JavaScript § 5 DDG (easily recognizable, directly accessible), Art. 12(1) GDPR (easily accessible form) How it is checked
- How it is checked
- Checks that imprint and privacy links (
imprint,privacyinlang/*.yml) exist with JavaScript off and that the linked page that loaded shows at least 100 characters of text without it. - How to fix
- Deliver the links and texts of the legal pages as static HTML.
- Reviewed
Accessibility 1 rule
A11Y-LANG-001low Page declares its language BFSG with § 3 BFSGV; EN 301 549 V3.2.1 clause 9.3.1.1 (WCAG 2.1 success criterion 3.1.1) How it is checked
- How it is checked
- Reads
<html lang>of the start page as the server sent it (JavaScript off) and compares it with the chosen language. - How to fix
- Set the lang attribute on <html>, for example <html lang="de">.
- Reviewed
Repository 8 rules
SEC-DEPS-005low GitHub Actions are pinned to a commit CRA Art. 13(5), due diligence for third-party components (from 11 Dec 2027) How it is checked
- How it is checked
- Reads
uses:lines in.github/workflows/*.ymland lists actions not pinned to a 40-character commit SHA. - How to fix
- Use owner/action@<commit-sha> instead of a tag; Dependabot keeps the SHAs current.
- Sources
- eur-lex.europa.eu
- Reviewed
SEC-DBAI-001critical Database rules do not open data to everyone Art. 32 GDPR How it is checked
- How it is checked
- Splits
supabase/**/*.sqlinto statements and comparescreate tablein the public schema withenable row level security; looks forif trueand test mode (request.time < timestamp.date(...)) in Firebase rules. - How to fix
- Enable row level security on every table and replace "if true" and test-mode rules with checks on the signed-in user.
- Reviewed
SEC-DEPS-003medium Dependency updates are automated CRA Annex I Part II(2) (from 11 Dec 2027), Art. 32 GDPR How it is checked
- How it is checked
- Looks for
.github/dependabot.yml(and which ecosystems it covers), Renovate config, or vulnerability scanners in workflows, as listed indata/update-tools.yml. - How to fix
- Set up Dependabot or Renovate for every ecosystem in use.
- Sources
- eur-lex.europa.eu
- Reviewed
SEC-SECRETS-002high .env files stay out of git Art. 32 GDPR How it is checked
- How it is checked
- Lists committed
.env*files, also with several suffixes like.env.production.local(templates and fixtures excluded), and checks that.gitignoreignores.env. - How to fix
- Add .env to .gitignore; revoke committed values and remove them from the history.
- Sources
- eur-lex.europa.eu
- Reviewed
LEG-DE-LIC-001medium Dependency licenses fit the project §§ 31, 69c UrhG (German Copyright Act) How it is checked
- How it is checked
- Compares licenses from npm and Composer lockfiles with the project license (package.json, composer.json or LICENSE) using the groups in
data/licenses.yml; an SPDXORwith a non-copyleft choice is not flagged. - How to fix
- Review the license of each flagged dependency; replace it, buy a license or license the project to match.
- Sources
- gesetze-im-internet.de
- Reviewed
SEC-DEPS-002low Dependencies are locked and listed in an SBOM CRA Annex I Part II(1) (from 11 Dec 2027) How it is checked
- How it is checked
- Reads all lockfiles (
src/repo/lockfiles.ts) for the SBOM the report writes torechtzeitig-sbom.cdx.json, and lists manifests without a lockfile in their folder or a parent folder. - How to fix
- Commit a lockfile for every manifest; keep the SBOM with each release. The CRA covers products with digital elements made available in the EU, usually not pure web services.
- Code
checks/repo/sbom- Sources
- eur-lex.europa.eu
- Reviewed
SEC-SECRETS-001critical No secrets in the repository Art. 32 GDPR How it is checked
- How it is checked
- Matches tracked files line by line against
data/secrets.yml, decoding JWT payloads where a pattern names claims (Supabaseservice_rolekeys); shows only the first 4 characters and the length of each find. - How to fix
- Revoke found keys right away, then remove them from code and git history and store them as secrets or environment variables.
- Sources
- eur-lex.europa.eu
- Reviewed
SEC-DEPS-001high No dependencies with known vulnerabilities Sends data to api.osv.dev Art. 32 GDPR, CRA Annex I Part I(2)(a) and Part II(2) (from 11 Dec 2027) How it is checked
- How it is checked
- Sends the package URLs of all locked components to the OSV API and loads details for up to 100 issues; high and critical issues in production dependencies fail.
- Runs when
- On by default; sends data to api.osv.dev. Turn it off with
vulnerabilities: false. - How to fix
- Update the affected packages to at least the fixed version shown.
- Sources
- eur-lex.europa.eu, osv.dev
- Reviewed
No check matches. Try fewer filters.
Rule ids
| Prefix | Area |
|---|---|
LEG-DE | German law (DDG, BGB, UrhG) |
LEG-EU | EU law (GDPR, ePrivacy as § 25 TDDDG) |
SEC | Security |
A11Y | Accessibility (BFSG) |
SUS | Sustainability |
Words and languages
Checks look for words like "Impressum", "Datenschutz" or "Alle ablehnen". The words live in one file per language, currently German and English. Pick the language of your site when you start the run; the page language check tells you if the choice looks wrong.