Changelog

What's new in XploitScan

1 change

  • +Three of the new rules now catch more: JWTs decoded by hand (`JSON.parse(atob(token.split(".")[1]))`) are treated like any other unverified token, Django projects that allow every origin with credentials are flagged like FastAPI and Flask ones, and AI endpoints running as Cloudflare Workers are checked for a missing caller check.
1 change

  • +Nine new rules for the places AI-built apps leak most often: Supabase migrations that switch off row-level security or open writes to everyone, Firebase rules left open, AI and secret keys shipped to the browser, Base44 functions using the service role without checking the caller, roles read from user-editable metadata, unauthenticated AI endpoints, sessions trusted without verification, Python CORS wildcards with credentials, and prefix-only path checks. TanStack Start server functions are now checked for missing auth on the free plan.
6 changes

  • +Scanning a public GitHub repository by URL from the Scan page works again. The browser was blocking the requests to GitHub, so every GitHub URL scan stopped with "Failed to fetch".
  • +Install commands now end in `@latest` (`npx xploitscan@latest scan .`, `npx -y xploitscan-mcp@latest`). Without it, npx can keep running whichever version it cached the first time, so fixes never reach you. If your MCP config or scripts use plain `xploitscan-mcp` or `xploitscan`, add `@latest` to get current rules and fixes.
  • +A Pro or Team free trial includes everything on the plan you are trying, including all 214 rules in the CLI, GitHub Action, VS Code extension and MCP server. Free trials are limited to one per person.
  • +SQL injection detection now works in Express files that use route parameters. A route like `/users/:id` used to switch the SQL injection check off for the whole file, so a query built from `req.params` went unflagged. Update to CLI 1.12.4 or later; the web scanner and GitHub checks pick it up automatically. The homepage scanner now judges pasted code on its content. It used to label every paste as a demo file, which could lead the AI false-positive filter to dismiss real findings as example code.
  • +Fewer false alarms on static sites and browser games. Namespaced storage keys like `myapp.settings` are no longer reported as secrets. Rate-limit findings need a real server, and N+1 findings need a database call inside the loop. SRI isn't suggested for vendor scripts that update in place, like Stripe.js. The CSP fix is built from your page's own scripts, and the nosniff and clickjacking fixes name the HTTP header. `// VC###-OK` markers now work on the website, as they already did in the CLI.
  • +The VS Code extension and the MCP server now work like the CLI: 30 free rules with no account, all 214 on a paid plan. Generate an API key under Settings → API Keys on an Indie, Pro or Team plan, then run "XploitScan: Enter API Key" in VS Code, or add `XPLOITSCAN_API_KEY` to the MCP server's `env` block. Scans still run locally; your code is never uploaded. This arrives in VS Code extension 1.3.0 and MCP server 1.6.0; earlier versions still run every rule without a key.
1 change

  • +`npx xploitscan cursor install` works again. It writes XploitScan's security rules to `.cursor/rules/xploitscan-security.mdc` and `.cursorrules` so Cursor follows them while it writes code. Earlier versions of the CLI rejected the command. Update to CLI 1.12.2 or later.
5 changes

Safer team invitations and clearer trial reminders

  • +The GitHub Action and GitLab and Bitbucket pipelines now use `XPLOITSCAN_API_KEY` to run your plan's full rule set and add the run to your dashboard, once per CI job. If the key is mistyped or revoked, the log now says so instead of quietly scanning with the free rules. If your plan's scan limit is reached, the build keeps going on the free rules rather than failing.
  • +We updated our Privacy Policy and Terms of Service. They now describe how long we keep your data, what deleting your account removes, and how Free Trust Page data is handled. If you had an account before this update, you'll see a short notice about it in the app for the next 30 days, or until you dismiss it.
  • +Joining a team is now always your choice. When someone invites you, the invitation waits in Settings → Team, with Accept and Decline buttons and a note explaining what the team will be able to see if you accept. Invitations only match email addresses you've verified. Team owners will see invitees as Pending until they accept. If you invited someone before this change, use Resend on their invitation so they get the email with the link to accept.
  • +The trial-ending reminder in the dashboard now counts down in hours when a trial ends within a day and a half, the same way the reminder email does. Before, it rounded up to whole days, so a trial ending tomorrow night said "2 days".
  • +Trial reminders now say exactly what happens when a trial ends: the renewal amount, the date your card will be charged, and how to cancel beforehand if you don't want to continue. The Privacy Policy and Terms now describe data retention as it works today. Scan results, audit logs and checklists are kept while your account is active, and you can delete scans at any time, or delete your account from Settings to remove your data.
1 change

Plan changes and team seats

  • +Switching plans now updates the subscription you already have, wherever you start from — pricing, the scan screen, a feature prompt or settings. Each route ends at the same confirmation, with prorated billing. Team members deactivated when a plan lapsed can be brought back: they show as **Inactive** with a Re-invite button beside them. Removing someone from a team ends their access to shared scans and nothing else — their own scan history stays with their account.
2 changes

Plan status that stays current, and whole-folder uploads

  • +Your plan, trial dates and renewal date are now reconciled against Stripe on a schedule, instead of only when a billing event reaches us or you happen to open the app. A subscription that changed while you were away shows its real state the next time you look. Backing out of Stripe checkout also returns you to the plans now, rather than to the settings page.
  • +The web scanner now takes a whole folder — dragged in, or picked with Browse Folder. It walks subdirectories and skips `node_modules`, build output and `.git`, so a real project uploads in one step instead of a file selection. It also tells you when a drop contained nothing it can scan, rather than looking as though nothing happened.
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.
40 changes

The scanner now checks your code against what you said it would do

  • +Actions that fail now say so. Saving notification preferences, revoking an API key or a session, deleting a saved questionnaire response, renaming a device and creating a checklist share link all report the outcome instead of assuming success, and a failed rename puts the old name back.
  • +Claiming a free Trust Page after signing up completes cleanly. If the page has already been claimed by another account, you are told that directly rather than sent back to your inbox.
  • +Deleting your account now removes everything tied to it, including your Trust Page — which previously stayed reachable by its public link — along with saved questionnaires and their per-prospect responses, custom domain verifications, project descriptions, your AI-analysis preference, dismissed prompts, review reminders and feedback. A connected GitHub App is unlinked rather than deleted, since the App still exists on GitHub.
  • +Saved scans now keep up to 500 findings, most severe first, so the detail you open matches the counts you were shown. Scans saved earlier kept fewer — re-run one to see everything it found.
  • +New: an intent check. Every other thing a scanner tells you is about code; this one is about the gap between your code and your own description of it. If your README says "customers can only see their own orders" and an endpoint returns orders without checking who is asking, you get that as a sentence: what you wrote, where you wrote it, and the endpoint that disagrees. It reads README.md, CLAUDE.md, AGENTS.md, .cursorrules, and a .xploitscan-intent file if you keep one.
  • +Benchmark figures quoted on the comparison and blog pages now match the benchmark page: XploitScan catches all 16 of the held-out third-party set.
13 changes

Findings now tell you the URL they sit behind — CLI 1.5.0

  • +CLI 1.5.0 — machine-readable scan output now names the AI builder that scaffolded the project. The terminal has shown this for a while ("Detected: Lovable project"); JSON, SARIF and the Splunk, Elastic and Datadog formats did not carry it at all, which is exactly where it is most useful — grouping or filtering findings by builder across many repositories in CI. It is context only and never affects a finding's severity or your grade.
  • +SARIF output was reporting the scanner's version as 0.1.0 regardless of which version produced it. If you upload results to GitHub code scanning, runs from different releases were indistinguishable. It now reports the real version.
  • +A finding used to give you a file and a line. It now also tells you the URL that reaches it, where one exists: "reachable at /api/webhooks/clerk". The scanner reads your project's own route table rather than guessing from folder names, so the path it shows is the path your app actually serves. Next.js, TanStack Router, React Router, Express and Flask are supported. It appears in the terminal, in JSON output, and on the finding card in the web report. Route information is shown for context only and does not change any finding's severity or your grade.
  • +Two new rules for account state that lives in the browser. The first flags an entitlement or role — a plan, a tier, an admin flag — read out of localStorage or sessionStorage and then used to decide what the user can do. Anyone can edit those values in their own browser, so the check has to happen on the server. The second is informational and flags per-account lifecycle state, such as whether onboarding is finished, being decided by browser storage alone: it is not a vulnerability, but it is why a signed-in user gets greeted as a first-time visitor on a new device.
  • +That second rule came from our own bug, and it is fixed here too: the "Welcome to XploitScan" prompt no longer appears for people who have already run a scan. Whether you are new is now answered by your scan history rather than by a flag in the browser, so signing in from a different browser or clearing site data no longer makes the product forget you.
  • +A scanner coverage fix worth naming plainly: files inside a folder called "onboarding" were being skipped during scans. The exclusion was meant to ignore our own demo fixtures and was matching far too broadly. If your project keeps real code in an onboarding folder, it was not being scanned, and your next scan may report findings that were always there. We would rather tell you that than let the number quietly change.