Lattice

Lattice scans the whole repository in the background and reads each pull request against that context. It traces candidate vulnerabilities through the codebase and recommends fixes that follow nearby patterns.

Validated vulnerabilities in MLflow, AutoGPT, authentik, and more.

PR #1842 · tenant file downloads

apps/api/src/FileController.ts

High
33
class FileController {
34
// Download endpoint used by every tenant
35
async downloadFile(req: Request, res: Response) {
36
const { tenantId, fileId } = req.query;
37
38
const file = await storage.getById(fileId);
39
if (!file) {
40
return res.status(404).send('Not found');
41
}
42
43
return res.download(file.path);
44
}
45
}

Missing tenant isolation

Broken access control · IDOR

downloadFile resolves fileId from the query string and returns the file without checking ownership. Any authenticated user can request another tenant's file by guessing its id.

Suggested fix

Verify file.tenantId === tenantId before returning the path.

Scrutinizes every assumption

Comments, names, and labels tell you what code is supposed to do. Lattice checks what it actually does, tracing each path to see whether the assumption holds. Where reality and the label disagree is where the vulnerabilities live.

Request middleware

app/middleware.py

Critical
1
class DebugAuth:
2
# Test-only: lets fixtures act as any user.
3
# Not mounted in production.
4
def resolve_user(self, req):
5
uid = req.headers.get("X-Debug-User")
6
if uid:
7
return load_user(uid) # trust header, skip login
8
return session_user(req)
9
10
MIDDLEWARE = [DebugAuth(), RateLimit()] # applied to every request

Debug auth mounted in production

Broken access control

The comment says DebugAuth is test-only and never mounted in production. It sits in the MIDDLEWARE list applied to every request, so anyone who sends X-Debug-User is authenticated as that user.

Suggested fix

Mount DebugAuth only behind a local/CI environment guard.

192 bugs, 1 confirmed RCE

Most of what a scan turns up is individually harmless — a loose unzip here, a trusting template loader there. Lattice chains them, runs the chain in a sandbox, and reports the one that actually detonates. What reaches your queue is a proven exploit, not four rules that matched near each other.

1
api/imports.py:extract_bundlealone: Medium
2
api/imports.py:validate_manifestalone: innocuous
+ 2 more

Confirmed · RCE on api-worker

Exploit reproduced end-to-end in a sandbox

The findings that actually matter

Every codebase has bugs — that's reality, and most scanners bury you in hundreds of them until it's all noise. Lattice ranks each one by what it can actually reach and wreck in your system, so the same sink can be a P0 in one file and a P3 in another. Only the findings that can take the account rise to the top.

Signup avatar import

api/signup.py

Critical
12
@app.post("/signup/avatar")
13
def import_avatar(url: str): # attacker-controlled, pre-auth
14
data = fetch_url(url) # runs in api pod, IAM role attached
15
return store_avatar(data)
P0 · Critical
Reachability
pre-auth via /signup/avatar
Exposure
public internet
Auth
none
Blast radius
api pod holds s3:GetObject and sts:AssumeRole; a redirect to IMDS lifts cloud credentials

Link-preview worker

worker/link_preview.py

8
def render_preview(doc_url: str): # from an admin-curated allowlist
9
data = fetch_url(doc_url) # worker pod, no IAM role
10
return thumbnail(data) # egress denies 169.254/16 + RFC-1918
11
P3 · de-escalated
Reachability
admin-curated allowlist, not attacker-controlled
Exposure
internal only
Auth
internal service
Blast radius
no instance role; egress firewall blocks the metadata range regardless
Same rule. Different blast radius.

One branch from failing closed

Beyond bugs, Lattice flags cheap hardening. This rate limiter returns true when Redis is unreachable, so throttling silently stops on login and password reset. Nothing is broken today, so it is informational. But a single branch keeps it failing closed, and an outage no longer opens the door to credential stuffing.

Gateway rate limiter

gateway/ratelimit.py

42
def allow_request(key: str, limit: int) -> bool:
43
try:
44
count = redis.incr(key)
45
if count == 1:
46
redis.expire(key, WINDOW)
47
return count <= limit
48
except RedisError:
49
return True # fails open when Redis is unreachable
Recommended, not blocking

Rate limiter fails open

Defense in depth

Informational
On a Redis error, allow_request returns true, so throttling drops on /login and /password-reset.

Recommendation

Fail closed on auth-sensitive routes.

Cheaper the more it knows

The first scan maps your whole repository — data flows, auth model, trust boundaries. That one is expensive. Every scan after reuses the map and pays only for the diff, so routine reviews cost a fraction of the first.

The first scan reads your whole repository. Every one after pays only for the diff.

Other scannersLatticeScans over timeCost per scan

An AppSec review on every pull request

Lattice reads each change against a standing map of the repository, validates what it finds, and ranks it by the blast radius it would carry in your deployment.