Does your app tell the truth about what it did?
These 12 checks are not security rules. They look for a different kind of defect: code that runs without error and quietly reports something that did not happen. A page that shows an empty list because the database was unreachable. A button that says “Saved” after a request that failed. A table header only a mouse can sort.
They are the defects an AI coding agent is least likely to catch, because the code it wrote is syntactically correct, type-checks, and does not throw. The failure only appears at runtime, to a user, on a path nobody tested.
Quality findings are reported separately from security findings and never affect your security grade. They run free, on every scan, on every plan.
How these were built
Every rule here began as a real defect found in this product, was handed to a review whose only job was to find correct code that would trip it, and ships only with the narrowing that survived. Four candidates did not survive and are not here. Each rule's page states the narrowing it shipped with, because a check you cannot audit is a check you have to take on faith.
Accessibility
This element is styled and wired as a button but is not one: it has a click handler and no role, no tabIndex and no key handler, so it cannot be reached by Tab, activated by Enter or Space, announced by a screen reader, or driven by voice control. Anyone not using a mouse cannot perform this action at all.
This full-screen overlay renders a panel with controls in it, but declares no dialog semantics: no role, no aria-modal, no Escape handler and no focus management. A screen reader announces nothing when it opens and keeps reading the page behind it, and a keyboard user has to tab through the covered page to reach the controls — or tabs straight past them into content they can see is obscured.
This <label> has no htmlFor and no id, and the field beside it carries no name of its own, so the two are never connected. Clicking the text does not focus the field, a screen reader announces the input as unlabelled, voice control has no name to address it by, and browser autofill loses the hint it uses to fill the form.
Authentication
Correctness
This handler answers a read failure with a success status and an empty payload, so callers cannot tell a broken query from an account that genuinely has no data. Pages render their empty state, and anything that saves after loading can write that emptiness back.
This handler fires a destructive write, never looks at whether it succeeded, and then tells the user it worked — a success toast, an optimistic row removal, or a redirect. When the server rejects the request the user is left believing a key was revoked, a member removed or a session ended when none of it happened.
This handler moves a row out of its pending state and only then makes the payment or entitlement grant that the row stands for, with the failure swallowed. If the transfer fails the record still reads as settled, the money never moved, and nothing will look at that row again because it no longer matches the pending query.
This loader turns a failed or unexpected response into an empty list and renders it, so the page shows the same thing it would show a brand-new account: no sessions, no scans, no members. Nothing tells the user the request failed, and anything they do next — including saving — acts on data the app never actually received.
The flag that permits this component to write the user's state back is set in a `finally`, so a load that failed arms it exactly like one that succeeded — while the component is still holding the empty values it initialised with. Opening the page during a blip is enough to write those empties over whatever the user had saved, and the write looks like any other.
When this setting is absent the handler returns early — with the same success payload it returns when the work actually happened. The caller cannot tell the two apart, so a request that did nothing is reported as one that did: the row was never written, and whoever asked is told it was.
This effect refetches whenever the user changes their selection, and does nothing to cancel the request already in flight. Pick one thing, then another before the first answers, and the first response lands last and wins: the selector says one thing and the panel shows another. Nothing errors, the data is real — it is just the wrong data, and it stays wrong until the next interaction.
Performance
Run these on your own code
Every scan runs them. Nothing to configure, and they never fail your build unless you ask them to.
npx xploitscan scan .Or paste a file into the scanner. Looking for the security rules instead? Browse those here.