Every push read.
Every pull request judged.
The hard part is no longer writing the code. It's reviewing it. Connect the GitHub App and AppScan reads every change: what it introduced against what the base branch already had, which of your own invariants it broke, and which files no rule can read - those go to a model. Then it writes the fix as a draft pull request.
Before a rule runs, the scan works out what your app is built from
52 read your source, 38 your deploy files, 24 are read by a model.
Deterministic and versioned. Every finding prints the id of the rule that raised it.
Derived from your own code, persisted per site, and re-checked on every push and every pull request.
Python, Go, Java, Ruby, PHP and Rust among them - the files no deterministic rule here can open.
Stack, routes, guards, tenancy, data and rate limits, each with a confidence and a provenance.
From a commit to a fix, without guessing in between.
Four steps, each one producing evidence the next can use. Scroll, or pick a step.
- CriticalAdd bulk refund endpoint14 commits · 32 files
- LowBump next to 15.5.71 commit · 2 files
- HighMove uploads to S36 commits · 11 files
- LowCopy changes on pricing page2 commits · 3 files
- 01Every push
Forty commits are still one change.
Install the GitHub App on the repositories you choose. Pushes to the same branch are coalesced into one change set, classified by what they actually touched, and scored - so a merge storm does not become forty scans and a dependency bump is not read like a rewritten auth middleware.
- Coalesced
A, then B, then C, then D become one change from A to D. The analysis runs once, on what actually changed.
- Classified
Every change set ends as CLEAN, MONITORED, REVIEW, ACTION_REQUIRED - and formatting-only pushes are recognised as MINIMAL, because the symbols are fingerprinted rather than the bytes.
- Read once
A file that did not change is not analyzed again. The cache is per blob, so a rebase or a force-push reuses the tree it already read.
- Secrets, in the diff and behind it
A credential in the change, in the commit message, or still sitting in bounded git history - masked before it is stored, and never auto-resolved just because the line was deleted.
- 02Every pull request
Did this change make it worse?
A check run on every pull request, marked against the base branch: what this change would introduce, what it inherited, and what it fixes. You are never asked to fix main to merge a branch.
- NEW or UNCHANGED
The verdict separates what the branch introduced from the backlog it walked into, with the resolved count in its favour.
- Protections that disappear
A guard removed, a tenant scope dropped, a signature check deleted - a protection that vanishes in a diff is a finding of its own.
- 13 invariants, re-checked
The truths your code established - tenant-scoped reads, guarded mutations, verified webhooks, server-side prices - are checked again before the merge, and a broken one fails the check.
- Advisories that chase you
Exact versions come from your lockfiles. When a new advisory lands, the affected repositories are re-evaluated the same day, without touching GitHub.
- 03Correlate
One problem is one finding.
Most tools hand you the same bug twice: once from the scanner that saw it live, once from the scanner that read the code. AppScan joins them - the code finding is canonical, because that is what you change, and the live observation rides along as proof that it is real in production.
- Fingerprints, not line numbers
A finding is identified by what it is, so it survives a refactor and resolves when the problem is actually gone.
- Proof you can check
Every finding carries the rule id, the file or URL it came from, and masked evidence.
- Five questions, always the same five
What is wrong, why it matters, how it would be abused, how to fix it, how the fix is verified.
- Dismissed stays dismissed
Accepted risk and false positive are first-class states with an audit trail, and never spend AI again.
- 04The deployed app
Code review does not see production.
The repository says what should happen; the deployed app says what does. A real browser walks your routes on a schedule and after any risky push, and what it sees is what proves - or disproves - a finding the source analysis raised.
- 25 stages, not one prompt
Detection is split into deterministic steps, each producing structured evidence. The same input always produces the same finding.
- Free and unlimited on a paid plan
Scanning your own live site costs no credits. The queue, a five-minute cooldown and the concurrency cap are the only brake.
- After a risky push
A change that touches authentication, authorization, tenancy, the API contract, a webhook or a security control triggers one bounded runtime re-check.
- Read-only, always
Nothing is written and nobody is logged in. The access-control probe replays a request your own page already made, and only on a domain you verified.
Can a model find what a rule cannot?
Only if it is held to the same standard. A model reads your repository file by file, proposes leads, and a second, better model is asked whether each one is real - with the whole file in front of it. A lead that cannot name a category from a closed list, and a symbol that provably exists in that file, is dropped rather than dressed up as a finding.
- Scout, confirm, escalate
The cheap model reads batches and usually says nothing. Anything it raises is re-read by a better one, and anything critical by a better one again.
- A closed list of categories
24 rule ids, published on the coverage page like every other rule. A model cannot invent a new kind of finding.
- The symbol has to exist
A lead names a file and a function. If the function is not in the file, the lead never becomes a finding - which is the whole of what makes a model’s output checkable.
- Bought as a pass, not a meter
The pass is reserved and charged once, up front. A talkative model costs us, not you, which is why keeping it quiet is our problem before it is your policy.
- scoutcheap tiernothing raised41 files read in this batch, asked about DATA_ISOLATION and EXPOSURE.
- lead—leadexportAll in src/routes/export.ts returns rows the caller does not own.
- confirmdefault tieradmittedWhole file read. The symbol exists, the category is EXPOSURE, the path is reachable.
- confirmdefault tierdroppedSecond lead named a function this file does not declare.
One finding from 161 batches. The rest of the pass said nothing, which is what a quiet scout is paid to do.
Three defects a pattern cannot describe.
The eight security categories a model may claim are ones an analyzer can at least attempt. These three are the reason a reading is worth paying for.
A refund issued twice, an order paid after it shipped, a race with money on it. There is no pattern to grep for; the defect is in the design.
An export, an import, a search or a preview that quietly returns rows above the caller’s level. Every line of it looks legitimate, because every line of it is.
An error that distinguishes “does not exist” from “no access”, a timing difference, an id that counts. Existence learned from a difference nobody meant to publish.
Deterministic analysis is TypeScript and JavaScript. A model reads 37 file types, which is the only reader a Python, Go, Java, Ruby, PHP or Rust repository has here - and we would rather say so than imply a rule exists for it.
A prompt that asks for everything gets an essay. Each batch of files is asked about the two domains its own contents suggest, with the questions that domain is made of.
- DATA_ISOLATIONmulti-tenant data access
- WEB_AUTHrequest handling and identity
- AVAILABILITYwork a caller can make expensive
- CLIENT_SIDEcode that runs in the browser
- SUPPLY_CHAINbuild, release and dependency resolution
- AI_DELEGATIONa model in a trust-sensitive decision
From a finding to a draft pull request.
Detection is deterministic; remediation is where a model earns its cost. Ask, and the change is written against your file and opened as a draft for you to read, run and merge. Every task has a fixed price in credits before it runs, and nothing runs unless somebody asks.
- Nothing is generated until you ask for it.
- Each task is estimated and reserved before it runs, and refunded if it fails.
- A ceiling per site and per organization stops any runaway, and a reserve is held back so a critical finding can always be escalated.
- Findings you dismissed never spend a credit again.
export async function GET(req) {
Found in source, proved in production. Nothing has been generated yet, and nothing has been charged.
Step 1 of 4: The finding
- Explain a finding8
- Fix with AI16
- Fix as a draft pull request58
- Verify a change22
Scanning the live site is free and unlimited on every paid plan. These are the tasks that spend credits, and each is charged once.
It remembers your app between scans.
Each scan writes facts, not just findings: what the app is built from, which routes exist, who is allowed to call them, where personal data lives. Facts carry a confidence and a provenance, they are re-verified as the code changes, and they are what makes the next scan cheaper and sharper than the last.
- Confidence, not guesses
Every fact is confirmed, likely, verifying, unknown or invalidated - and says which scan established it.
- Invariants derived from you
The rules your code already follows become invariants, re-checked on every push.
- Baselines per route
Load, DOM-ready and time-to-first-byte are remembered so a regression is measurable.
- Inventory that stays current
Packages from lockfiles, direct and transitive, re-evaluated when advisories land.
- TECH_STACKNext.js 15 on Vercel, Prisma against Postgres, Stripe for payments.
- ROUTES38 endpoints from source, 12 of them mutating, 4 seen at runtime only.
- AUTHENTICATIONSession cookies issued by the app; no third-party identity provider.
- AUTHORIZATIONrequireRole guards 9 of 12 mutating routes.
- TENANCYRows are scoped by organizationId; two lookups are not.
- DATA_MODELOrders, customers and refunds hold personal data.
- EXTERNAL_SERVICESStripe, Resend, Supabase storage, Sentry.
- SECURITY_CONTROLSCSP present, HSTS present, webhook signatures verified.
- RATE_LIMITSNo rate limit observed on the public search route.
- INFRASTRUCTUREDockerfile runs as root; database port published in Compose.
No repository yet? Start with a URL.
110 of the 249 rules need nothing but the address of your live app. A real browser loads one page, the DNS and mail records are read, and the report arrives by email - then you decide whether to connect the repository.
- Security
- Domain & DNS
- SEO & indexing
- AI discoverability
- App health
- Accessibility
- Privacy
- Performance
- Cost & waste
- Technology
- Criticalsource.secrets.credential-committedA Stripe secret key is committed to the repository
- Criticalsource.injection.sql-built-from-inputSQL is built from request input in findOrders
- Highbrowser.network.data-readable-unauthenticatedOrders API answers without a session
- Mediumruntime.headers.csp-missing-or-unsafeContent-Security-Policy allows inline scripts
- ✓Reaching the site
- ✓Checking HTTPS
- ✓Detecting the stack
- ✓Inspecting security headers
- ✓Checking cookies
- ✓Reading DNS and mail records
- ✓Reading the page head and structure
- ✓Reading robots.txt, sitemaps and security.txt
9 unchanged findings inherited from main, not raised again.
One broke in this change: tenant scope removed from a lookup.
Every finding, answered the same way
Written deterministically by the rule, before any model is asked anything. Five examples; pick one.
The file src/lib/stripe.ts contains a Stripe secret key. Anyone with repository access, and every clone or fork, now has it.
Whoever holds the key can charge cards, issue refunds and read your customer list. Git history keeps it even after the line is deleted.
Read the value from the repository or its history and call the Stripe API as you.
Rotate the key in the Stripe dashboard first, then load it from an environment variable on the server. Purging history alone does not help.
The next commit that touches this file is re-scanned and the finding resolves when the literal is gone. Rotation stays yours.
Every finding names the rule that raised it.
A sample of the 249. Each id is printed on the finding it raises, so a claim on this page can be checked against a report. Nothing in the catalogue needs a model to run.
- Live site62
- Real browser52
- Source code52
- Infrastructure38
- Code improve21
- Read by a model24
What changes when it is on.
No customer logos here yet, so here is the next most useful thing: the four decisions you actually feel, and the mechanism behind each one.
The code finding is canonical; the live observation is attached as proof.
A runtime observation and the line of code behind it share a fingerprint, so they arrive as one issue with two proofs instead of two issues nobody can tell apart.
NEW, UNCHANGED and resolved, every time.
The backlog on the base branch is listed once and never raised again on a branch that did not cause it. Nobody is asked to fix main to merge a feature.
A draft pull request costs 58 credits, decided before the first token.
The estimate is reserved, the tier is chosen by the task rather than by you, the call settles at what it really cost, and a failure is refunded in full.
Accepted risk and false positive are states, not deletions.
Each carries a reason and an audit entry, survives the next scan, and never spends a credit again - which is what stops a security tool from becoming a thing people mute.
Fits where you already work.
A push arrives, and what AppScan makes of it goes back to the places your team already looks - starting with the pull request it came from.
- A push or a pull request arrives from GitHub.
- AppScan reads the change, correlates it with the live app, and scores it.
- A check on the pull request: NEW against UNCHANGED.
- A draft pull request: when you ask for the fix.
- Slack: grouped, one per site.
- Email: instant, daily or weekly.
- The API and exports: JSON, CSV, Markdown, PDF.
Install once, connect repositories to a site. Pushes are coalesced into change sets, pull requests get a check, and Fix with AI opens a draft branch.
A webhook per organization. Instant alerts are grouped and cooled down so one bad deploy does not become forty messages.
Instant for what cannot wait, a digest for the rest, and per-user preferences on top of the organization setting.
Lockfile versions are matched against public advisories, and affected apps are targeted for re-evaluation daily.
Any report or issue list as CSV, JSON or a PDF you can hand to a client without editing it first.
Everything the app does is available over the API, with the same permissions and the same tenancy rules.
Plans, top-ups, refunds and disputes behind signed idempotent webhooks and a normalized subscription state. Paddle sells as merchant of record, on our own checkout page.
API and worker both expose scrape endpoints: HTTP, jobs, queues, GitHub, AI spend and scan outcomes.
A security product has to go first.
These are the rules the product is built under, not aspirations for a later release.
Every probe is a read an anonymous visitor could perform. Nothing is modified, nothing is submitted, nobody is logged in.
A credential is identified and masked before it is stored. The full value never reaches our database and never reaches a model.
TOTP with recovery codes, enforced at the login challenge, for every account that turns it on.
Owner, admin, member and viewer, with invitations, email verification and per-organization isolation on every query.
Every sensitive action - invites, role changes, dismissals, billing, exports - is written down and readable by owners and admins.
The App reads the repositories you connect. Source is analyzed and discarded; what we keep is findings, facts and file paths.
Nothing you connect is used to train a model. AI runs on the task in front of it and nothing is retained for anyone else.
Coverage is recorded per scan. A scan that could not finish says so rather than reading as a clean bill of health.
One repository, or ten of them.
The product is the same either way. What changes is how many applications it watches and how many people answer for them.
Free finds out. Pro keeps watching.
The free plan is a real scan of a real site, not a demo. A paid plan adds the thing the product is for: the repository, on every push.
| What you get | Free$0 forever | Pro$29 / month |
|---|---|---|
| Monthly | $0 | $29 |
| Sites | 1 | 1 |
| Repositories per site | 1 | |
| Browser crawl (pages per scan) | 1 + the 404 page | 20 |
| Source rules (52) | ||
| GitHub App | ||
| Included credits per usage window | 1,000 | |
| Manual full scan | 5 / month, 1 credit each | Free, unlimited |
| Fix with AI | 16 credits |
No card for the trial, once per organization. Studio $49 · Agency $99 · Team by arrangement.
Straight answers
Do you need access to my code to be useful?
No. The free scan reads only what an anonymous visitor can reach: TLS, headers, cookies, cross-origin rules, public JavaScript, markup, exposed paths, the DNS and mail records of the domain, robots.txt and sitemaps, how the site answers a page that does not exist, and everything a real browser sees on your page - the requests it makes, what leaves for third parties, alt text and labels, and how fast it actually loads. Connecting GitHub adds the source rules, dependency advisories and infrastructure checks, but the runtime half works on a URL alone.
What happens to a secret you find?
It is masked before it is stored. Evidence keeps enough to identify which key it is and where it lives; the value itself is never written to our database, never sent to a model, and never shown back in full.
Is AI deciding what is a vulnerability?
No. Detection is deterministic and repeatable - the same input produces the same finding, with the rule id printed on it. AI is used after that, and only when you ask: to explain a finding in your application terms, to judge authorization, and to write a fix. Every AI task is budgeted before it runs.
What does a pull request check actually say?
Each finding on the pull request is marked NEW or UNCHANGED against the base branch, so a review is about what this change introduced rather than about the backlog it inherited. A protection removed in the diff is raised as a security regression.
What is a credit?
The unit AI work is priced in. A plan includes credits per usage window and each AI task has a fixed credit cost. Scanning your live site is free and unlimited on paid plans; the Free plan gets 5 a month at 1 credit each. Top-ups are available and nothing spends a credit without you starting it.
Can I cancel?
Yes, from the billing screen, and the plan stays active until the end of the period you paid for. After that the organization drops to Free, which does not expire: nothing is deleted and the runtime half of the product keeps working.
You already shipped it.
Find out what the next push does.
Connect one repository and the next pull request gets a verdict, the invariants your code establishes get re-checked, and the first fix arrives as a draft. Or scan the live app first - that costs nothing.