Methodology
How the audit actually runs.
Seven steps, a five-level severity model, and nine fields on every finding. Published because a process you cannot inspect is a promise, not a method. Every example below is a real record from auditing our own work, not an illustration.
The seven steps
Discover
What the business does, who uses it, and what the system is supposed to do. Without this an audit produces a list of technical defects with no idea which of them costs you money.
You receive: a written scope naming the pages, journeys and systems in and out of bounds, agreed before any testing starts.
Map
The critical journeys get written down as steps, with the expected behaviour at each one. A defect is only a defect against a stated expectation.
You receive: the journey list we will test, so you can tell us we have missed one before we spend the time.
Test
Automated first, because machines are better at coverage. Transport and security headers against OWASP Secure Headers, the accessibility tree against WCAG 2.2 AA with axe-core in a real browser, Core Web Vitals with Lighthouse, then a human pass over what tools cannot judge.
You receive: the raw run output alongside the report, so every number is traceable.
From our own work: the WCAG sweep across wcag2a, 2aa, 21a, 21aa and 22aa returns 0 violations on each of the ten pages that make up this site. The same sweep against our six product demo pages returns 84 failing elements. Both numbers come from the same run, which is the point: a tool that only ever reports zero is not measuring anything.
Break
Edge cases, bad input, and the paths nobody designed for. This is where the defects that reach production actually live, because the happy path is the one everybody already tested.
You receive: reproduction steps for every failure we can trigger, including the ones you will decide not to fix.
From our own work: our own scanner accepts a URL from a stranger, so we attacked it. It now refuses credentials embedded in a URL, non-standard ports, every reserved IPv4 and IPv6 range, IPv4-mapped IPv6 such as ::ffff:127.0.0.1, and decimal and octal spellings of loopback. It re-checks every redirect hop, because a 302 into a private address is the standard way past a check that only looks at the first request. Nineteen tests hold those open.
Document
Every finding carries the same nine fields. Not a slide of recommendations: a defect record a developer can act on without a meeting.
You receive: the findings, worst first, each with evidence attached.
From our own work: the record shape is enforced in code, not in a template. Our finding builder throws rather than emit a record missing any of the nine fields, and a test asserts that for every field in turn. A report is only as trustworthy as its weakest row.
Prioritize
Cosmetic separated from business-critical, so you can spend a fixed budget on the things that actually matter. Severity is assigned against the published definitions below, not by feel.
You receive: a quick-wins list and a severity-ranked backlog.
From our own work: nothing is promoted to Critical automatically. axe's own scale measures harm to an assistive-technology user; ours measures business impact. They are different axes, so an axe "critical" enters our report as High. Critical means a workflow cannot be completed, and only a human who has run that workflow can establish it.
Verify
Fixes are retested against the original finding. A closed ticket is not evidence; a passing retest is.
You receive: a second run showing which findings are actually resolved, and which regressed.
From our own work: this is the credential behind the whole practice. A full automated regression suite was built and maintained for a transportation software company, covering payment, order fulfilment and job quotation systems. The same discipline runs our own tooling: our trading engine holds a sizing feature at 2x until 25 closed trades have tested it, because a multiplier the log cannot yet justify should not be trusted.
Severity, defined
Published so you can argue with a rating. Each row carries a real example from auditing our own systems.
| Level | Definition | Real example from our own audits |
|---|---|---|
| Critical | System failure, severe security issue, major business disruption, or inability to complete a critical workflow. | None on our own site. The check that would raise one is a page served over plain HTTP, which we test for and have never triggered here. |
| High | Major functionality failure or significant user or business impact. | A missing viewport meta tag. Every mobile visitor gets a desktop-width layout scaled down, which is the most common reason a phone visitor leaves. |
| Medium | Meaningful usability or functional problem that does not completely block the user. | A tagline on our own AnswerWeave demo at 1.98:1, where a legacy brand cyan is used as text on a light background. Readable to most, unreadable to some. |
| Low | Minor defect, inconsistency, or improvement opportunity. | Our own Content-Security-Policy currently ships report-only, so it reports violations without blocking them. The worked finding below is that one, verbatim. |
| Enhancement | Not broken, but an opportunity to improve UX, efficiency, clarity or conversion. | A missing Permissions-Policy header. Nothing is wrong; the powerful browser features the site never uses could simply be denied outright. |
One finding, in full
This is not a sample. It is the output of running our own scanner against this website, unedited, including the fact that it is a finding against us.
Content-Security-Policy is report-only, so it does not block anything
- Location
- https://russellspc.com/ , response headers
- Steps to reproduce
curl -sI https://russellspc.com/; note only the -Report-Only variant is present.- Expected behaviour
- An enforcing Content-Security-Policy once the report-only policy is clean.
- Actual behaviour
- Only Content-Security-Policy-Report-Only is set. Violations are reported but permitted.
- Business impact
- The policy provides monitoring but no protection: an injected script still runs.
- Severity
- Low. The policy is a defence in depth measure, and the site has no user-generated content, so the exposure is bounded.
- Recommendation
- After a clean console sweep across every template, promote the policy to the enforcing header.
- Evidence
- content-security-policy-report-only: default-src 'self'; script-src 'self' 'unsafe-inline'; ...
What we refuse to do
- A timeout is never recorded as a zero. A measurement that did not complete is reported as not measured. We learned this the hard way: one of our own tools was recording a 79 second performance-API failure as a near-zero speed score, for a site that answered in 0.36 seconds. That report would have told a business their site was slow when it was not. The rule is now enforced in code, with a test named after it.
- A check we cannot run is deferred, not passed. Every report carries a "what we could not test" section listing each skipped check and why. Coverage is reported as a fraction, and a run with anything deferred is never described as complete.
- We respect robots.txt and bot challenges. A path your own crawl rules disallow is not fetched, and a robots.txt we cannot even retrieve is not treated as permission. Bypassing either requires your written authorisation, and the report records that it was used.
- We will say when we cannot help. If the problem is outside what we can test honestly, we say so and decline rather than bill for a document.
- No number we did not measure. If a figure appears in your report, the raw run that produced it ships alongside.
Don't assume it works. Prove it.
Start with the free instant check to see the format, or tell us what to test and we will scope it in writing before any work begins.