ProofmergeA senior engineer reviews what your AI wrote.
Launch Security Check
Security review of AI-built and AI-powered software
Prepared forDemo Client (sample data)
Applicationsample-app
Scan date2026-11-11
Review statusReviewed by Demo reviewer (illustrative decisions on planted sample data), 2026-11-11
Findings70 (15 critical, 42 high)
0of 100
Grade
F
Not ready to launch. Critical issues expose data, credentials or infrastructure.
Reviewed. Every finding below was confirmed by Demo reviewer (illustrative decisions on planted sample data) (2026-11-11). 1 automated finding(s) were dismissed as false positives and are listed in the appendix.
1. Executive summary
We scanned sample-app (19 files, 396 lines) with LaunchCheck built-in checks and Gitleaks. The scan produced 70 findings across 27 distinct issue types: 15 critical, 42 high, 10 medium and 3 low.
Assessment: grade F, score 0/100. Not ready to launch. Critical issues expose data, credentials or infrastructure.
Every finding in this report was reviewed by Demo reviewer (illustrative decisions on planted sample data); 1 automated finding(s) were dismissed as false positives.
Highest risks
Hardcoded API key or provider secret (7 places) - Anyone who can read the code - a contractor, a leaked zip, a public repo, an AI tool with repo access - can use this key.
LLM output passed to a dangerous sink (3 places) - Model output is untrusted text: a prompt-injected document or user can make the model write anything.
Secret exposed to the browser through a public env prefix (2 places) - Variables with these prefixes are copied into the JavaScript that every visitor downloads.
Table created without Row Level Security (2 places) - Supabase exposes every table in the public schema through an auto-generated API.
Private key committed to the repository (1 place) - A private key proves identity.
Recommended order of work
Rotate every exposed credential and remove secrets from the repository. Assume they are already compromised.
Close access-control gaps: database row-level rules and authentication on every API route.
Remove injection paths and stop executing model output; restrict agent tools and MCP servers.
Harden configuration (CORS, debug, rate limits) and lock dependency versions.
2. Severity breakdown
15critical
42high
10medium
3low
By area
LLM and agents20
Secrets16
Access control9
Configuration8
Injection8
Dependencies5
Supabase4
By OWASP category
A01:2025 Broken Access Control
13
A02:2025 Security Misconfiguration
8
A03:2025 Software Supply Chain Failures
5
A04:2025 Cryptographic Failures
1
A05:2025 Injection
11
A06:2025 Insecure Design
3
A07:2025 Authentication Failures
15
LLM01:2025 Prompt Injection
3
LLM02:2025 Sensitive Information Disclosure
5
LLM03:2025 Supply Chain
2
LLM05:2025 Improper Output Handling
3
LLM06:2025 Excessive Agency
9
LLM10:2025 Unbounded Consumption
5
OWASP Top 10:2025 (web) and OWASP Top 10 for LLM Applications 2025.
3. Findings
#
Severity
Finding
Location
Confidence
Source
Status
1
critical
LLM output passed to a dangerous sink
LLM002-0834971b
agent-service/main.py:56
confirmed by reviewer
launchcheck
confirmed
2
critical
LLM output passed to a dangerous sink
LLM002-46fc0b91
agent-service/main.py:68
confirmed by reviewer
launchcheck
confirmed
3
critical
Hardcoded API key or provider secret
SEC001-ed715aa0
.env:4
confirmed by reviewer
gitleaks, launchcheck
confirmed
4
critical
Hardcoded API key or provider secret
SEC001-5dbd24da
.env:5
confirmed by reviewer
launchcheck
confirmed
5
critical
Hardcoded API key or provider secret
SEC001-815d437c
.env:6
confirmed by reviewer
launchcheck
confirmed
6
critical
Hardcoded API key or provider secret
SEC001-44f9a518
.env:7
confirmed by reviewer
launchcheck
confirmed
7
critical
Hardcoded API key or provider secret
SEC001-5b1f5a03
.env:8
confirmed by reviewer
launchcheck
confirmed
8
critical
Hardcoded API key or provider secret
SEC001-926d29a2
agent-service/main.py:11
confirmed by reviewer
launchcheck
confirmed
9
critical
Hardcoded API key or provider secret
SEC001-7e075a0c
lib/stripe.ts:3
confirmed by reviewer
launchcheck
confirmed
10
critical
Private key committed to the repository
SEC002-b32f4c47
agent-service/keys/jwt_signing.pem:1
confirmed by reviewer
gitleaks, launchcheck
confirmed
11
critical
Secret exposed to the browser through a public env prefix
SEC004-db028cea
.env:4
confirmed by reviewer
launchcheck
confirmed
12
critical
Secret exposed to the browser through a public env prefix
SEC004-d4fe1e67
.env:5
confirmed by reviewer
launchcheck
confirmed
13
critical
Table created without Row Level Security
SUPA001-071de26e
supabase/migrations/0001_init.sql:12
confirmed by reviewer
launchcheck
confirmed
14
critical
Table created without Row Level Security
SUPA001-0a48b64a
supabase/migrations/0001_init.sql:19
confirmed by reviewer
launchcheck
confirmed
15
critical
Supabase service-role key used in frontend code
SUPA003-5722a896
lib/supabaseClient.ts:6
confirmed by reviewer
launchcheck
confirmed
16
high
Next.js API route with no authentication check
AUTH001-ec7eccc5
app/api/admin/users/route.ts:6
confirmed by reviewer
launchcheck
confirmed
17
high
Next.js API route with no authentication check
AUTH001-22590ed4
app/api/chat/route.ts:6
confirmed by reviewer
launchcheck
confirmed
18
high
Next.js API route with no authentication check
AUTH001-636574b9
app/api/export/route.ts:4
confirmed by reviewer
launchcheck
confirmed
19
high
Express route with no authentication middleware
AUTH002-2acf1372
services/admin-api/index.js:10
confirmed by reviewer
launchcheck
confirmed
20
high
Express route with no authentication middleware
AUTH002-20f7a06e
services/admin-api/index.js:14
confirmed by reviewer
launchcheck
confirmed
21
high
FastAPI/Flask endpoint with no authentication check
AUTH003-e94c439d
agent-service/main.py:44
confirmed by reviewer
launchcheck
confirmed
22
high
FastAPI/Flask endpoint with no authentication check
AUTH003-10dda696
agent-service/main.py:60
confirmed by reviewer
launchcheck
confirmed
23
high
FastAPI/Flask endpoint with no authentication check
AUTH003-efb41921
agent-service/main.py:72
confirmed by reviewer
launchcheck
confirmed
24
high
FastAPI/Flask endpoint with no authentication check
AUTH003-14cf804a
agent-service/main.py:78
confirmed by reviewer
launchcheck
confirmed
25
high
Permissive CORS configuration
CFG001-e938a299
agent-service/main.py:17
confirmed by reviewer
launchcheck
confirmed
26
high
Permissive CORS configuration
CFG001-8f7c9e91
app/api/admin/users/route.ts:11
confirmed by reviewer
launchcheck
confirmed
27
high
Package name on the known-bad / typosquat sample list
DEP003-bc9c4c1d
agent-service/requirements.txt:5
confirmed by reviewer
launchcheck
confirmed
28
high
Package name on the known-bad / typosquat sample list
DEP003-2d448800
package.json:17
confirmed by reviewer
launchcheck
confirmed
29
high
SQL query built by string concatenation
INJ001-cbde9238
agent-service/main.py:74
confirmed by reviewer
launchcheck
confirmed
30
high
SQL query built by string concatenation
INJ001-6124f1ce
app/api/admin/users/route.ts:8
confirmed by reviewer
launchcheck
confirmed
31
high
SQL query built by string concatenation
INJ001-8f6ecf3e
app/api/admin/users/route.ts:19
confirmed by reviewer
launchcheck
confirmed
32
high
Dynamic code execution (eval / exec)
INJ002-139ae6a1
app/api/export/route.ts:7
confirmed by reviewer
launchcheck
confirmed
33
high
Shell command built from variable input
INJ004-8e5070dd
agent-service/main.py:27
confirmed by reviewer
launchcheck
confirmed
34
high
Shell command built from variable input
INJ004-9baecebe
agent-service/main.py:80
confirmed by reviewer
launchcheck
confirmed
35
high
Shell command built from variable input
INJ004-5e202ed0
app/api/export/route.ts:6
confirmed by reviewer
launchcheck
confirmed
36
high
User input placed directly into the system prompt
LLM001-a488e80b
agent-service/main.py:47
confirmed by reviewer
launchcheck
confirmed
37
high
User input placed directly into the system prompt
LLM001-b5fc5614
app/api/chat/route.ts:9
confirmed by reviewer
launchcheck
confirmed
38
high
User input placed directly into the system prompt
LLM001-1205aa43
app/api/chat/route.ts:10
confirmed by reviewer
launchcheck
confirmed
39
high
LLM output passed to a dangerous sink
LLM002-8815d0b7
components/ChatWindow.tsx:21
confirmed by reviewer
launchcheck
confirmed
40
high
Agent tool with unrestricted shell, file or network access
LLM004-325d8342
agent-service/main.py:25
confirmed by reviewer
launchcheck
confirmed
41
high
Agent tool with unrestricted shell, file or network access
LLM004-b1af7026
agent-service/main.py:30
confirmed by reviewer
launchcheck
confirmed
42
high
Agent tool with unrestricted shell, file or network access
LLM004-a0a556dd
agent-service/main.py:36
confirmed by reviewer
launchcheck
confirmed
43
high
Agent tool with unrestricted shell, file or network access
LLM004-95c80ab1
agent-service/run_agent.sh:3
confirmed by reviewer
launchcheck
confirmed
44
high
Plaintext credential in MCP / agent configuration
MCP001-50ee263a
.mcp.json:18
confirmed by reviewer
launchcheck
confirmed
45
high
Plaintext credential in MCP / agent configuration
MCP001-24016329
.mcp.json:26
confirmed by reviewer
launchcheck
confirmed
46
high
Plaintext credential in MCP / agent configuration
MCP001-273c6cc0
.mcp.json:42
confirmed by reviewer
launchcheck
confirmed
47
high
Over-broad MCP server or agent permission
MCP002-dfe084cf
.mcp.json:3
confirmed by reviewer
launchcheck
confirmed
48
high
Over-broad MCP server or agent permission
MCP002-7a9e2b03
.mcp.json:29
confirmed by reviewer
launchcheck
confirmed
49
high
Over-broad MCP server or agent permission
MCP002-1e115d6c
.mcp.json:35
confirmed by reviewer
launchcheck
confirmed
50
high
Over-broad MCP server or agent permission
MCP002-10d1ff23
.mcp.json:40
confirmed by reviewer
launchcheck
confirmed
51
high
Environment file (.env) is in the repository and not git-ignored
Raw HTML rendering (dangerouslySetInnerHTML / innerHTML)
INJ003-f0cc179f
components/NoteCard.tsx:5
confirmed by reviewer
launchcheck
confirmed
66
medium
LLM call without an output-length or cost limit
LLM003-831a66a1
agent-service/main.py:48
confirmed by reviewer
launchcheck
confirmed
67
medium
LLM call without an output-length or cost limit
LLM003-14f0356a
app/api/chat/route.ts:12
confirmed by reviewer
launchcheck
confirmed
68
low
Unpinned dependency versions
DEP002-78a19d7b
agent-service/requirements.txt:1
confirmed by reviewer
launchcheck
confirmed
69
low
Unpinned dependency versions
DEP002-dcbc8802
package.json:13
confirmed by reviewer
launchcheck
confirmed
70
low
Over-broad MCP server or agent permission
MCP002-a261e9de
.mcp.json:7
confirmed by reviewer
launchcheck
confirmed
Confidence:confirmed-by-pattern - the matched text is itself the issue (for example a key in a file). needs-human-verification - the pattern indicates a likely issue whose impact depends on context a person must check.
4. Finding details
critical
Hardcoded API key or provider secret
SEC001 · 7 instances
A07:2025 Authentication Failures
Why it matters
Anyone who can read the code - a contractor, a leaked zip, a public repo, an AI tool with repo access - can use this key. For LLM and payment providers that means running up your bill or moving money; for cloud keys it can mean full account takeover.
How to fix
Revoke and rotate the key at the provider now (assume it is compromised). Load it from a server-side environment variable or a secret manager, and remove it from git history (git filter-repo) if the repository was ever shared.
Severity basis: A string matching a provider key format (or a decoded Supabase service-role JWT) is stored in a repository file.
criticalconfirmed by reviewersource: gitleaks, launchcheck
Severity basis: A string matching a provider key format (or a decoded Supabase service-role JWT) is stored in a repository file. Corroborated by 2 independent sources (gitleaks, launchcheck).
.env:5 · SEC001-5dbd24da
NEXT_PUBLIC_OPENAI_API_KEY=sk-p****[48 chars]
OpenAI API key (sk-p****[48 chars])
criticalconfirmed by reviewersource: launchcheck
.env:6 · SEC001-815d437c
OPENAI_API_KEY=sk-p****[48 chars]
OpenAI API key (sk-p****[48 chars])
criticalconfirmed by reviewersource: launchcheck
.env:7 · SEC001-44f9a518
STRIPE_SECRET_KEY=sk_l****[41 chars]
Stripe live secret key (sk_l****[41 chars])
criticalconfirmed by reviewersource: launchcheck
.env:8 · SEC001-5b1f5a03
AWS_ACCESS_KEY_ID=AKIA****[20 chars]
AWS access key ID (AKIA****[20 chars])
criticalconfirmed by reviewersource: launchcheck
agent-service/main.py:11 · SEC001-926d29a2
ANTHROPIC_API_KEY = "sk-a****[39 chars]"
Anthropic API key (sk-a****[39 chars])
criticalconfirmed by reviewersource: launchcheck
lib/stripe.ts:3 · SEC001-7e075a0c
export const stripe = new Stripe("sk_l****[41 chars]");
Model output is untrusted text: a prompt-injected document or user can make the model write anything. Running that text as code, SQL, a shell command or HTML hands the attacker your server, database or users' browsers.
How to fix
Never execute model output directly. Validate it against a strict schema, run generated SQL read-only with a limited role, run code only in an isolated sandbox, and render text as text.
Severity basis: A variable holding model output flows into eval/exec, a shell command, a raw SQL call or raw HTML. Rated high for HTML sinks.
agent-service/main.py:56 · LLM002-0834971b
exec(generated_code)
model output `generated_code` reaches code execution
criticalconfirmed by reviewersource: launchcheck
agent-service/main.py:68 · LLM002-46fc0b91
rows = db.execute(generated_sql).fetchall()
model output `generated_sql` reaches a raw SQL call
Secret exposed to the browser through a public env prefix
SEC004 · 2 instances
A02:2025 Security MisconfigurationLLM02:2025 Sensitive Information Disclosure
Why it matters
Variables with these prefixes are copied into the JavaScript that every visitor downloads. Naming a secret this way publishes it.
How to fix
Rename the variable without the public prefix, use it only in server code (API routes, server actions), rotate the secret, and have the browser call your own endpoint instead of the provider directly.
Severity basis: A variable whose name marks it as secret uses a prefix (NEXT_PUBLIC_, VITE_, ...) that the build tool inlines into client JavaScript.
NEXT_PUBLIC_SUPABASE_SERVICE_ROLE_KEY (also referenced in lib/supabaseClient.ts)
criticalconfirmed by reviewersource: launchcheck
.env:5 · SEC004-d4fe1e67
NEXT_PUBLIC_OPENAI_API_KEY=sk-p****[48 chars]
NEXT_PUBLIC_OPENAI_API_KEY
criticalconfirmed by reviewersource: launchcheck
critical
Table created without Row Level Security
SUPA001 · 2 instances
A01:2025 Broken Access Control
Why it matters
Supabase exposes every table in the public schema through an auto-generated API. Without Row Level Security, anyone holding the public anon key (it ships in your frontend) can read and change every row of this table.
How to fix
Run `ALTER TABLE <table> ENABLE ROW LEVEL SECURITY;` and add policies that tie rows to `auth.uid()`. Test with the anon key that other users' rows are not returned.
Severity basis: A CREATE TABLE in the public schema has no matching ENABLE ROW LEVEL SECURITY in any scanned migration.
A private key proves identity. With it an attacker can sign tokens your app trusts, decrypt data, or log in to servers.
How to fix
Generate a new key pair, replace the old public key everywhere, and keep the private key outside the repository (secret manager or deployment-platform secret).
Severity basis: A PEM private-key header is present in a repository file. Corroborated by 2 independent sources (gitleaks, launchcheck).
MCP servers act with your developer's or your server's privileges. A filesystem server on `/` or a shell server lets any prompt injection reach everything on the machine.
How to fix
Limit filesystem servers to the project folder, remove shell servers or wrap them in an allowlist, pin server package versions, and keep approval prompts on.
Severity basis: An MCP server is configured with whole-disk access, command execution, auto-approval, an unpinned package or an unencrypted remote URL. Rated medium for unpinned packages.
.mcp.json:3 · MCP002-dfe084cf
"filesystem": {
server `filesystem`: filesystem access rooted at `/`
highconfirmed by reviewersource: launchcheck
.mcp.json:29 · MCP002-7a9e2b03
"shell": {
server `shell`: gives the model command execution on this machine
highconfirmed by reviewersource: launchcheck
.mcp.json:35 · MCP002-1e115d6c
"autoApprove": [
server `shell`: tools auto-approved without a prompt (autoApprove)
server `analytics`: remote server over unencrypted http
highconfirmed by reviewersource: launchcheck
.mcp.json:7 · MCP002-a261e9de
"@modelcontextprotocol/server-filesystem",
unpinned server packages run at their latest version on every start: filesystem (@modelcontextprotocol/server-filesystem), github (@modelcontextprotocol/server-github), shell (mcp-shell-server)
lowconfirmed by reviewersource: launchcheck
Severity basis: An MCP server is configured with whole-disk access, command execution, auto-approval, an unpinned package or an unencrypted remote URL. Rated medium for unpinned packages. Reviewer adjusted severity from medium to low.
Reviewer note: Developer-machine configuration only; pin versions when convenient.
high
Hardcoded password, token or signing secret
SEC005 · 5 instances
A07:2025 Authentication Failures
Why it matters
A signing secret or password in source code is known to everyone with code access and usually never rotated. A leaked JWT secret lets an attacker mint a valid login for any user.
How to fix
Move the value to a server-side environment variable or secret manager, rotate it, and use a long random value.
Severity basis: A literal value is assigned to a name that indicates a credential (secret, password, token, api key).
connection string with an embedded password (FAKE****[21 chars])
highconfirmed by reviewersource: launchcheck
agent-service/main.py:12 · SEC005-315b9ae7
ADMIN_PASSWORD = "FAKE****[24 chars]"
ADMIN_PASSWORD = FAKE****[24 chars]
highconfirmed by reviewersource: launchcheck
lib/stripe.ts:4 · SEC005-483dc713
export const jwtSecret = "FAKE****[36 chars]";
jwtSecret = FAKE****[36 chars]
highconfirmed by reviewersource: launchcheck
high
FastAPI/Flask endpoint with no authentication check
AUTH003 · 4 instances
A01:2025 Broken Access Control
Why it matters
This endpoint answers anyone on the internet who finds its URL - no login needed. AI coding tools often generate the happy path and leave the access check out.
How to fix
FastAPI: add `Depends(get_current_user)` to the route or router. Flask: add `@login_required` or verify the token in a `before_request` hook.
Severity basis: A route handler was found with no session, token or API-key check in the handler or in shared middleware.
agent-service/main.py:44 · AUTH003-e94c439d
@app.post("/agent/run")
POST /agent/run -> agent_run()
highconfirmed by reviewersource: launchcheck
agent-service/main.py:60 · AUTH003-10dda696
@app.post("/agent/report")
POST /agent/report -> agent_report()
highconfirmed by reviewersource: launchcheck
agent-service/main.py:72 · AUTH003-efb41921
@app.get("/notes/search")
GET /notes/search -> search_notes()
highconfirmed by reviewersource: launchcheck
agent-service/main.py:78 · AUTH003-14cf804a
@app.post("/admin/backup")
POST /admin/backup -> backup()
highconfirmed by reviewersource: launchcheck
high
Agent tool with unrestricted shell, file or network access
LLM004 · 4 instances
LLM06:2025 Excessive Agency
Why it matters
Whatever the tool can do, a prompt-injected model can be talked into doing: reading secrets from disk, running commands, calling internal services.
How to fix
Give each tool the smallest capability that works: fixed commands, one working directory, an allowlist of hosts, and human approval for destructive actions.
Severity basis: A function exposed to the model as a tool runs commands, touches files or fetches URLs with no allowlist or path restriction, or an agent is started with its permission prompts disabled.
agent-service/main.py:25 · LLM004-325d8342
def run_shell(command: str) -> str:
tool `run_shell` runs shell commands with no allowlist
highconfirmed by reviewersource: launchcheck
agent-service/main.py:30 · LLM004-b1af7026
def read_file(path: str) -> str:
tool `read_file` reads or writes arbitrary files with no allowlist
highconfirmed by reviewersource: launchcheck
agent-service/main.py:36 · LLM004-a0a556dd
def fetch_url(url: str) -> str:
tool `fetch_url` fetches arbitrary URLs with no allowlist
highconfirmed by reviewersource: launchcheck
agent-service/run_agent.sh:3 · LLM004-95c80ab1
claude -p "fix the failing tests and push" --dangerously-skip-permissions
`--dangerously-skip-permissions` removes the safety checks around agent actions
highconfirmed by reviewersource: launchcheck
high
Next.js API route with no authentication check
AUTH001 · 3 instances
A01:2025 Broken Access Control
Why it matters
This endpoint answers anyone on the internet who finds its URL - no login needed. AI coding tools often generate the happy path and leave the access check out.
How to fix
Check the session at the top of every handler (e.g. `const { data: { user } } = await supabase.auth.getUser()`; return 401 when missing) or protect the path in `middleware.ts`. Then check the user is allowed to touch the specific record.
Severity basis: A route handler was found with no session, token or API-key check in the handler or in shared middleware.
app/api/admin/users/route.ts:6 · AUTH001-ec7eccc5
export async function GET(req: Request) {
handlers: DELETE, GET
highconfirmed by reviewersource: launchcheck
app/api/chat/route.ts:6 · AUTH001-22590ed4
export async function POST(req: Request) {
handlers: POST
highconfirmed by reviewersource: launchcheck
app/api/export/route.ts:4 · AUTH001-636574b9
export async function POST(req: Request) {
handlers: POST
highconfirmed by reviewersource: launchcheck
high
Permissive CORS configuration
CFG001 · 3 instances
A02:2025 Security Misconfiguration
Why it matters
CORS decides which websites may call your API from a visitor's browser. `*` means every website. Combined with credentials, some frameworks echo the caller's origin, so a malicious page can act with a logged-in user's session.
How to fix
List the exact origins you serve (your production and preview domains). Never combine a wildcard origin with credentials.
Severity basis: CORS allows any origin (`*`). Rated high when credentials are also allowed in the same configuration.
agent-service/main.py:17 · CFG001-e938a299
allow_origins=["*"],
wildcard origin together with credentials
highconfirmed by reviewersource: launchcheck
app/api/admin/users/route.ts:11 · CFG001-8f7c9e91
"Access-Control-Allow-Origin": "*",
wildcard origin together with credentials
highconfirmed by reviewersource: launchcheck
services/admin-api/index.js:5 · CFG001-2a6c3142
app.use(cors());
wildcard origin (no credentials seen nearby)
mediumconfirmed by reviewersource: launchcheck
high
SQL query built by string concatenation
INJ001 · 3 instances
A05:2025 Injection
Why it matters
If any part of that string comes from a user, they can rewrite the query: read other customers' data, change it, or delete tables.
How to fix
Use parameterised queries (`$1` / `%s` placeholders with a separate values array) or the query builder of your ORM. Never paste values into SQL text.
Severity basis: A SQL statement is assembled with string interpolation or concatenation instead of bound parameters.
agent-service/main.py:74 · INJ001-cbde9238
cur = db.execute(f"SELECT id, title FROM notes WHERE owner = '{owner}' AND title LIKE '%{q}%'")
highconfirmed by reviewersource: launchcheck
app/api/admin/users/route.ts:8 · INJ001-6124f1ce
const result = await pool.query(`SELECT id, email, plan FROM users WHERE email = '${email}'`);
highconfirmed by reviewersource: launchcheck
app/api/admin/users/route.ts:19 · INJ001-8f6ecf3e
await pool.query("DELETE FROM users WHERE id = " + id);
highconfirmed by reviewersource: launchcheck
high
Shell command built from variable input
INJ004 · 3 instances
A05:2025 Injection
Why it matters
If a user controls any part of the command, adding `; rm -rf /` or `| curl attacker` runs their command on your server.
How to fix
Call the program with an argument list and no shell (`subprocess.run([...])`, `execFile`), and validate the input against an allowlist.
Severity basis: A shell command string is built from a variable and run through a shell.
The system prompt is the model's rulebook. Text a user types into it is read as rules, so a user can tell the model to ignore your instructions, reveal the prompt, or misuse its tools (prompt injection).
How to fix
Keep the system prompt constant. Pass user text only as a separate `user` message, treat it as untrusted data, and enforce permissions in code, not in the prompt.
Severity basis: A value that looks user-controlled is interpolated into the system prompt or instructions string.
agent-service/main.py:47 · LLM001-a488e80b
system_prompt = f"You are the NoteGenie agent. The user's instructions are: {user_message}"
interpolates `user_message`
highconfirmed by reviewersource: launchcheck
app/api/chat/route.ts:9 · LLM001-b5fc5614
const systemPrompt = `You are NoteGenie, a helpful assistant for ${userName}.
interpolates `userName`
highconfirmed by reviewersource: launchcheck
app/api/chat/route.ts:10 · LLM001-1205aa43
Follow the user's preferences: ${question}`;
interpolates `question`
highconfirmed by reviewersource: launchcheck
high
Plaintext credential in MCP / agent configuration
MCP001 · 3 instances
A07:2025 Authentication FailuresLLM02:2025 Sensitive Information Disclosure
Why it matters
MCP config files are often committed and are read by every AI tool that opens the project. A token here is shared with all of them.
How to fix
Reference an environment variable (`${GITHUB_TOKEN}`) instead of the value, rotate the exposed credential, and scope the new one to the minimum.
Severity basis: An MCP or agent configuration file contains a literal token, password or connection string instead of an environment reference.
server `postgres`: argument holds a literal credential
highconfirmed by reviewersource: launchcheck
.mcp.json:42 · MCP001-273c6cc0
"Authorization": "Bearer FAKE****[32 chars]"
server `analytics`: Authorization holds a literal credential
highconfirmed by reviewersource: launchcheck
high
Express route with no authentication middleware
AUTH002 · 2 instances
A01:2025 Broken Access Control
Why it matters
This endpoint answers anyone on the internet who finds its URL - no login needed. AI coding tools often generate the happy path and leave the access check out.
How to fix
Add an authentication middleware (`app.use(requireAuth)` or per route) that verifies the session or token before the handler runs.
Severity basis: A route handler was found with no session, token or API-key check in the handler or in shared middleware.
AI assistants sometimes invent or misspell package names; attackers register those names with malware inside. Installing one runs their code on your machine and in your build.
How to fix
Remove the package, install the intended one, and check machines and CI that installed it. Verify against a current advisory database (OSV, GitHub Advisories).
Severity basis: A declared dependency name matches the bundled SAMPLE list of publicly reported malicious or typosquatted package names.
A policy whose condition is simply `true` switches Row Level Security back off for that operation: every visitor passes the check.
How to fix
Replace `true` with a real ownership condition, e.g. `USING (auth.uid() = user_id)`. Keep `true` only for data that is intentionally public and read-only.
Severity basis: A CREATE POLICY statement uses USING (true) or WITH CHECK (true) and is not limited to the service role.
This document starts as the output of an automated first pass. In a paid engagement a senior engineer then works through it and the codebase. That review adds what tooling cannot:
Confirms what is exploitable. Each automated finding is checked in context. False positives are removed, and real issues are ranked by what an attacker could do with them, not by pattern match.
Tests authorisation logic. Whether user A can read user B's records, whether tenants are isolated and whether admin functions are reachable are logic questions a pattern scanner cannot answer.
Reads the database rules against the data model. Row Level Security policies are reviewed table by table for what each role can select, insert, update and delete.
Looks at how the app is deployed. With access you grant: environment configuration, exposed endpoints, storage buckets, security headers and what the production build ships to the browser.
Exercises the LLM features. Prompt injection, data leakage through the model, and what the agent's tools and MCP servers allow when the model is manipulated.
Checks git history and third-party access. Secrets that were committed and later deleted are still in history; tokens are checked for scope and rotation.
Delivers a fix plan. A prioritised list your developer or AI assistant can act on, a walkthrough call, and a re-check after fixes.
6. Scope and limitations
In scope: a static review of the source tree sample-app as provided on 2026-11-11: 19 text files, 396 lines. Dependency folders, build output, lockfile contents, test fixtures and git-ignored .env files were skipped.
could not download rules 'p/default' from the Semgrep registry (network blocked or offline); use --semgrep-config <local rules path> to run offline
Trivy (fs)
known dependency vulnerabilities, secrets, misconfiguration
skipped
-
binary not found on PATH or in product/.tools/bin; adapter skipped
Findings from all scanners are normalised into one schema and de-duplicated (same rule class, file and line range); the Source column lists every scanner that reported a finding. A scanner shown as skipped or failed contributed nothing to this report.
Not covered
The running application, its hosting, cloud accounts, DNS and network were not tested. This is not a penetration test.
Git history was not examined by the built-in checks; a secret that was committed and later removed will not appear.
Authorisation logic (who may access which record), business logic and payment flows are not assessed by pattern matching.
The built-in checks are heuristics over source text. They do not follow data across files, so they produce both false positives and missed issues.
Languages and frameworks outside JavaScript/TypeScript (Next.js, Express), Python (FastAPI, Flask), SQL migrations and MCP configuration receive secret scanning only.
The known-bad package list is a small bundled sample, not a vulnerability database.
A clean result means none of these checks matched. It is not a statement that the application is secure.
7. Method and scoring
Score. Start at 100. Each issue type with open findings costs its severity weight per instance, capped at two instances: critical 15, high 8, medium 3, low 1. Findings dismissed in review cost nothing. Grade: A 90+, B 80+, C 65+, D 50+, F below 50; an open critical finding caps the grade at D and an open high finding at B.
Severity is the default for the issue type, adjusted by the evidence found (stated under each finding) and by the reviewer. Secret values are masked everywhere in this report; only the first four characters are shown.
Checks run
ID
Check
Area
Result
SEC001
Hardcoded API key or provider secret
Secrets
7 findings
SEC002
Private key committed to the repository
Secrets
1 finding
SEC003
Environment file (.env) is in the repository and not git-ignored
Secrets
1 finding
SEC004
Secret exposed to the browser through a public env prefix