17 changes
Configuration, quality checks, team access and a round of fixes
- +New accounts receive the welcome sequence — day 1, day 3 and day 5 — and the two-day "anything blocking your first scan?" note. Accounts created from today onwards enter the sequence; nobody receives a backlog of older messages.
- +A page that cannot load your data says so instead of showing you an empty one. This covers your security checklist, account activity log, team, team scans, trend chart and saved scan intent — and the checklist no longer saves over itself when it could not load.
- +Site-verification tokens are no longer reported as possible secrets. Google, Bing, Yandex and Facebook domain-ownership tokens are published on purpose — Next.js renders them into a meta tag on every page — so flagging them cost you grade for doing the right thing. Secret detection also now weighs the name a value is assigned to, so a credential called something like `apiKey` is caught even when the value itself looks unremarkable. Your next scan may report secrets earlier ones did not.
- +The compliance page now covers NIST SP 800-53, the CIS Critical Security Controls and the HIPAA Security Rule, alongside SOC 2, ISO 27001, OWASP and CWE. Each finding maps to specific controls, with the control's official title shown so a reviewer can check it. As before, this is an informational mapping to help you answer a security questionnaire — not an audit, a certification, or a claim that any control is satisfied. Long control lists collapse, so a tab opens on what matters.
- +Long lists are paged. A scan report showed every finding at once — up to 500 full cards on one page — and now shows 25 at a time, worst first, so the criticals are always on the first screen. Links that jump straight to a finding still land on it, whichever page it is on. Your saved questionnaire responses are paged the same way.
- +A pull request whose scan failed gets scanned on the retry. GitHub re-sends a delivery when a scan does not complete, but the record we write to avoid scanning the same pull request twice was also swallowing those retries — so a scan interrupted by a timeout or a transient error left the pull request with no check at all, looking exactly like the App not being installed. An interrupted scan now releases its claim, and a completed one is still never repeated.
- +Downgrading from Team now removes team seats, whichever plan you move to. Moving to Indie left every member active, so ex-teammates kept a stale membership that locked them out of managing their own billing. Separately, "Free Months Earned" on the referral panel now counts credits that were actually applied to your account rather than conversions — a referral that converted while the credit could not be applied is shown as pending instead of counted as paid.
- +The unprotected-payment-webhook check no longer reads comments as code. A file that calls the Stripe API and happens to explain itself — mentioning a webhook, or naming an event type in a sentence — could be reported as a critical unprotected webhook even when nothing external can reach it. The check now looks at code only, in both directions: a comment can no longer raise the finding, and can no longer silence it on a webhook that really is unprotected.
- +Four operations now finish what they promise. Deleting your account stops rather than proceeding if the subscription cannot be cancelled first, so a closed account can no longer keep billing. The free Trust Page success screen says plainly when we could not email your Edit URL — it is the only way back in, so save it. Removing a team member permanently deletes their scans first, so a failure leaves the action retryable. And a CLI login that times out no longer permanently consumes an API key slot.
- +New: a second catalogue of checks, about correctness rather than security. The scanner's 214 rules ask whether your code can be attacked. These twelve ask whether it tells the truth — a page that shows an empty list when the database was unreachable, an action that reports success it never got, a record written before the payment it stands for, a control only a mouse can reach. They are reported separately from security findings and are not counted among the 214.
- +`// VC###-OK:` and `// scanner-OK:` now work on every rule. They were described as a general mechanism and applied to only a handful, so on most rules the comment did nothing and said nothing. `rules.disable` now applies to every engine, not just the VC rules — entropy, config, cross-file, dependency, semgrep and gitleaks findings too. Also honoured: `scan.exclude`, `scan.extensions`, `scan.maxFileSize`, `output.format`, `output.verbose` and `ai`. The GitHub Action gains a `fail-on-quality` input.
- +The Custom Rules tab in Settings is gone. It let you write rules and saved them in your browser, but no scan ever read them, so nothing written there affected a result. It was labelled "Not applied to scans yet"; now it is removed rather than pending. To turn off a built-in rule, use `rules.disable` in `.xploitscanrc`, or `.xploitscanignore` to scope one to certain paths.
- +Three checks decided things by searching the whole file, so a second component in the same file could answer for the first. An autosave warning could be raised from an unrelated component's state, and a stale-response warning from an unrelated input. All three now resolve names the way the language does, and a new test runs every published example twice — once with a neighbouring component added — so this cannot come back quietly.
- +Every scan now runs a second set of checks beside the security rules. They look for code that runs without error and quietly reports something that did not happen — an empty list because the request failed, a "Saved" that never landed, a control only a mouse can reach. Free on every plan, in their own section, never counted toward your security grade. Worked examples for each at /quality.
- +Two checks were narrowed to stop reporting correct code, and the narrowing was too tight. A failed read shown as an empty state went unreported when the response was cast, destructured or assigned rather than declared; an autosave armed by a failed load went unreported in any file with a second component using the same flag name. Both now match on shape rather than one spelling, each pinned by a test.
- +Admins can invite teammates again. The invite form was offered to them and then refused with an upgrade prompt for a plan their team already had. A membership row left behind by an ended plan also no longer restricts the person holding it — it could block them from the billing portal and from scanning on their own account. Roles are now read from a team with a live subscription, so they end when it does.
- +Cancelling a Team plan now clears its seats. Members' rows previously stayed active after the final invoice, and the team trend chart kept aggregating their scans. Both halves are fixed: cancellation deactivates non-owner seats, and the trend endpoint checks the team owner's subscription the way every other team endpoint already does. Teams inside Stripe's payment-retry window keep full access, and personal trends are unaffected.