# QA results — v1.0.0 (2026-11-02)

| Suite | SQLite | MariaDB 10.11 | Real Apache 2.4 + PHP 8.3 |
|---|---|---|---|
| End-to-end flows (qa/flows.py) | 254/254 | 254/254 | 254/254 |
| Attack suite (qa/attack.py) | 111/111 | 109/109 (one SQLite-only check) | 111/111 |
| Paystack money path (qa/pay.py) | 18/18 | — | — |
| Apache .htaccess checks (qa/apache_checks.sh) | — | — | 32/32 |
| Static gates (qa/gates.py) | 900 passed | | |
| Backup restore + setup re-run (qa/restore.sh) | — | pass | — |
| sqlmap (public + 3 admin endpoints) | not injectable | | |

## Mutation sweep (each a real vulnerability planted on purpose)

```
[01] csrf-check-removed     BITES sqlite (18s)  FAIL: POST without CSRF token refused
[02] idor-invoice           BITES sqlite (29s)  FAIL: another client cannot open Kwame's invoice (404, not 403)
[03] escape-raw             BITES sqlite (30s)  FAIL: script in body is shown as text, never run
[04] svg-allowed            BITES sqlite (29s)  FAIL: SVG refused (it can carry script)
[05] safe-next-open         BITES sqlite (30s)  FAIL: open redirect / header injection blocked for next='https://evil.example'
[06] totp-replay            BITES sqlite (29s)  FAIL: the same code cannot be replayed from another browser
[07] no-throttle            BITES sqlite (30s)  FAIL: more than 10 messages an hour from one IP: refused (10, not 5: mobile networks share IPs)
[08] csp-frame              BITES sqlite (30s)  FAIL: CSP on /
[09] like-backslash-mysql   BITES mysql (30s)  FAIL: insight search works and is noindex
[10] like-backslash-gate    BITES sqlite (0s)  FAIL: backslash LIKE escape in jocyt_site/app/controllers/public.php
[11] gate-inline-style      BITES sqlite (0s)  FAIL: style attribute (blocked by CSP) in jocyt_site/app/views/public/home.php
[12] gate-status-419        BITES sqlite (0s)  FAIL: non-standard HTTP status 419 in jocyt_site/app/lib/security.php
[13] role-check-invoices    BITES sqlite (3s)  FAIL: editor cannot open /invoices (closes the hole mutation role-check-invoices found)
[14] paystack-amount        BITES sqlite (6s)  FAIL: Paystack says 1 pesewa short: invoice stays unpaid
[15] webhook-unsigned       BITES sqlite (7s)  FAIL: webhook signed with the wrong key refused
[16] mass-assign            BITES sqlite (3s)  FAIL: mass assignment: id and created_at in the form are ignored
[17] mrr-door-active-only   BITES sqlite (36s)  FAIL: MRR tile links to the paying filter
mutations: 17 of 17 bite
```
