Skip to main content

This is a test site with dummy HMRC services. Do not enter real personal information. How it works.

Security, GOV.UK and usability review

10 October 2026: dependencies, forms, headers, sign-in limits, GDS-Check and the GOV.UK checklist.

This review covers the service after it was made general: nothing in it is specific to one app (HMRC's Budget Payment Plan service is an ordinary organisation), payment plan amounts and the tax so far this year are capabilities any organisation can switch on for each way of use, and pages in the middle of a flow only open in order.

It is a review by the development team with automated tools. It does not replace the specialist accessibility audit, the penetration test or the data protection sign-off listed in the README under "Still to do before going live".

Summary

Area Result
Security No known vulnerabilities in the dependencies. 6 issues found and fixed (below). Security tests run on every page and form
Pages only in order No page in the middle of the calculator, payment plan, tax so far, account or admin flows opens without going through the pages before it. Tested locally and on the live site
GOV.UK and accessibility (GDS-Check, WCAG 2.2 AA) No proven or likely findings on any question page. Every journey ran to the end
Usability (GOV.UK Service Manual, Design System and HMRC patterns) All 21 checks pass, after 4 small fixes: a back link, two shorter sentences, and the email address filled in on the sign-in page after it is confirmed
Live site 61 of 61 checks pass, including the new options. One warning: the site has no database

Security

What was checked

Check How Result
Known vulnerabilities in dependencies pip-audit -r requirements.txt cryptography was affected by PYSEC-2026-3552 and is now 50.0.0. No known vulnerabilities remain
Secrets in the repository Searched what git tracks None. Local settings are in .env.local and the throwaway GDS-Check account journey is not committed (both gitignored)
CSRF tests/test_security.py posts to every form route without a token Every form refuses it
Security headers and cookies tests/test_security.py on every page Content Security Policy with a nonce for each request, X-Frame-Options: DENY; the session cookie is HttpOnly, SameSite and Secure (except when run locally over http)
Open redirects Apps' return addresses and the language switch tried with other sites All refused. The language switch also accepted /\host, which some browsers treat as another site: fixed
Escaping Every \| safe in the templates reviewed; request text sent back to pages The dummy Notify inbox showed request text unescaped: fixed. Banners now take plain text and escape it
Authentication Admin API, organisations' API, admin sign-in, customer accounts Keys and tokens required. Admin sign-in had no limit on wrong passwords; it now locks after 5. Customer accounts already locked
Rate limits Public API, organisations' API Organisations had limits and quotas; the public API had none. It now has a limit for each address
Organisations kept apart Journeys J25, J39 and J58 One organisation cannot see another's settings, results or administration. A journey link opened in a second browser is refused, and a result can only be collected by the organisation that started it
Capabilities tests/test_security.py A capability cannot be switched on for a way of use the organisation has closed
Notifications to apps Journey J62 and the live check Signed, and the dummy payroll app checks the signature
Pages only in order tests/test_flows.py, the live check No page in the middle of a flow opens directly; posting to a later page does not skip ahead
Personal data in logs Every log call in app/ The service logs page paths, task names, error types and notification attempts, not answers or personal details. Unexpected errors are logged with their trace, which could include a value from a request: worth checking when log storage is chosen

Recommendations

  • Switch off the API documentation page on a real service. /docs (Swagger UI) and /openapi.json are on by default so developers can try the API on the test site. Set ENABLE_API_DOCS=false and publish the documentation on HMRC's Developer Hub instead.
  • Link the database on the live site. The live site has no DATABASE_URL, so accounts and settings are lost each time Render restarts it. Link taxcalc-db to the web service in Render.
  • The penetration test and data protection sign-off are still needed before real customers use it.

GOV.UK and accessibility: GDS-Check

Every screen was scanned with GDS-Check (WCAG 2.2 AA and the GOV.UK Design System), each scan starting its own local server: the public pages (30 pages), the service overview (25), the admin pages (20) and 11 journeys through the calculator, the payment plan pages, the tax so far at Example Accountants, customer accounts, document reading, organisation settings and the dummy payroll app.

  • No proven or likely findings on any question page. The only proven findings are on /docs (61), which is Swagger UI, not a GOV.UK page.
  • Four journeys stopped part way on the first run because their files had fallen behind the pages (the offer to fill in answers from HMRC records, the residence question, GOV.UK One Login on the account page, and confirming the email address before signing in). The journey generator now walks the pages with the same settings as the local server, and the four were run again to the end.
  • The account journey found that after confirming their email address, people had to type it again to sign in (WCAG 3.3.7, redundant entry). The sign-in page reached from the confirmation link now has it filled in.

Left for review, with reasons:

Finding Why it is left
Only one way to find each page (WCAG 2.4.5) Pages in a transaction are steps in a process, which 2.4.5 excludes. The service is reached through GOV.UK navigation and search
Reading age of the service overview, admin pages and accessibility statement Written for people assessing or running the service. The accessibility statement follows the GOV.UK model wording
Help links in a different order on the account pages (WCAG 3.2.6) The footer is the same on every page. The scanner counts links to the privacy notice and terms in the account pages' text
"Key" used as an adjective It means an API key
No back link on sign-in, result and account home pages These are not question pages: there is no earlier answer to go back to
The email address asked for again when signing in later Signing in after signing out is a new process, and the browser can fill it in (autocomplete="email")
No check answers step in the document reading journey That scan stops at the sample documents page on purpose; the calculator's check answers page is covered by the other journeys
Pages of the dummy services They stand in for HMRC, GOV.UK One Login, Notify and an app, and are not part of the service

Usability: GOV.UK and HMRC checklist

Check Result
Start page with a "Start now" button and what you need before you start Pass
One thing per page Pass
Page title is the heading, the service name and GOV.UK; Error: in front when there is an error Pass, on every question page of the calculator, payment plan and tax so far flows (new tests/test_govuk_patterns.py)
One h1 on each page Pass (same test)
Back link on every question page Pass. The take-home pay page had none: fixed
Error summary at the top linking to each field, and a message by the field Pass (same test)
Error messages say what to do ("Enter…", "Select…") Pass
Optional questions say "(optional)" Pass
Nothing already given is asked for again in the same process (WCAG 3.3.7) Pass. The email address was asked for again after confirming it: fixed
Check your answers with Change links, and hidden text for screen readers Pass
A final button cannot be pressed twice Pass
Session timeout warning, and a page saying the answers were deleted Pass (HMRC timeout dialog)
Pages only open in order Pass
Works without JavaScript Pass
No "please" Pass (tested on every question page)
Sentences of 25 words or fewer on customer pages Two were longer, on the tax so far start page and the privacy notice: split
Skip link, lang="en" Pass
Footer: cookies, accessibility statement, privacy, terms, help, contact, Welsh services, licence and copyright Pass
Cookies Pass. Only essential cookies, so no cookie banner is needed; the cookies page lists them
Phase banner with a feedback link Pass (Beta). The test site shows a "Test site" banner instead
"Is this page not working properly?" link Pass
Page not found and service error pages in GOV.UK style Pass

Still outstanding (in the README): Welsh translations from HMRC's Welsh Language Unit, the specialist accessibility audit and research with users, including assistive technology users.

Live site

scripts/live_check.py now also checks pages only open in order, a payment plan amount and the tax so far (on Example Accountants' pages, inside Example Payroll App, and through Example Tax API's API for a fixed date, where it must be £1,760.22 exactly). On 10 October 2026 all 61 checks passed on https://uk-tax-calculator-5844.onrender.com. The one warning was that the site has no database.

Is this page not working properly? (opens in new tab)