checkmyvibe 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +247 -44
- package/SKILL.md +405 -396
- package/adapters/AGENTS-SNIPPET.md +32 -0
- package/adapters/checkmyvibe.mdc +18 -0
- package/adapters/opencode-checkmyvibe.md +19 -0
- package/commands/checkmyvibe-auth.md +15 -9
- package/commands/checkmyvibe-backend.md +24 -14
- package/commands/checkmyvibe-db.md +32 -14
- package/commands/checkmyvibe-frontend.md +23 -9
- package/commands/checkmyvibe-payment.md +53 -14
- package/commands/checkmyvibe-secrets.md +22 -13
- package/commands/checkmyvibe.md +12 -11
- package/install.js +58 -0
- package/package.json +2 -1
- package/references/vibe_risk_patterns.md +65 -21
- package/scripts/check_auth_patterns.py +27 -2
- package/scripts/check_db_config.py +72 -23
- package/scripts/check_gitignore.py +92 -14
- package/scripts/check_payment_config.py +146 -0
- package/scripts/scan_secrets.py +43 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# checkmyvibe — AGENTS.md snippet
|
|
2
|
+
|
|
3
|
+
Paste the section below into your project's `AGENTS.md` (or the global one, e.g.
|
|
4
|
+
`~/.codex/AGENTS.md`, `~/.gemini/GEMINI.md`). This makes any agent that reads
|
|
5
|
+
AGENTS.md — Codex CLI, Gemini CLI, Cursor, opencode, Antigravity, and others —
|
|
6
|
+
able to discover and run checkmyvibe.
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## checkmyvibe (production readiness & code quality audit)
|
|
11
|
+
|
|
12
|
+
When the user asks to "check my vibe", run a production readiness check, review
|
|
13
|
+
code quality, do a pre-ship sanity check, check for exposed environment variables,
|
|
14
|
+
check launch readiness, or asks for a scoped check (`secrets`, `auth`, `db`,
|
|
15
|
+
`backend`, `frontend`, `payment`) — use the checkmyvibe skill:
|
|
16
|
+
|
|
17
|
+
1. Locate its instructions file `SKILL.md` by checking, in order:
|
|
18
|
+
- `.claude/skills/checkmyvibe/SKILL.md`
|
|
19
|
+
- `~/.claude/skills/checkmyvibe/SKILL.md`
|
|
20
|
+
- Search the repo for a `SKILL.md` whose frontmatter contains `name: checkmyvibe`
|
|
21
|
+
2. Read it fully and follow every instruction: scope selection, all applicable
|
|
22
|
+
checks, evidence/confidence rules, severity rubric, report format, and final summary.
|
|
23
|
+
3. Run helper scripts from the `scripts/` folder next to SKILL.md where the skill
|
|
24
|
+
directs you to (Checks 1–4 and Check 7). They are Python 3: try `python <script> <target>`,
|
|
25
|
+
and if not found retry with `python3`.
|
|
26
|
+
4. Save the full detailed audit report to `checkmyvibe-report.md` in the target directory,
|
|
27
|
+
and output the summary and verdict in the conversation response.
|
|
28
|
+
5. If no scope is specified, run the full audit (all checks).
|
|
29
|
+
|
|
30
|
+
Scopes map to checks exactly as defined in SKILL.md's "Scope selection" table:
|
|
31
|
+
`secrets` = 1a+1b+2 · `auth` = 3 · `db` = 4 · `backend` = 1a+3+4+5+6(server)+7(server)
|
|
32
|
+
· `frontend` = 1b+3(client)+7(client) · `payment` = 7 · full = everything.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: checkmyvibe production readiness audit trigger and entry point
|
|
3
|
+
globs:
|
|
4
|
+
alwaysApply: true
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# checkmyvibe (production readiness & code quality audit)
|
|
8
|
+
|
|
9
|
+
When the user asks to "check my vibe", run a production readiness check, review code quality, do a pre-ship sanity check, check for exposed environment variables, check launch readiness, or asks for a scoped check (`secrets`, `auth`, `db`, `backend`, `frontend`, `payment`) — use the checkmyvibe skill.
|
|
10
|
+
|
|
11
|
+
Locate its instructions file `SKILL.md` by checking, in order:
|
|
12
|
+
1. `.claude/skills/checkmyvibe/SKILL.md`
|
|
13
|
+
2. `~/.claude/skills/checkmyvibe/SKILL.md`
|
|
14
|
+
3. Search the repo for a `SKILL.md` whose frontmatter contains `name: checkmyvibe`
|
|
15
|
+
|
|
16
|
+
Read it fully and follow every instruction: scope selection, all applicable checks, evidence/confidence rules, severity rubric, report format, and final summary. If no scope is specified, run the full audit (all checks). Scopes map to checks exactly as defined in SKILL.md's "Scope selection" table.
|
|
17
|
+
|
|
18
|
+
Run helper scripts from the `scripts/` folder next to SKILL.md where the skill directs (Checks 1–4 and Check 7). They are Python 3: try `python <script> <target>` first; if not found, retry with `python3`. Always save the complete, detailed audit report to `checkmyvibe-report.md` in the target directory, and provide the summary and verdict in your response.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Run a checkmyvibe production readiness audit. Optional scope argument: secrets | auth | db | backend | frontend | payment (empty = full audit).
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
$ARGUMENTS
|
|
6
|
+
|
|
7
|
+
Run the checkmyvibe production readiness and code quality audit.
|
|
8
|
+
|
|
9
|
+
First, locate the checkmyvibe skill file `SKILL.md`. Check these paths in order:
|
|
10
|
+
|
|
11
|
+
1. `.claude/skills/checkmyvibe/SKILL.md` (project-level install)
|
|
12
|
+
2. `~/.claude/skills/checkmyvibe/SKILL.md` (global install)
|
|
13
|
+
3. If neither exists, search the working directory for a file named `SKILL.md` whose frontmatter contains `name: checkmyvibe`
|
|
14
|
+
|
|
15
|
+
Read it in full and follow it completely: scope selection, checks, scripts, evidence/confidence rules, severity rubric, report format, post-fix verification, and final summary structure. Always save the complete, detailed audit report to `checkmyvibe-report.md` in the target directory and display the summary and verdict in your response.
|
|
16
|
+
|
|
17
|
+
**Scope handling:** interpret `$ARGUMENTS` above as the scope keyword plus an optional target directory (e.g. `secrets src/`). Valid scopes: `secrets`, `auth`, `db`, `backend`, `frontend`, `payment`. No arguments means a full audit across all checks (1a, 1b, 2, 3, 4, 5, 6, 7). Run only the checks mapped to the chosen scope in SKILL.md's scope table and list skipped checks in the final summary.
|
|
18
|
+
|
|
19
|
+
Helper scripts live in the `scripts/` folder next to SKILL.md. They are Python 3: try `python <script> <target>` first; if `python` is not found, retry with `python3`.
|
|
@@ -20,27 +20,33 @@ This is an **authentication-only check** (Check 3). Checks 1a/1b, 2, 4, 5, 6, an
|
|
|
20
20
|
python <skill_dir>/scripts/check_auth_patterns.py <target>
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
It flags stub names (`mockAuth`, `fakeLogin`, `tempAuth`, `bypassAuth
|
|
23
|
+
It flags stub names (`mockAuth`, `fakeLogin`, `tempAuth`, `bypassAuth`), functions returning `true` unconditionally, mock user dictionary/object returns (`req.user = {...}`, `return { id: ... }`), middleware unconditionally calling `next()`, and insecure Supabase `getSession()` usage on server routes. The script skips test directories and documentation files.
|
|
24
24
|
|
|
25
25
|
## Step 2 — Manual reasoning pass (this is where the real findings are)
|
|
26
26
|
|
|
27
|
-
The script is a first pass only. Read the actual auth code
|
|
27
|
+
The script is a first pass only. Read the actual auth code across login handlers, middleware, route guards, session checks, and every route that returns or modifies user-specific data.
|
|
28
28
|
|
|
29
29
|
Findings to hunt for:
|
|
30
30
|
|
|
31
|
-
- **Always-true stubs:** `function isAuthenticated() { return true; }`, `
|
|
32
|
-
- **Stub-named helpers still wired in:** `mockAuth`, `devAuth`, `bypassAuth` reachable in production paths — Critical
|
|
33
|
-
- **
|
|
34
|
-
- **
|
|
35
|
-
- **
|
|
36
|
-
- **
|
|
31
|
+
- **Always-true stubs & mock user objects:** `function isAuthenticated() { return true; }`, `req.user = { id: "demo", role: "admin" }`, middleware calling `next()` unconditionally with a TODO comment — **Critical**.
|
|
32
|
+
- **Stub-named helpers still wired in:** `mockAuth`, `devAuth`, `bypassAuth` reachable in production paths — **Critical**. Properly guarded behind `NODE_ENV === 'development'` → **Should Fix** (environment misconfigurations frequently expose these); verify the guard covers every call site.
|
|
33
|
+
- **Provider-specific security gotchas:**
|
|
34
|
+
- **Clerk:** Check `middleware.ts` matcher regexes. If `/api/(.*)` is omitted from the protected matcher, or if Clerk v5 `auth.protect()` is omitted from sensitive API routes → **Critical**.
|
|
35
|
+
- **NextAuth / Auth.js:** Missing `AUTH_SECRET` / `NEXTAUTH_SECRET` in production configuration; exposing sensitive user properties or database credentials inside client session callbacks → **Should Fix**.
|
|
36
|
+
- **Supabase Auth:** Using `supabase.auth.getSession()` on the server (Server Components, API routes, Server Actions) instead of `supabase.auth.getUser()`. `getSession()` reads local cookies without re-validating the token with the Supabase Auth server → **Critical**.
|
|
37
|
+
- **Firebase Auth:** Unverified `auth.currentUser` on the client trusted on server routes without server-side `admin.auth().verifyIdToken()`.
|
|
38
|
+
- **Protected routes with no auth check at all:** Compare routes that return or modify user-specific data against route definitions. Any route touching user records with no guard is **Critical**.
|
|
39
|
+
- **Client-side-only enforcement:** UI hides a button or redirects on the client (`{user.isAdmin && <AdminPanel />}`), but the underlying API endpoint lacks an authentication/role check — **Critical**. Anyone can call the API directly. You MUST inspect the server route.
|
|
40
|
+
- **Cookie & Token Storage Security:** Auth tokens stored in browser `localStorage` (vulnerable to XSS token theft) rather than `httpOnly`, `Secure`, `SameSite=Lax/Strict` cookies → **Should Fix**.
|
|
41
|
+
- **Password hashing in custom auth:** Storing passwords in plaintext, or using outdated hash algorithms (MD5, SHA-1, plain SHA-256 without salt/work factor) instead of bcrypt or argon2 → **Critical**.
|
|
37
42
|
|
|
38
43
|
## Step 3 — Judgment rules
|
|
39
44
|
|
|
40
45
|
- Read the function body fully before flagging or clearing — never decide from the name alone.
|
|
41
46
|
- Prefer one precise finding over several weak ones; tag uncertain items `High confidence` / `Medium confidence` / `Needs manual review`.
|
|
42
|
-
- Identify the stack's intended auth mechanism (
|
|
47
|
+
- Identify the stack's intended auth mechanism (Clerk, NextAuth, Supabase Auth, Firebase, custom JWT/session) first; "missing" means missing relative to how routes access user data, not absence of a specific library.
|
|
43
48
|
|
|
44
49
|
## Report
|
|
45
50
|
|
|
51
|
+
Save the complete, detailed audit report to `checkmyvibe-report.md` in the target directory following the report structure in `SKILL.md`. Output the executive summary, key findings, and verdict in your conversation response, and include a reference to `checkmyvibe-report.md`.
|
|
46
52
|
Use the format, severity rubric, and final-summary structure from SKILL.md. Scope reminder: "authentication-only check — secrets, .gitignore, database rules, IDOR, input validation, and payment checks were skipped. This does not mean the app is production-ready. Run a full `/checkmyvibe` audit before launch."
|
|
@@ -14,19 +14,20 @@ Use SKILL.md **only** for the report format, severity rubric, and final-summary
|
|
|
14
14
|
|
|
15
15
|
This is a **backend-only check**: Check 1a (server-side secrets) + Check 3 (auth) + Check 4 (db) + Check 5 (IDOR) + Check 6 server-side + Check 7 server-side. Skipped and to be listed as such in the summary: Check 1b (client-exposed secrets), Check 2 (.gitignore hygiene), and client-side views of checks 3/6/7.
|
|
16
16
|
|
|
17
|
-
## Step 1 — Run all
|
|
17
|
+
## Step 1 — Run all four scripts
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
20
|
python <skill_dir>/scripts/scan_secrets.py <target>
|
|
21
21
|
python <skill_dir>/scripts/check_auth_patterns.py <target>
|
|
22
22
|
python <skill_dir>/scripts/check_db_config.py <target>
|
|
23
|
+
python <skill_dir>/scripts/check_payment_config.py <target>
|
|
23
24
|
```
|
|
24
25
|
|
|
25
|
-
Triage per the rules in `/checkmyvibe-secrets`, `/checkmyvibe-auth`,
|
|
26
|
+
Triage findings per the rules in `/checkmyvibe-secrets`, `/checkmyvibe-auth`, `/checkmyvibe-db`, and `/checkmyvibe-payment` respectively. If Python is unavailable, do each check manually and say so in the report.
|
|
26
27
|
|
|
27
|
-
## Step 2 — IDOR sweep (Check 5 — spend the most time here)
|
|
28
|
+
## Step 2 — IDOR / BOLA sweep (Check 5 — spend the most time here)
|
|
28
29
|
|
|
29
|
-
This is the single most common serious flaw in AI-generated apps. Enumerate every route
|
|
30
|
+
This is the single most common serious flaw in AI-generated apps. Enumerate every route, Next.js Server Action, or RPC procedure that takes an ID and touches a database record:
|
|
30
31
|
|
|
31
32
|
```js
|
|
32
33
|
// Finding example — Critical: any logged-in user reads ANY order
|
|
@@ -41,22 +42,31 @@ const order = await db.query(
|
|
|
41
42
|
if (!order) return res.status(404).json({ error: 'Not found' });
|
|
42
43
|
```
|
|
43
44
|
|
|
44
|
-
|
|
45
|
+
### Advanced IDOR Patterns to Check:
|
|
46
|
+
- **Multi-Tenant / Organization IDOR:** In B2B or team workspaces, verifying `organization_id = req.params.orgId` is NOT enough. You must verify that the requesting `req.user.id` is an active member/admin of `orgId` before executing the query → **Critical**.
|
|
47
|
+
- **Next.js Server Actions:** Functions marked `'use server'` (`export async function deleteDocument(docId)`) are public RPC endpoints. If user authentication and document ownership are not verified inside the function body, anyone can invoke the action remotely → **Critical**.
|
|
48
|
+
- **tRPC / GraphQL Resolvers:** Check that resolvers pulling resources by ID verify authorization in context rather than returning records purely by input ID.
|
|
49
|
+
- Check GET (exposure), PUT/PATCH (modification), and DELETE (often most damaging) across all endpoints.
|
|
45
50
|
|
|
46
|
-
## Step 3 — Server-side input handling (Check 6)
|
|
51
|
+
## Step 3 — Server-side input handling & validation (Check 6)
|
|
47
52
|
|
|
48
|
-
- SQL built by string concatenation instead of parameterized queries
|
|
49
|
-
- **
|
|
50
|
-
-
|
|
51
|
-
-
|
|
52
|
-
-
|
|
53
|
+
- **SQL built by string concatenation** instead of parameterized queries or ORM methods → **Critical**.
|
|
54
|
+
- **NoSQL / MongoDB Injection:** Passing `req.body` or `req.query` directly into `find()`, `findOne()`, or `deleteMany()` without sanitization → **Critical** (`{ "$gt": "" }` bypasses checks).
|
|
55
|
+
- **Server-Side Request Forgery (SSRF):** Endpoints that fetch user-supplied URLs (link scrapers, webhooks, image proxies via `axios.get(req.body.url)` or `fetch()`). If URLs are not validated against private IP ranges (`127.0.0.1`, `localhost`, `169.254.169.254` AWS metadata, internal RFC1918 subnets), attackers can exfiltrate cloud credentials or hit internal services → **Critical**.
|
|
56
|
+
- **Mass assignment:** `req.body` spread straight into ORM create/update (`prisma.user.update({ data: req.body })`, `User.findByIdAndUpdate(id, req.body)`) letting users set `role`, `plan`, `isAdmin`, `emailVerified` → **Critical**; non-privileged fields → **Should Fix**.
|
|
57
|
+
- **CORS Misconfiguration:** Wildcard CORS reflection with credentials (`cors({ origin: '*', credentials: true })`) → **Critical**.
|
|
58
|
+
- **Rate limiting on auth endpoints:** Login, signup, password reset, and OTP endpoints with no attempt throttle allow credential stuffing and SMS toll fraud → **Should Fix**.
|
|
59
|
+
- **Unrestricted File Uploads:** Upload endpoints with no validation of MIME type or file size.
|
|
53
60
|
|
|
54
61
|
## Step 4 — Payment processing & webhooks (Check 7, server side)
|
|
55
62
|
|
|
56
|
-
- Price/discount/total taken from request body, query param, or hidden field instead of looked up from the DB → Critical
|
|
57
|
-
- **Webhook signature verification:**
|
|
58
|
-
- Webhook
|
|
63
|
+
- Price/discount/total taken from request body, query param, or hidden field instead of looked up from the DB → **Critical**.
|
|
64
|
+
- **Webhook signature verification:** Every payment webhook route (**Stripe**, **Lemon Squeezy**, **Dodo Payments**, **Polar**, **Paddle**, **Razorpay**, **PayPal**) must verify cryptographic signatures before trusting the body. An unverified webhook route → **Critical** (anyone can POST fake successful payments).
|
|
65
|
+
- **Webhook Idempotency:** Missing event deduplication on gateway `event.id` causing duplicate credits on retried webhooks → **Should Fix**.
|
|
66
|
+
- **Subscription Revocation:** Missing handling for subscription cancellation/expiration events (`customer.subscription.deleted`, `subscription_cancelled`) → **Critical**.
|
|
67
|
+
- **Customer Portal IDOR:** Creating customer billing sessions using `req.body.customerId` instead of the session user's record → **Critical**.
|
|
59
68
|
|
|
60
69
|
## Report
|
|
61
70
|
|
|
71
|
+
Save the complete, detailed audit report to `checkmyvibe-report.md` in the target directory following the report structure in `SKILL.md`. Output the executive summary, key findings, and verdict in your conversation response, and include a reference to `checkmyvibe-report.md`.
|
|
62
72
|
Use the format, severity rubric, evidence/confidence rules, and post-fix verification step from SKILL.md. Fix priority when multiple issues exist: critical user exposure > auth bypass > IDOR > payment logic > config > hygiene. Scope reminder: "backend-only check — client-exposed secrets, .gitignore hygiene, and frontend-side views were skipped. This does not mean the app is production-ready. Run a full `/checkmyvibe` audit before launch."
|
|
@@ -20,32 +20,50 @@ This is a **database-only check** (Check 4). Checks 1a/1b, 2, 3, 5, 6, and 7 are
|
|
|
20
20
|
python <skill_dir>/scripts/check_db_config.py <target>
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
It scans
|
|
23
|
+
It scans for:
|
|
24
|
+
- SQL migrations/schemas for tables created without RLS and permissive policies (`USING (true)` / `WITH CHECK (true)`) in BaaS stacks.
|
|
25
|
+
- Firestore/storage rules for `allow ...: if true` and Realtime Database rules set to `"true"`.
|
|
26
|
+
- Exposed SQLite database files (`.sqlite`, `.db`) located in web-accessible directories (`public/`, `static/`, `www/`, `dist/`).
|
|
27
|
+
- NoSQL/MongoDB direct object injection (`find(req.body)`).
|
|
28
|
+
- Insecure database connection configs (`sslmode=disable`, `rejectUnauthorized: false`).
|
|
24
29
|
|
|
25
|
-
|
|
30
|
+
If Python is unavailable or it fails, do the equivalent checks by reading schema/rules files manually and say so in the report.
|
|
26
31
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
32
|
+
## Step 2 — Determine the Database Architecture
|
|
33
|
+
|
|
34
|
+
Distinguish between two very different database models:
|
|
35
|
+
|
|
36
|
+
### Branch A: Client-Exposed BaaS (Supabase, Firebase, Convex)
|
|
37
|
+
In these stacks, the browser connects directly to the database using an anonymous public API key. Security MUST be enforced at the database row/collection level:
|
|
38
|
+
|
|
39
|
+
- **Supabase:** Every table holding user-specific data must have `ENABLE ROW LEVEL SECURITY`. A table without it → **Critical**.
|
|
40
|
+
- Policies granting broad access fail: `FOR SELECT USING (true)`, policies `TO public/anon` with unconditional USING/CHECK → **Critical**.
|
|
41
|
+
- Fix pattern:
|
|
30
42
|
```sql
|
|
31
43
|
CREATE POLICY "users see own orders" ON orders
|
|
32
44
|
FOR SELECT USING (auth.uid() = user_id);
|
|
33
45
|
```
|
|
34
|
-
-
|
|
46
|
+
- **Firebase:** `firestore.rules` containing `allow read, write: if true;` on user data collections → **Critical**. `database.rules.json` with `".read": "true"` → **Critical**.
|
|
47
|
+
- **Convex:** Ensure functions returning private data are defined as `internalQuery` or validate `ctx.auth.getUserIdentity()`.
|
|
35
48
|
|
|
36
|
-
|
|
49
|
+
### Branch B: Server-Backed Databases & ORMs (Neon, AWS RDS, Prisma, Drizzle, Local DBs, Mongo)
|
|
50
|
+
In these stacks, client browsers never talk to the database directly; all queries flow through a backend server (Express, FastAPI, Next.js server):
|
|
37
51
|
|
|
38
|
-
-
|
|
39
|
-
-
|
|
40
|
-
-
|
|
52
|
+
- **Do NOT flag missing RLS on server-only tables:** Standard SQL migrations generated by Prisma or Drizzle do not require Postgres RLS if queries are filtered in backend application code.
|
|
53
|
+
- **Neon & Serverless Pooling:** Verify that serverless functions connect via connection pooling (e.g. `@neondatabase/serverless` or PgBouncer pooled connection strings). Direct unpooled Postgres connections in serverless routes cause connection exhaustion and crashes → **Should Fix**.
|
|
54
|
+
- **SSL / Transport Security:** Database connection URIs or pool configs with `sslmode=disable` or `rejectUnauthorized: false` transmit credentials and data in cleartext → **Critical** in production.
|
|
55
|
+
- **SQLite / Embedded DBs:** SQLite databases (`*.db`, `*.sqlite`, `*.sqlite3`) placed in web-accessible public folders (`public/`, `static/`) or committed to git allow arbitrary database download by any visitor → **Critical**.
|
|
56
|
+
- **MongoDB / NoSQL Injection:** Passing unescaped `req.body` or `req.query` directly into Mongoose/MongoDB query filters (e.g., `User.findOne(req.body)`) allows query selector injection (`{ "$gt": "" }` bypassing passwords) → **Critical**.
|
|
57
|
+
- **Hardcoded DB Credentials:** Database connection strings with embedded plaintext passwords committed in code or schemas (e.g., in `schema.prisma` datasource) → **Critical**.
|
|
41
58
|
|
|
42
|
-
## Step
|
|
59
|
+
## Step 3 — Storage buckets
|
|
43
60
|
|
|
44
|
-
Supabase Storage, Firebase Storage, S3:
|
|
61
|
+
Supabase Storage, Firebase Storage, AWS S3:
|
|
45
62
|
|
|
46
|
-
- Public buckets holding private user content (documents, receipts, profile files) → Critical
|
|
47
|
-
- Public buckets for genuinely public assets (avatars, static images) → not findings; note the distinction.
|
|
63
|
+
- Public buckets holding private user content (documents, receipts, profile identity files) → **Critical**.
|
|
64
|
+
- Public buckets for genuinely public assets (avatars, static product images) → not findings; note the distinction.
|
|
48
65
|
|
|
49
66
|
## Report
|
|
50
67
|
|
|
68
|
+
Save the complete, detailed audit report to `checkmyvibe-report.md` in the target directory following the report structure in `SKILL.md`. Output the executive summary, key findings, and verdict in your conversation response, and include a reference to `checkmyvibe-report.md`.
|
|
51
69
|
Use the format, severity rubric, and final-summary structure from SKILL.md. Scope reminder: "database-only check — secrets, .gitignore, authentication, IDOR, input validation, and payment checks were skipped. This does not mean the app is production-ready. Run a full `/checkmyvibe` audit before launch."
|
|
@@ -12,7 +12,7 @@ Use SKILL.md **only** for the report format, severity rubric, and final-summary
|
|
|
12
12
|
|
|
13
13
|
## Scope
|
|
14
14
|
|
|
15
|
-
This is a **frontend-only check**: Check 1b (client-exposed secrets) + Check 3 viewed from the client (UI-only enforcement) + Check 7 viewed from the client (client-controlled pricing). Skipped and to be listed as such in the summary: Check 1a standalone triage, Check 2 (.gitignore), Check 4 (db rules), Check 5 (IDOR sweep), and full server-side reviews
|
|
15
|
+
This is a **frontend-only check**: Check 1b (client-exposed secrets) + Check 3 viewed from the client (UI-only enforcement) + Check 6 viewed from the client (DOM XSS / AI markdown rendering) + Check 7 viewed from the client (client-controlled pricing). Skipped and to be listed as such in the summary: Check 1a standalone triage, Check 2 (.gitignore), Check 4 (db rules), Check 5 (IDOR sweep), and full server-side reviews.
|
|
16
16
|
|
|
17
17
|
## Step 1 — Client-exposed secrets (run script, then manual pass)
|
|
18
18
|
|
|
@@ -22,27 +22,41 @@ python <skill_dir>/scripts/scan_secrets.py <target>
|
|
|
22
22
|
|
|
23
23
|
Then manually inspect everything reachable from the browser:
|
|
24
24
|
|
|
25
|
-
- Framework
|
|
26
|
-
-
|
|
27
|
-
-
|
|
25
|
+
- **Framework Env Prefixes:** `NEXT_PUBLIC_*`, `VITE_*`, `REACT_APP_*`, `EXPO_PUBLIC_*`. Any secret behind one of these is inlined into shipped JavaScript → **Critical**.
|
|
26
|
+
- **React Server Component (RSC) Prop Leaks:** In Next.js App Router, check if a Server Component imports a private secret and passes it as a prop to a client component (`<ClientComponent apiKey={process.env.PRIVATE_KEY} />`). Next.js serializes all props into the client HTML payload → **Critical**.
|
|
27
|
+
- Supabase `service_role` key, Firebase admin SDK JSON, OpenAI (`sk-proj-`), Anthropic, or Stripe secret keys anywhere under `src/`, `app/`, `components/`, `pages/`, `public/`, or client entry files → **Critical**.
|
|
28
|
+
- Publishable keys (`pk_`, Supabase anon key, Firebase web config `apiKey`) are public-by-design → **NOT findings**; note this explicitly so the user isn't confused.
|
|
28
29
|
- Placeholders and test-fixture values → not findings.
|
|
29
30
|
|
|
30
|
-
## Step 2 —
|
|
31
|
+
## Step 2 — DOM XSS & Unescaped AI Markdown Rendering
|
|
32
|
+
|
|
33
|
+
AI-generated applications frequently display LLM responses, user bios, or chat logs:
|
|
34
|
+
|
|
35
|
+
- Inspect components rendering HTML or markdown (`react-markdown`, `marked`, `markdown-it`).
|
|
36
|
+
- **Unescaped rendering:** Rendering LLM or user markdown with `dangerouslySetInnerHTML`, `v-html`, or `react-markdown` without `rehype-sanitize` or DOMPurify → **Critical** (an attacker or malicious prompt injection can inject `<script>` tags, `<img onerror=...>`, or iframe exploits directly into users' browsers).
|
|
37
|
+
|
|
38
|
+
## Step 3 — UI-only auth enforcement (Check 3, client view)
|
|
31
39
|
|
|
32
40
|
Find every place the UI gates access: redirects on protected pages, hidden nav items, disabled buttons, client route guards:
|
|
33
41
|
|
|
34
|
-
- For each gated feature, open the corresponding API route/mutation and confirm it independently verifies the session server-side. If it does not → Critical ("hiding the button does nothing; anyone
|
|
35
|
-
- Auth state trusted purely from client storage (localStorage JWT, global store) to protect data → Critical if no server verification exists.
|
|
42
|
+
- For each gated feature, open the corresponding API route/mutation/Server Action and confirm it independently verifies the session server-side. If it does not → **Critical** ("hiding the button does nothing; anyone can call the endpoint directly").
|
|
43
|
+
- Auth state trusted purely from client storage (localStorage JWT, global store) to protect data → **Critical** if no server verification exists.
|
|
36
44
|
- You must read the server routes to clear or confirm findings — a clean-looking frontend proves nothing on its own.
|
|
37
45
|
|
|
38
|
-
## Step
|
|
46
|
+
## Step 4 — Client-controlled pricing (Check 7, client view)
|
|
39
47
|
|
|
40
48
|
Inspect checkout/cart/pricing flows:
|
|
41
49
|
|
|
42
|
-
- Prices, discounts, totals, or quantities computed client-side and sent as the chargeable value (hidden form fields, request bodies, query params) → Critical on the corresponding server endpoint.
|
|
50
|
+
- Prices, discounts, totals, or quantities computed client-side and sent as the chargeable value (hidden form fields, request bodies, query params) → **Critical** on the corresponding server endpoint.
|
|
43
51
|
- Coupon codes validated only in the UI → flag the endpoint that accepts them without server-side validation.
|
|
44
52
|
- Note exactly which server endpoint accepts the tainted value so the backend fix is obvious.
|
|
45
53
|
|
|
54
|
+
## Step 5 — Security Headers & Analytics Data Hygiene
|
|
55
|
+
|
|
56
|
+
- **Clickjacking:** Missing `X-Frame-Options: DENY` or `Content-Security-Policy: frame-ancestors 'none'` allows malicious sites to embed the app in an invisible iframe → **Should Fix**.
|
|
57
|
+
- **Analytics PII auto-capture:** Session recording tools (PostHog, Hotjar, LogRocket) capturing private form fields (passwords, credit card numbers, auth tokens) without masking classes (`data-mask` / `ph-no-capture`) → **Should Fix**.
|
|
58
|
+
|
|
46
59
|
## Report
|
|
47
60
|
|
|
61
|
+
Save the complete, detailed audit report to `checkmyvibe-report.md` in the target directory following the report structure in `SKILL.md`. Output the executive summary, key findings, and verdict in your conversation response, and include a reference to `checkmyvibe-report.md`.
|
|
48
62
|
Use the format, severity rubric, and final-summary structure from SKILL.md. Scope reminder: "frontend-only check — server-side secret triage, .gitignore hygiene, database rules, IDOR, server input validation, and webhook verification were skipped. This does not mean the app is production-ready. Run a full `/checkmyvibe` audit before launch."
|
|
@@ -14,17 +14,36 @@ Use SKILL.md **only** for the report format, severity rubric, and final-summary
|
|
|
14
14
|
|
|
15
15
|
This is a **payment/pricing-only check** (Check 7, both client and server views). Checks 1a/1b, 2, 3, 4, 5, and 6 are skipped and must be listed as skipped in the final summary. Note: if this app handles real payments, state in the report that a professional external review is strongly recommended regardless of findings.
|
|
16
16
|
|
|
17
|
-
## Step 1 —
|
|
17
|
+
## Step 1 — Run the first-pass script
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
```bash
|
|
20
|
+
python <skill_dir>/scripts/check_payment_config.py <target>
|
|
21
|
+
```
|
|
20
22
|
|
|
21
|
-
|
|
23
|
+
It scans source files for client-controlled amounts/prices in checkout endpoints, detects payment webhook routes, checks for provider signature verification (Stripe, Lemon Squeezy, Dodo Payments, Paddle, Razorpay), checks for missing subscription cancellation listeners, and detects billing portal IDOR risks.
|
|
24
|
+
|
|
25
|
+
If Python is unavailable or it fails, do the equivalent checks by reading payment handlers manually and say so in the report.
|
|
26
|
+
|
|
27
|
+
## Step 2 — Map the payment surface
|
|
28
|
+
|
|
29
|
+
Identify all payment and merchant-of-record providers in use:
|
|
30
|
+
- **Stripe** (`stripe`, `@stripe/stripe-js`)
|
|
31
|
+
- **Dodo Payments** (AI app monetization)
|
|
32
|
+
- **Lemon Squeezy** (`@lemonsqueezy/lemonsqueezy.js`)
|
|
33
|
+
- **Polar.sh** (`@polar-sh/sdk`)
|
|
34
|
+
- **Paddle** (`@paddle/paddle-node-sdk`)
|
|
35
|
+
- **Razorpay** (`razorpay`)
|
|
36
|
+
- **PayPal** (`@paypal/checkout-server-sdk`)
|
|
37
|
+
|
|
38
|
+
Locate checkout endpoints, webhook routes, cart/price calculation code, subscription tier handlers, and coupon/discount handling. If there is no payment code at all, report "No issues found — no payment flow exists" and stop.
|
|
39
|
+
|
|
40
|
+
## Step 3 — Server-side price trust
|
|
22
41
|
|
|
23
42
|
For each chargeable action:
|
|
24
43
|
|
|
25
|
-
- Is the amount read from the request (body field, query param, hidden form field) or computed from client-supplied data? → Critical
|
|
44
|
+
- Is the amount read from the request (body field, query param, hidden form field) or computed from client-supplied data? → **Critical**:
|
|
26
45
|
```js
|
|
27
|
-
// Finding example — Critical
|
|
46
|
+
// Finding example — Critical: client controls price
|
|
28
47
|
const { productId, price } = req.body;
|
|
29
48
|
await chargeCard(req.user.paymentMethod, price);
|
|
30
49
|
|
|
@@ -33,20 +52,40 @@ For each chargeable action:
|
|
|
33
52
|
const product = await db.query('SELECT price FROM products WHERE id = $1', [productId]);
|
|
34
53
|
await chargeCard(req.user.paymentMethod, product.price);
|
|
35
54
|
```
|
|
36
|
-
- Quantities, currency, plan tiers, or seat counts accepted from the client and multiplied into totals without server-side
|
|
37
|
-
- Coupons/discounts validated only on the client, or discount values sent by the client rather than looked up server-side → Critical
|
|
38
|
-
- Free-trial/trial-flag booleans trusted from request bodies → Critical (anyone posts `trial: true` forever).
|
|
55
|
+
- Quantities, currency, plan tiers, or seat counts accepted from the client and multiplied into totals without server-side validation → same severity.
|
|
56
|
+
- Coupons/discounts validated only on the client, or discount values sent by the client rather than looked up server-side → **Critical**.
|
|
57
|
+
- Free-trial/trial-flag booleans trusted from request bodies (`req.body.trial = true`) → **Critical** (anyone posts `trial: true` forever).
|
|
39
58
|
|
|
40
|
-
## Step
|
|
59
|
+
## Step 4 — Webhook signature verification across providers
|
|
41
60
|
|
|
42
61
|
Every payment webhook route must verify authenticity BEFORE trusting or acting on its body:
|
|
43
62
|
|
|
44
|
-
- Stripe
|
|
45
|
-
-
|
|
46
|
-
-
|
|
47
|
-
-
|
|
48
|
-
-
|
|
63
|
+
- **Stripe:** `stripe.webhooks.constructEvent(rawBody, sigHeader, process.env.STRIPE_WEBHOOK_SECRET)` with `express.raw({ type: 'application/json' })`.
|
|
64
|
+
- **Lemon Squeezy:** Verify `x-signature` header using `crypto.createHmac('sha256', secret).update(rawBody).digest('hex')` (with timing-safe comparison).
|
|
65
|
+
- **Dodo Payments:** Verify webhook signature header via Dodo SDK or HMAC verification.
|
|
66
|
+
- **Paddle:** Verify signature with `paddle.webhooks.unmarshal` or HMAC check.
|
|
67
|
+
- **Razorpay:** `validateWebhookSignature` or `crypto.createHmac('sha256', secret)` comparison.
|
|
68
|
+
- **PayPal:** `verify-webhook-signature` API call.
|
|
69
|
+
|
|
70
|
+
No signature verification anywhere in the handler chain → **Critical**: anyone who finds the URL can POST a fake "payment succeeded" event and get orders or licenses marked paid for free.
|
|
71
|
+
|
|
72
|
+
## Step 5 — Webhook Idempotency & Replay Attack Prevention
|
|
73
|
+
|
|
74
|
+
Payment gateways retry webhooks if an endpoint takes >3s or returns 5xx:
|
|
75
|
+
- Check if webhook handlers record the processed gateway event ID (`event.id`) in the database before granting access or fulfilling orders.
|
|
76
|
+
- If missing, a retried webhook can cause duplicate credits, duplicate license generation, or double-shipping → **Should Fix**.
|
|
77
|
+
|
|
78
|
+
## Step 6 — Subscription Cancellation & Revocation Lifecycle
|
|
79
|
+
|
|
80
|
+
- AI apps often handle `checkout.session.completed` to grant access, but completely omit `customer.subscription.deleted`, `customer.subscription.updated`, `subscription_cancelled`, or `invoice.payment_failed`.
|
|
81
|
+
- If the revocation event is not handled, users who cancel their plan or whose credit cards expire retain paid access indefinitely → **Critical**.
|
|
82
|
+
|
|
83
|
+
## Step 7 — Billing Portal IDOR
|
|
84
|
+
|
|
85
|
+
- Inspect customer billing portal session creation (e.g. `stripe.billingPortal.sessions.create`):
|
|
86
|
+
- If `customerId` is taken from `req.body` rather than resolved from the authenticated user's session record in the database, users can manage, view invoices for, or cancel other customers' subscriptions → **Critical**.
|
|
49
87
|
|
|
50
88
|
## Report
|
|
51
89
|
|
|
90
|
+
Save the complete, detailed audit report to `checkmyvibe-report.md` in the target directory following the report structure in `SKILL.md`. Output the executive summary, key findings, and verdict in your conversation response, and include a reference to `checkmyvibe-report.md`.
|
|
52
91
|
Use the format, severity rubric, and final-summary structure from SKILL.md. Scope reminder: "payment-only check — secrets, .gitignore, authentication, database rules, IDOR, and input validation were skipped. This does not mean the app is production-ready. Run a full `/checkmyvibe` audit before launch, and get a professional security review before handling real money."
|
|
@@ -21,35 +21,44 @@ python <skill_dir>/scripts/scan_secrets.py <target>
|
|
|
21
21
|
python <skill_dir>/scripts/check_gitignore.py <target>
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
If Python is unavailable or a script fails, say so explicitly in the report ("automated secret scan could not run; manually reviewed instead") and do the equivalent manually: grep for key prefixes (`sk_live_`, `sk_test_`, `AIza`, `AKIA`, `ghp_`, `xox[bp]-`) and literal assignments to names containing `key`, `secret`, `token`, `password`.
|
|
24
|
+
If Python is unavailable or a script fails, say so explicitly in the report ("automated secret scan could not run; manually reviewed instead") and do the equivalent manually: grep for key prefixes (`sk-proj-`, `sk-ant-`, `gsk_`, `re_`, `sk_live_`, `sk_test_`, `AIza`, `AKIA`, `ghp_`, `xox[bp]-`), JWT tokens with `service_role`, database URIs, and literal assignments to names containing `key`, `secret`, `token`, `password`.
|
|
25
25
|
|
|
26
26
|
## Step 2 — Triage every script finding
|
|
27
27
|
|
|
28
28
|
The scripts over-match on purpose. For each hit, open the file and decide:
|
|
29
29
|
|
|
30
|
-
- **
|
|
31
|
-
- **
|
|
32
|
-
- **
|
|
33
|
-
- **
|
|
30
|
+
- **OpenAI Project Keys (`sk-proj-...`, `sk-None-...`)** → **Critical**. Charges API accounts. Revoke immediately at platform.openai.com.
|
|
31
|
+
- **Anthropic Claude Keys (`sk-ant-api03-...`)** → **Critical**. Charges API usage. Revoke at console.anthropic.com.
|
|
32
|
+
- **Groq (`gsk_...`), Perplexity (`pplx-...`), HuggingFace (`hf_...`)** → **Critical**. Revoke at provider consoles.
|
|
33
|
+
- **Resend Email Keys (`re_...`)** → **Critical**. Used for phishing and mass spam abuse under your domain.
|
|
34
|
+
- **Supabase `service_role` JWT (containing `"role":"service_role"`)** → **Critical**. Completely bypasses Row-Level Security across all tables.
|
|
35
|
+
- **Database Connection URIs with passwords** (`postgres://...:...@...`, `mongodb+srv://...`) → **Critical**. Direct database access.
|
|
36
|
+
- **Live Stripe key (`sk_live_...`)** → **Critical**. Charges real cards. Recommend immediate rotation at dashboard.stripe.com.
|
|
37
|
+
- **Test Stripe key (`sk_test_...`) in source** → **Should Fix**. Must not be committed; rotate if repo was ever shared/pushed publicly.
|
|
38
|
+
- **AWS `AKIA`, Google `AIza`, GitHub `ghp_`, Slack tokens in source** → **Critical**.
|
|
39
|
+
- **Publishable keys (`pk_live`, `pk_test`, Supabase anon keys, Firebase apiKey config)** → **NOT findings**. These are public-by-design; note this distinction so the user isn't confused.
|
|
34
40
|
- **Placeholders** (`your-api-key-here`, `<secret>`, dummy values) → not findings.
|
|
35
|
-
- Anything inside test/fixture/mock directories → not findings (
|
|
41
|
+
- Anything inside test/fixture/mock directories → not findings (scripts skip these).
|
|
36
42
|
|
|
37
43
|
## Step 3 — Client-exposure pass (Check 1b)
|
|
38
44
|
|
|
39
|
-
|
|
45
|
+
Verify secrets aren't reachable from the browser:
|
|
40
46
|
|
|
41
47
|
- Grep frontend code (`src/`, `app/`, `components/`, `pages/`, `public/`, client entry points) for references to secret env vars or service-role keys.
|
|
42
|
-
- In Next.js
|
|
43
|
-
-
|
|
48
|
+
- **Bundler Prefixes:** In Next.js, Vite, CRA, Expo: any secret placed behind `NEXT_PUBLIC_*`, `VITE_*`, `REACT_APP_*`, `EXPO_PUBLIC_*` gets bundled into shipped browser JavaScript → **Critical**.
|
|
49
|
+
- **React Server Component (RSC) prop leaks:** In Next.js App Router, check if a Server Component imports a private secret and passes it as a prop to a client component (`<ClientComponent apiKey={process.env.PRIVATE_KEY} />`). Next.js serializes props into the client payload JSON → **Critical**.
|
|
50
|
+
- Supabase `service_role` key, Firebase admin SDK private key JSON, OpenAI/Stripe/Anthropic secret keys appearing anywhere client-reachable → **Critical**.
|
|
44
51
|
|
|
45
|
-
## Step 4 — .gitignore hygiene (Check 2)
|
|
52
|
+
## Step 4 — .gitignore & Docker hygiene (Check 2)
|
|
46
53
|
|
|
47
54
|
From `check_gitignore.py` output plus manual review:
|
|
48
55
|
|
|
49
|
-
- `.env
|
|
50
|
-
-
|
|
51
|
-
-
|
|
56
|
+
- `.env`, `.env.local`, `.env.production` present but not ignored in `.gitignore` → **Critical** regardless of contents.
|
|
57
|
+
- **Docker risk:** If a `Dockerfile` exists and `.env` is omitted from `.dockerignore` → **Critical** (bakes secret environment files into public container image layers).
|
|
58
|
+
- **NPM auth tokens:** `.npmrc` files containing `_authToken=` committed in git → **Critical**.
|
|
59
|
+
- Run `git log --all --full-history -- .env` (if git available). If `.env` was ever committed → **Critical**, and state plainly: removing it now is not enough; every secret in git history must be rotated because git history remains permanently recoverable.
|
|
52
60
|
|
|
53
61
|
## Report
|
|
54
62
|
|
|
63
|
+
Save the complete, detailed audit report to `checkmyvibe-report.md` in the target directory following the report structure in `SKILL.md`. Output the executive summary, key findings, and verdict in your conversation response, and include a reference to `checkmyvibe-report.md`.
|
|
55
64
|
Use the format, severity rubric, and final-summary structure from SKILL.md. Scope reminder for this run: "secrets-only check — Checks 3 (auth), 4 (db), 5 (IDOR), 6 (inputs), and 7 (payments) were skipped. This does not mean the app is secure. Run a full `/checkmyvibe` audit before launch."
|
package/commands/checkmyvibe.md
CHANGED
|
@@ -12,15 +12,16 @@ If it still cannot be found, tell the user and stop — do not improvise an audi
|
|
|
12
12
|
|
|
13
13
|
Then read `SKILL.md` in full and run the **complete audit: Checks 1a, 1b, 2, 3, 4, 5, 6, and 7**:
|
|
14
14
|
|
|
15
|
-
- Check 1a — server-side secrets and credentials
|
|
16
|
-
- Check 1b — client-exposed secrets
|
|
17
|
-
- Check 2 — .gitignore hygiene (including git-history check for committed `.env`)
|
|
18
|
-
- Check 3 — missing or fake authentication
|
|
19
|
-
- Check 4 — database
|
|
20
|
-
- Check 5 — broken object-level authorization (IDOR/BOLA
|
|
21
|
-
- Check 6 — unvalidated inputs, SQLi
|
|
22
|
-
- Check 7 — client-side payment
|
|
23
|
-
|
|
24
|
-
Run every script in the skill's `scripts/` folder
|
|
25
|
-
|
|
15
|
+
- Check 1a — server-side secrets and credentials (OpenAI, Anthropic, Groq, Resend, Supabase service-role JWTs, database URIs, Stripe, cloud keys)
|
|
16
|
+
- Check 1b — client-exposed secrets & RSC server-to-client prop leaks
|
|
17
|
+
- Check 2 — .gitignore and .dockerignore hygiene (including git-history check for committed `.env` and `.npmrc`)
|
|
18
|
+
- Check 3 — missing or fake authentication (mock user returns, no-op `next()` stubs, Clerk matcher holes, NextAuth secrets, Supabase `getUser`)
|
|
19
|
+
- Check 4 — database misconfiguration (Supabase RLS, Firebase rules, Neon pooling/SSL, Prisma/Drizzle schema checks, public SQLite files, MongoDB injection)
|
|
20
|
+
- Check 5 — broken object-level authorization (IDOR/BOLA across REST routes, Next.js Server Actions, tRPC, and multi-tenant org boundaries)
|
|
21
|
+
- Check 6 — unvalidated inputs (SSRF in AI link/image scrapers, SQLi, NoSQL injection, DOM XSS in AI markdown, mass assignment, CORS wildcards, rate limiting)
|
|
22
|
+
- Check 7 — client-side payment logic, webhook signature verification (Stripe, Lemon Squeezy, Dodo Payments, Polar, Paddle, Razorpay), webhook idempotency, and subscription lifecycle handling
|
|
23
|
+
|
|
24
|
+
Run every script in the skill's `scripts/` folder (`scan_secrets.py`, `check_gitignore.py`, `check_auth_patterns.py`, `check_db_config.py`, `check_payment_config.py`) against the target directory before relying on your own reasoning. If Python is unavailable or a script fails, state that explicitly in the report and do the check manually instead of silently skipping it.
|
|
25
|
+
|
|
26
|
+
Save the complete, detailed audit report to `checkmyvibe-report.md` in the target directory following the report structure in `SKILL.md`. Output the executive summary, key findings, and verdict in your conversation response, and include a reference to `checkmyvibe-report.md`.
|
|
26
27
|
Use the report format, severity rubric, evidence/confidence rules, post-fix verification step, and full-audit final summary structure defined in `SKILL.md`.
|