CSP-1AI-first application security

Your code has vulnerabilities AI can exploit today.

You don't know where they are.
CodeSecPilot finds them.

Private preview · the illustrative workflow below shows how CodeSecPilot is designed to explain exploitable vulnerabilities, the path to your data and the business impact, with practical guidance for the responsible developer. Sign-in and GitHub repository selection are available; hosted assessments are under verification.

Key specificationsCSP-1
Input
GitHub connection · GitLab planned
Code executed
Never
Planned output
Findings with exploit paths, business impact and remediation guidance
Team delivery
Planned · by ownership and authorization
Fix verification
Planned · at the new commit
CSP-1 · Fig. 1Find → re-assess → patchIllustrative product preview · fictional repositories and findingsReady
MCMaya Chen
Source
github.com/northstarread-only
Repositories3
  • northstar/billing-apiPython · FastAPImain @ 8f3c2a1pinned
  • northstar/auth-serviceTypeScript · Nodemain @ 5d0e9b4
  • northstar/payments-gatewayGomain @ e19a7c3
Pinned at 8f3c2a1

Read-only access. The repository is read at a pinned commit and never executed.

Assessment 1 · Findnorthstar/billing-apimain @ 8f3c2a1 · pinned
Files indexed1,284
Executed0
Candidates38
Assessment 2 · Re-assess for real exploitation
Re-assessed38 / 38
Rejected35
Exploitable3
  • SQL injection in report sortsort value checked against a fixed listrejected
  • Weak hashing in cache moduleno secret involvedrejected
  • Open redirect after sign-inonly fixed relative paths allowedrejected
  • + 32 more rejected
38 candidates → 35 rejected → 3 exploitable
HighCSP-142Any signed-in customer can open another company's invoicesOpen
HighCSP-142billing-apiExploitableOwner · Maya Chen (you)
Any signed-in customer can open another company's invoices
The problem

Changing the invoice number in the address returns that invoice, even when it belongs to another company. The lookup checks that someone is signed in, but not which company they belong to.

Business impact

Customer names, amounts and bank details are visible to other customers. This is likely a notifiable personal-data breach.

How hard to exploit

Easy. Needs only an ordinary customer account. Invoice numbers are sequential.

Exploit pathPatch +4 −1
  1. 1Way inGET /invoices/{invoice_id}Takes any invoice number from the addressapi/routes/invoices.py:41
  2. 2Check that failsDepends(current_user)Signs in, but never checks the company:42
  3. 3Datadb.invoices.get(id=invoice_id)Returns another company's invoice:43
--- a/api/routes/invoices.py
+++ b/api/routes/invoices.py
@@ -41,6 +41,9 @@
4141 @router.get("/invoices/{invoice_id}")
4242 def get_invoice(invoice_id: int, user: User = Depends(current_user)):
43- invoice = db.invoices.get(id=invoice_id)
43+ invoice = db.invoices.get(
44+ id=invoice_id,
45+ tenant_id=user.tenant_id,
46+ )
4447 if invoice is None:
4548 raise HTTPException(status_code=404)
4649 return invoice
Traced from source at main @ 8f3c2a1 · no exploit was run$ git apply csp-142.patchfrom the repository root
§1Why nowSources 1–2

AI moved the cost of attack to near zero.

Finding and exploiting a vulnerability used to take a skilled attacker days. AI agents now do it for under $10 an exploit, and they never stop looking. If a vulnerability in your code can be exploited, assume someone will try.

87%
of a test set of known vulnerabilities exploited by a GPT-4 agent from their public descriptions[1]
$8.80
average cost per exploit in the same study, 2.8× cheaper than a human expert[1]
31%
of breaches now start with an exploited vulnerability, the most common way in[2]
§2Exploitable onlyValues from Fig. 1

CodeSecPilot doesn't just find vulnerabilities. It finds the exploitable ones.

Your codebase has thousands of potential vulnerabilities. Chasing all of them would keep your business in patch-fixing mode forever.

The hard reality: not every vulnerability is worth patching. That's why businesses sideline security. They want to move forward and focus on growth.

But sidelining a critical vulnerability that is exploitable can end your business.

That's why CodeSecPilot runs two completely separate assessments:

  1. Assessment 1

    Find

    A model reads your code at a pinned commit and proposes every candidate vulnerability, each tied to the exact lines it cites.

  2. Assessment 2

    Re-assess for real exploitation

    Separate models re-assess every candidate the way an attacker would: can the way in be reached, does a check stop it, what does the attacker get, and how hard is it. Candidates that don't hold up are rejected.

38 candidates35 rejected3 exploitableIllustrative run

You stop spending time on low-probability security alerts. Developer time goes to the burning-hot, critical attacks that need to be stopped today. You focus on growth, and your app keeps the security level your customers expect.

Every finding is traced from your source at a pinned commit. We never run exploits against your systems.

§3Need-to-knowPlanned team controls · Fig. 2

None of your developers should see the entire vulnerability list.

The most likely attacker may already be inside: someone on your own staff, frustrated with how things work. Let the full vulnerability list flow to every developer and each of them holds a map of how to break in.

A proper, secure segmentationFig. 2
Admins
See the full list of vulnerabilities, without the exploitation details.
Admins
Assign vulnerabilities to developers and set priorities.
Developers
See the exploitation details of the one vulnerability they're working on. When its patch is verified, the next one opens.

Secure compartmentalization on a need-to-know basis is a core feature of CodeSecPilot. It is enforced on our servers, not hidden in the browser.

CSP-1 · Fig. 2Need-to-knowIllustrative product preview · fictional repositories and findingsReady
Demo seatTomAdminMayaDeveloperSamDeveloper
MCMaya Chen

Pick a demo seat to see the workspace as that person.

Vulnerabilities
3 exploitableadmin view
Exploitation details are not delivered to admins
ProblemBusiness impactDifficultyPriorityAssignee
CSP-142Customers can open other companies' invoicesCustomer billing data exposed; likely notifiable breachEasyFix nowMaya Chen
CSP-143Used password reset links still workAccount takeover from old reset emailsModerateFix nowSam Okafor
CSP-147Forged payment notifications could be acceptedUnpaid orders marked as paidHardThis sprintLéa Martin
audit CSP-147 assignee → léa.martin · CSP-143 priority → fix now
To fix
1 active · the next opens when this patch is verified
HighCSP-142billing-apiEasy to exploit
Any signed-in customer can open another company's invoices
  1. 1Way inGET /invoices/{invoice_id}Takes any invoice number from the addressapi/routes/invoices.py:41
  2. 2Check that failsDepends(current_user)Signs in, but never checks the company:42
  3. 3Datadb.invoices.get(id=invoice_id)Returns another company's invoice:43
api/routes/invoices.pypatch +4 −1
@@ -41,6 +41,9 @@
def get_invoice(invoice_id: int, user: User = Depends(current_user)):
- invoice = db.invoices.get(id=invoice_id)
+ invoice = db.invoices.get(
+ id=invoice_id,
+ tenant_id=user.tenant_id,
+ )
if invoice is None:
To fix
1 active · the next opens when this patch is verified
HighCSP-143auth-serviceModerate to exploit
A password reset link keeps working after it has been used
  1. 1Way inresetPassword(token, …)src/auth/reset.ts:18
  2. 2Check that failsrecord.expiresAt < new Date():20
  3. 3Accountusers.setPassword(record.userId, …):21
src/auth/reset.tspatch +6 −2
@@ -18,5 +18,9 @@
export async function resetPassword(token: string, newPassword: string) {
- const record = await db.resetTokens.findOne({ token });
- if (!record || record.expiresAt < new Date()) throw new InvalidToken();
+ const record = await db.resetTokens.findOneAndUpdate(
+ { token, usedAt: null, expiresAt: { $gt: new Date() } },
+ { $set: { usedAt: new Date() } },
+ );
+ if (!record) throw new InvalidToken();
await users.setPassword(record.userId, newPassword);
+ await sessions.revokeAll(record.userId);
}
404
Not found

Maya opens a link to Sam's vulnerability. The server answers exactly as it does for one that does not exist: no title, no severity, no count.

Sam's vulnerability
GET /v1/findings/CSP-143
→ 404 not_found
A vulnerability that does not exist
GET /v1/findings/CSP-999
→ 404 not_found

Filtered on the server before search, sort and count.

Network
§4Patch verificationPlanned fix verification · Fig. 3

We verify that a vulnerability is really patched.

When a developer pushes a patch, CodeSecPilot re-checks the original exploit path at the new commit. The vulnerability closes only when the path is gone. If it just stops showing up in a scan, it stays open. Then the developer's next vulnerability opens.

Fig. 3 results
FindingCommitChecksResult
CSP-142b71e09d3 of 3Verified fixed
CSP-143c42d9e01 of 2Still open, reopened to Sam
From the app
Verify fix
From the CLI
codesecpilot verify CSP-142 --ref b71e09d
From an agent
verify_finding
CSP-1 · Fig. 3Verify the patchIllustrative product preview · fictional repositories and findingsReady
SOSam Okafor
HighCSP-142billing-apiVerified fixed
Any signed-in customer can open another company's invoices
Commitb71e09dScope invoice lookup to tenant+4−1maya.chen
Verified
CLIcodesecpilot verify CSP-142 --ref b71e09d
MCPverify_finding { "finding": "CSP-142", "ref": "b71e09d" }
Exploit path re-checked at b71e09doriginal exploit path
Invoice lookup now requires the signed-in companyapi/routes/invoices.py:43–46
Every other path to db.invoices.get checked: 2 found, both scopedapi/routes/exports.py:88 · api/jobs/reminders.py:31
Independent second model agrees
Verified fixed at b71e09d3/3 checks passed · the exploit path is gone
Before8f3c2a1 · L43
43 invoice = db.invoices.get(id=invoice_id)
Afterb71e09d · L43–46
43 invoice = db.invoices.get(
44 id=invoice_id,
45 tenant_id=user.tenant_id,
46 )
HighCSP-143auth-serviceReopened
A password reset link keeps working after it has been used
Commitc42d9e0Mark reset token as used+2−1sam.okafor
Checked
CLIcodesecpilot verify CSP-143 --ref c42d9e0
MCPverify_finding { "finding": "CSP-143", "ref": "c42d9e0" }
Exploit path re-checked at c42d9e0original exploit path
Token is now marked as usedsrc/auth/reset.ts:21
The check and the update are two separate steps: two requests sent at the same moment can both succeedsrc/auth/reset.ts:19–21
Still openReopened to Sam Okafor with the new evidence and the complete patch
src/auth/reset.tsc42d9e0 · L19–22
19 const record = await db.resetTokens.findOne({ token });
20 if (!record || record.usedAt || record.expiresAt < new Date()) throw new InvalidToken();
21 await db.resetTokens.update({ token }, { usedAt: new Date() });
22 await users.setPassword(record.userId, newPassword);

Two requests that both read line 19 before either reaches line 21 both pass line 20. The complete patch claims the token in one atomic findOneAndUpdate, then revokes every session.

RuleCloses only when the exploit path is gone. A scan that stops reporting it does not close it.
§5Agents · MCP serverPlanned integration · illustrative listings

Your coding agent writes the patch. CodeSecPilot verifies it.

Claude Code, Cursor or any MCP client can pull the vulnerability assigned to its developer, read the exploit path, apply the patch and ask for verification. The agent gets exactly what its developer gets: same need-to-know, same repositories, nothing more.

Planned endpoint
POST https://api.codesecpilot.com/mcp
Protocol
MCP 2025-11-25, Streamable HTTP
Token issued by
A person signed in with MFA
Token bound to
Selected repositories
Scopes
read, optional scan
Lifetime
Expires, revocable, checked on every call
Tenant argument
None
Visibility
The token holder's need-to-know window
Exports
HTML, JSON, SARIF
MCP tools7
  • 1list_repositories
  • 2list_assessments
  • 3get_assessment
  • 4list_findings
  • 5get_report
  • 6start_assessment
  • 7verify_finding
Listing 1 · Claude Code sessionIllustrative
> patch the vulnerability assigned to me
● codesecpilot · list_findings { "view": "to_fix" }
1 vulnerability assigned to you · CSP-142 High · billing-api
● codesecpilot · get_report { "finding": "CSP-142" }
● Edit api/routes/invoices.py (+4 −1)
● Bash git commit -m "Scope invoice lookup to tenant" → b71e09d
● codesecpilot · verify_finding { "finding": "CSP-142", "ref": "b71e09d" }
✓ Verified fixed at b71e09d · 3/3 checks passed
Listing 2 · .mcp.json · Claude CodeIllustrative configuration
{
"mcpServers": {
"codesecpilot": {
"type": "http",
"url": "https://api.codesecpilot.com/mcp",
"headers": { "Authorization": "Bearer ${CODESECPILOT_TOKEN}" }
}
}
}
Listing 3 · CI gateIllustrative CI workflow
codesecpilot scan --repository billing-api --budget 30 --ref "$GITHUB_SHA"
codesecpilot status --wait --fail-on high
§6Security design6.1 – 6.5

Built for teams who don't trust anyone with their code. Including us.

A service that holds your exploit paths is a target. We designed CodeSecPilot as if we were the ones being attacked.

S.01
Release
Private preview
S.02
Hosted assessments
Under verification
S.03
GitHub connection
Repository metadata
S.04
Code executed
Never
S.05
Scan isolation
Design under qualification
S.06
MFA
Required for product sign-in
S.07
Password minimum
20 characters, 4 classes
S.08
Initial home
eu-west-1
S.09
Customer-key sealing
Planned · unavailable
S.10
Team controls
Planned
6.1

Separate authority. Isolated assessments.

Fig. 4 · S.01–S.03

The reviewed design separates the application from the broker that checks identity and authorizes data operations. Human sign-in uses authenticator MFA; hosted machine access is planned.

Each scan attempt is designed to use a fresh isolated task. Separately authorized regional gateways acquire source and call models, keeping provider credentials outside the source-processing task.

Public website delivery is separate from private assessment data. The scan runtime and its network restrictions must pass qualification before hosted assessments are enabled.

Planned assessment architectureIllustrative reviewed design: an application API with independent data authority, an isolated scan task and regional acquisition and inference gateways. Public static website delivery is separate from assessment data.INTERNETpeople, CI, agentsCDNstatic files onlyREVIEWED REGIONAL DESIGNHTTPS · MFA or scoped tokenAPI + BROKERindependent authorityfor private dataDATA STORESauthorized accessDatabaseObject storageKeysINBOUND · NONESCANNER TASKone per assessmentdisposable storageDESIGN BOUNDARIESno code executionno provider keysin scan tasksbounded source accessPRIVATE PREVIEW:IRELAND FIRSTOUTBOUNDONLYSOURCE GATEWAYpinned revisionINFERENCE GATEWAYregional model calls
Fig. 4 · Planned network pathsIllustrative
Authority
Independent broker
Scan runtime
Under qualification
Scanner inbound
None
Planned scanner outbound
Regional source and inference gateways
Data stores
Managed AWS, scoped access
CDN
Static files, no customer data
Provider credentials
Outside source-processing tasks
Release scope
Private Ireland preview
6.2

Tenant separation, across several boundaries.

Fig. 5 · S.05
Exploded view of the planned tenant-separation controlsSeven stacked plates, from identity at the top to region at the bottom, pierced by one request axis. Each plate is numbered and described in the list beside the drawing.REQUESTTENANT DATAPLANNED ACCESS CONTROLSeu-west-1Ireland first07 · ONE REGION7tokenbilling-api06 · TOKEN SCOPE605 · ONE TASK5aad: tenant purpose04 · ENCRYPTION4iam t_8c1f… onlyother tenant03 · AWS POLICY3TENANT#t_8c1f…tenants/t_8c1f…/02 · KEY PREFIX2tenant ←identity01 · IDENTITY1
Fig. 5 · Planned tenant separationIllustrative

The reviewed design combines these controls. Independent application and AWS authorization are required; naming prefixes and regional placement alone do not grant or deny access.

  1. 1
    Identity decides the tenant.

    Tenant comes from your authenticated identity and live membership, never from a client-supplied ID. Guessed IDs return 404.

  2. 2
    Every key starts with the tenant.

    Database partitions and object paths are tenant-prefixed: TENANT#t_8c1f…, tenants/t_8c1f…/…

  3. 3
    AWS enforces it too.

    The broker uses operation-specific tenant authority. Extending and qualifying this boundary for scans and findings is part of the hosted release work.

  4. 4
    Encryption is bound to the tenant.

    The findings design binds each encrypted section to its tenant, purpose and version. Protected publication and reading are under qualification.

  5. 5
    One task, one assessment.

    The scan design uses a fresh task and task-local source for each attempt. Runtime isolation remains under qualification.

  6. 6
    Machine tokens are repository-bound.

    Planned CI and MCP tokens are restricted to selected repositories and current principal permissions.

  7. 7
    One region.

    Ireland eu-west-1 is the initial home. Source, findings and inference must follow the qualified regional path; additional regions are planned.

6.3

Your code is data, never executed.

S.04

The assessment design treats code as text: no execution, dependency installation or git hooks. Source acquisition is bounded, models receive no credentials, and task-local copies must be removed after every attempt. Hosted cleanup is under qualification.

Code executed
Never
Dependency install
None
Build
None
Git hooks
Not run
Symlinks
Rejected
Planned integrity checks
Pinned objects and bounded source
Size limits
Strict
Credentials given to models
None
Planned source lifetime
Task-local, removed after each attempt
Cleanup evidence
Operational status and receipt
6.4

Your key. Your findings.

Customer-key sealing · planned, unavailable

Optional customer-key sealing is planned and is not available in the private preview. Its goal is to leave completed findings readable only with customer-held keys.

This requires a separately qualified key, recovery and cleanup workflow. Ordinary server-managed encryption does not make findings unreadable to the service.

  1. Step 1 · Your browserProposed: customer devices generate and retain private decryption keys.
  2. Step 2 · Assessment completesProposed: separate encrypted sections and recipient-specific access protect technical and executive detail.
  3. Step 3 · SealedProposed: sealing completes only after vendor-recoverable copies and key wraps are accounted for.
Section protection
Separate keys · planned
Recipient access
Customer-authorized · planned
Service recovery
Must be excluded before sealing
Private keys
Customer-held · planned
Sealed state
Unavailable in this preview
Viewer
Browser decryption · under qualification
Boundaries for the planned sealed mode
  • We process your code in plaintext during the scan.
  • Routing metadata (IDs, status, timestamps) stays readable to us so work can be dispatched.
  • Customer-only keys require customer-managed recovery; the recovery workflow is not yet available.
  • The viewer code we serve is part of the trust boundary.
6.5

Identity.

S.06–S.07

Authenticator MFA is required for product sign-in, with complex passwords of at least 20 characters. Hosted machine access is not yet available; its planned credentials are separate from human sessions.

MFA
Required for product sign-in
Password minimum
20 characters with upper, lower, number and symbol
Sessions
MFA-bound sign-in and refresh
Credentials
Human and machine kept separate
Machine tokens
Planned · scoped and repository-bound
Authority
Recomputed on every request
§7 · Start

The vulnerability is already there. Find it before someone else does.

Connect a repository. Get the vulnerabilities an attacker could exploit today, each with its exploit path and patch, delivered only to the developer who owns the code.

Read-only accessYour code is never executedStays in your region