SlopGradeby Maxor Global LLC
Sign inStart the free 14-day trial
Access-control gate · CWE-639 / BOLAFor teams shipping AI-written code to multi-tenant SaaS

Block cross-tenant data leaks
before they reach main.

An org-scoped query with no org filter is broken object-level authorization — #1 on the OWASP API Top 10 — and AI writes it constantly, because the happy-path test still passes. SlopGrade catches the missing .eq(org_id) in CI, on every pull request, before the merge — deterministic, and on a private repo by default only a {file · line · kind} fingerprint leaves your runner.

#1
OWASP API risk (BOLA)
0
lines of source stored
0
model calls · deterministic
3
classes block a paid repo today
Trust, proven — not promised
Open-source clientMIT · audit every line before you pin it
Audit the fingerprint--print-payload prints the exact bytes sent
Pin the SHAfreeze the exact code; a tag can be re-pointed
File content stayson a private repo, by default only the structural fingerprint is posted
Fail-openan outage never breaks your build
The bug

One missing filter, and tenant A reads tenant B's data.

The query returns rows scoped by id but never by org_id. Every test passes — the seed data has one org. In production, any authenticated user can read any tenant's invoices by changing an id. AI writes this constantly; a human reviewer skims past it. The gate doesn't.

What the AI shipped

api/invoices.ts:44 — leaks across tenants
// no org filter — returns ANY tenant's rows const { data } = await db .from("invoices") .select("*") .eq("id", req.params.id) // ✗ missing .eq("org_id", ctx.orgId)

What leaves your runner

the structural fingerprint — not the code
{ "file": "api/invoices.ts", "line": 44, "kind": "cross-tenant-leak" }

Path, line, class. By default the content of a private file stays on the runner. Audit it with --print-payload.

How the gate catches it

Detect → adapt → verify. On a private repo, nothing else leaves by default.

01 · DETECT

In your runner, on the diff

The open-source client walks the pull request, resolves each org-scoped table access, and flags any query that reads by id without an org predicate — intra-function dataflow. By default, no private code leaves the machine.

→
02 · ADAPT

Server verdict + gate

The fingerprint is classified server-side. A hard leak blocks the check on a paid private repo; public repos are gated free. The paywall fails open — never a build broken by mistake.

→
03 · VERIFY

Fix computed in the runner

The finding is posted inline on line 44. You add the org filter; the next push re-runs the gate and the check turns green.

→
vs a generic SAST

Most scanners ingest your private code. By default, this one does not.

Generic SAST
SlopGrade
Your private code
often analyzed in the vendor's cloud
stays in your runner by default
Cross-tenant leak detection
rarely — generic taint rules
a dedicated gate class
Verdict
a score + a triage queue
deterministic pass / block
False positives
tuned per team
tenancy-aware: detects row, RLS or schema-per-tenant first
Pricing

Block cross-tenant leaks on private repos. Solo for one person, Team for a team.

Advisory is free everywhere. Blocking is free on every public repo and one private repo. Solo covers 10 private repos for one person; Team covers 50, unlimited users. 14 days free, no card.

Free
$0
Cross-tenant leaks and PHP echo/print XSS block on every public repo and 1 private repo.
Solo
$49 / month
One person: blocks cross-tenant leaks + 2 more classes on 10 private repos (up to 50).
Start Solo — 14 days, no card
Team
$299 / month
A team: the same 3 classes on 50 private repos, unlimited users, Deep Scan on every PR.
Start Team — 14 days, no card

Ready to block the next tenant-isolation leak before merge?

Add it to one workflow file. The first AI pull request you scan will tell you what it was about to let through.

2-minute install · no card · the client is open source (MIT) · fail-open
FAQ

Cross-tenant leaks — the questions a security team asks.

What is a cross-tenant data leak?

In a multi-tenant SaaS, every row belongs to an organization. A cross-tenant leak is a query that filters by a record id but not by the caller's org — so an authenticated user of tenant A can read tenant B's data by changing an id. It's also called BOLA / IDOR (CWE-639) and it is #1 on the OWASP API Security Top 10.

Why do tests miss it?

Because the happy-path test seeds a single org, so the missing org filter still returns the "right" row. The bug only appears with real multi-tenant data in production. A deterministic CI gate that reads the query shape catches it before it ever ships.

Does my source code leave the runner?

Not by default. The client reads files locally and posts only a structural fingerprint — file paths, {file, line, kind} and the table and column names the cross-tenant check needs. Run --print-payload to audit the exact bytes sent. The exceptions are the deep scan (heisen-slop) on a public repo, on by default, and the opt-in deep scan on a paid private repo: at most 80 sink files, analysed in memory and dropped. A free private repo never sends source.

Will it break my build with false positives?

Start in advisory mode — see every finding, block nothing — then switch to gate when you trust it. The gate first detects your tenancy pattern (row filter, RLS or schema per tenant) before it judges a query, and it fails open by default: an outage never breaks a build.

Which languages and frameworks?

JavaScript/TypeScript and Python today (Go and .NET cover the core subset), across common query builders and ORMs. The cross-tenant gate is in the free open-source client.

Add it to a workflow file. Catch the leak before merge.

# .github/workflows/slop-gate.yml name: slop-gate on: { pull_request: {} } jobs: slop: # keep the job name: it is the check you require runs-on: ubuntu-latest permissions: contents: read id-token: write # required — OIDC proves the repo, no secret pull-requests: write # optional — judges the PR on its own changes + inline findings security-events: write # optional — Security tab (Code Scanning) steps: - uses: actions/checkout@v7 with: { fetch-depth: 0 } - uses: maxor-tech/slopgrade-firewall@f18a953e15e84ff0f9e457da4a056ddea3548d46 # v0.13.6