checkmyvibe 1.0.2 → 1.2.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 +22 -10
- package/SKILL.md +82 -17
- package/commands/checkmyvibe-auth.md +46 -0
- package/commands/checkmyvibe-backend.md +62 -0
- package/commands/checkmyvibe-db.md +51 -0
- package/commands/checkmyvibe-frontend.md +48 -0
- package/commands/checkmyvibe-payment.md +52 -0
- package/commands/checkmyvibe-secrets.md +55 -0
- package/commands/checkmyvibe.md +26 -0
- package/install.js +46 -22
- package/package.json +2 -1
- package/scripts/check_auth_patterns.py +12 -2
- package/scripts/check_db_config.py +13 -1
- package/scripts/scan_secrets.py +17 -4
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# checkmyvibe
|
|
2
2
|
|
|
3
|
-
A structured, zero-dependency, local production readiness and code quality workflow packaged as an Agent Skill for AI coding assistants
|
|
3
|
+
A structured, zero-dependency, local production readiness and code quality workflow packaged as an Agent Skill for AI coding assistants. Built for Claude Code today; the skill and command files can be adapted to other agents' rule/command formats.
|
|
4
4
|
|
|
5
5
|
AI-generated ("vibe-coded") applications built on modern AI tools frequently ship with serious, well-documented configuration and quality issues—such as exposed API keys, fake authentication stubs, permissive default database rules, and client-side pricing logic. **checkmyvibe** solves this by packaging readiness and verification checks directly into an Agent Skill. When you ask your coding agent to "run checkmyvibe" or "perform a readiness check", the agent uses checkmyvibe's local helper scripts and its own reasoning capabilities to analyze your codebase, producing a prioritized report detailing what configuration issues or gaps exist, why they matter, and how to fix them.
|
|
6
6
|
|
|
@@ -13,7 +13,7 @@ AI-generated ("vibe-coded") applications built on modern AI tools frequently shi
|
|
|
13
13
|
* **Fake & Stubbed Authentication:** Greps for common mock authentication markers (such as functions named `mockAuth`, `fakeLogin`, `tempAuth`, or logic that returns `true` unconditionally to bypass authentication checks).
|
|
14
14
|
* **Database Misconfigurations:** Identifies permissive default rules (such as `allow read, write: if true;` in Firebase/Firestore configs) and checks if Row-Level Security (RLS) is enabled on Supabase database schemas.
|
|
15
15
|
* **Broken Object-Level Authorization (BOLA/IDOR):** Analyzes API routes to check if endpoints fetch resources by ID without validating that the authenticated user owns or has permission to access that resource.
|
|
16
|
-
* **Client-Side Payment & Pricing Logic:** Scans checkout routes and payment integrations to check if prices or transaction values are calculated or accepted directly from client-side parameters rather than securely fetched on the server.
|
|
16
|
+
* **Client-Side Payment & Pricing Logic:** Scans checkout routes and payment integrations to check if prices or transaction values are calculated or accepted directly from client-side parameters rather than securely fetched on the server, and verifies that payment webhooks validate provider signatures before trusting event payloads.
|
|
17
17
|
|
|
18
18
|
---
|
|
19
19
|
|
|
@@ -42,21 +42,33 @@ If you prefer not to use `npx`, copy the files manually:
|
|
|
42
42
|
1. Create a `checkmyvibe` directory inside your agent's skills path:
|
|
43
43
|
* **Project-level (Claude Code):** `.claude/skills/checkmyvibe/`
|
|
44
44
|
* **Global/Personal (Claude Code):** `~/.claude/skills/checkmyvibe/`
|
|
45
|
-
2. Copy `SKILL.md`, the `scripts/` folder, and
|
|
45
|
+
2. Copy `SKILL.md`, the `scripts/` folder, `references/` folder, and `commands/` folder into that directory.
|
|
46
|
+
3. (Optional for slash command support) Copy the files from `commands/` directly into `.claude/commands/` (or `~/.claude/commands/`).
|
|
46
47
|
|
|
47
48
|
---
|
|
48
49
|
|
|
49
50
|
## Usage
|
|
50
51
|
|
|
51
|
-
|
|
52
|
+
### Full Production Readiness Audit
|
|
53
|
+
Run a complete audit across all categories before deploying or shipping:
|
|
54
|
+
* Command: `/checkmyvibe`
|
|
55
|
+
* Or prompt: *"Run checkmyvibe on this project"*
|
|
52
56
|
|
|
53
|
-
###
|
|
54
|
-
|
|
55
|
-
> "Run checkmyvibe on this project"
|
|
56
|
-
*Or:*
|
|
57
|
-
> "Perform a production readiness check using checkmyvibe"
|
|
57
|
+
### Focused / Scoped Scanning
|
|
58
|
+
When actively developing a specific feature, run focused scans for fast, targeted feedback without running the entire test suite:
|
|
58
59
|
|
|
59
|
-
|
|
60
|
+
| Slash Command | Scope / Keyword | Included Checks | Use Case |
|
|
61
|
+
| :--- | :--- | :--- | :--- |
|
|
62
|
+
| `/checkmyvibe-secrets` | `/checkmyvibe secrets` | Checks 1a + 1b + 2 | Server-side and client-exposed API keys/credentials, plus `.gitignore` hygiene |
|
|
63
|
+
| `/checkmyvibe-auth` | `/checkmyvibe auth` | Check 3 | Missing, mock, stubbed, or bypassed authentication guards |
|
|
64
|
+
| `/checkmyvibe-db` | `/checkmyvibe db` | Check 4 | Database & BaaS rules, Supabase RLS policies, Firebase permissions |
|
|
65
|
+
| `/checkmyvibe-backend` | `/checkmyvibe backend` | Checks 1a, 3, 4, 5, 6 (server), 7 (server) | All server-side logic: hardcoded server credentials, auth, DB/RLS, IDOR/BOLA, SQLi/input validation/mass assignment, payment & webhook processing |
|
|
66
|
+
| `/checkmyvibe-frontend` | `/checkmyvibe frontend` | Checks 1b, 3 (client), 7 (client) | Client bundle key leaks, UI-only auth hiding, client-side pricing overrides |
|
|
67
|
+
| `/checkmyvibe-payment` | `/checkmyvibe payment` | Check 7 | Client-side payment tampering, price overrides, unverified webhooks, checkout integrity |
|
|
68
|
+
|
|
69
|
+
Each scoped command file contains its complete operating instructions inline — it only falls back to `SKILL.md` for the report format and severity rubric — so scoped scans work reliably even when skill auto-discovery fails.
|
|
70
|
+
|
|
71
|
+
The agent will walk through the scoped checks, execute relevant local helper scripts, and print a prioritized markdown report (Critical / Should Fix / Worth Reviewing) with concrete remediation steps.
|
|
60
72
|
|
|
61
73
|
---
|
|
62
74
|
|
package/SKILL.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: checkmyvibe
|
|
3
3
|
description: >
|
|
4
|
-
Use this skill when the user asks to "check my vibe", run a production readiness check, review code quality, do a sanity check, check for exposed environment variables, or check if the app is ready to launch/ship
|
|
4
|
+
Use this skill when the user asks to "check my vibe", run a production readiness check, review code quality, do a sanity check, check for exposed environment variables, or check if the app is ready to launch/ship, or runs a scoped check like `/checkmyvibe db`, `/checkmyvibe auth`, `/checkmyvibe secrets`, `/checkmyvibe payment`, `/checkmyvibe backend`, or `/checkmyvibe frontend`. Also trigger proactively when the agent is about to help deploy, publish, or push an application live, or when the codebase shows signs of AI-scaffolded patterns (Supabase/Firebase config, recently generated boilerplate, auth stubs, no existing verification) and the user has not had one done yet.
|
|
5
5
|
---
|
|
6
6
|
# checkmyvibe — Production Readiness & Code Quality Check for Vibe-Coded Apps
|
|
7
7
|
|
|
@@ -27,14 +27,34 @@ expected them to hold real user data yet.
|
|
|
27
27
|
|
|
28
28
|
This is a first-pass review for known, documented scaffolding failure patterns. It is not a
|
|
29
29
|
comprehensive external validation, and it does not cover infrastructure hosting, third-party package
|
|
30
|
-
issues, or novel/business-logic-specific flaws outside the
|
|
31
|
-
below. Never tell the user their app is completely "secure" or "safe" in an unqualified way.
|
|
30
|
+
issues, or novel/business-logic-specific flaws outside the categories below. Never tell the user their app is completely "secure" or "safe" in an unqualified way.
|
|
32
31
|
The correct language is "no issues found in this pass" or "ready to ship as far as
|
|
33
32
|
these checks go" — always paired with the scope reminder in the Final Summary
|
|
34
33
|
section. If the app appears to handle payments, health data, or other regulated
|
|
35
34
|
data, say explicitly that a professional verification is strongly recommended regardless
|
|
36
35
|
of what this pass finds.
|
|
37
36
|
|
|
37
|
+
## Scope selection
|
|
38
|
+
|
|
39
|
+
checkmyvibe supports targeted/scoped scanning for rapid iteration during development, as well as full audits before release. When a specific scope or slash command is specified, execute only the mapped checks:
|
|
40
|
+
|
|
41
|
+
| Scope / Command Keyword | Included Checks | Description / Focus Area |
|
|
42
|
+
| :--- | :--- | :--- |
|
|
43
|
+
| **`secrets`** | **Check 1a + Check 1b + Check 2** | Server-side and client-exposed credentials, API keys, tokens, and `.gitignore` file protection |
|
|
44
|
+
| **`auth`** | **Check 3** | Missing, mock, stubbed, or bypassed authentication guards |
|
|
45
|
+
| **`db`** | **Check 4** | Database & BaaS rules, Supabase RLS policies, Firebase/storage permissions |
|
|
46
|
+
| **`backend`** | **Check 1a + Check 3 + Check 4 + Check 5 + Check 6 (server-side) + Check 7 (server-side)** | All server-side logic: hardcoded server credentials, auth guards, database configs, IDOR/BOLA, SQLi/input validation, mass assignment, and payment/webhook processing |
|
|
47
|
+
| **`frontend`** | **Check 1b + Check 3 (client-side view) + Check 7 (client-side view)** | Client-side bundle leaks, UI-only auth hiding, and client-controlled payment/pricing logic |
|
|
48
|
+
| **`payment`** | **Check 7** | Client-side payment amount tampering, price overrides, unverified webhooks, and checkout integrity |
|
|
49
|
+
| *(no argument / `full`)* | **All Checks (1a–7)** | Full production readiness and code quality audit |
|
|
50
|
+
|
|
51
|
+
> **Canonical definitions note:** The check definitions in this file are canonical. The scoped command files (`commands/checkmyvibe-*.md`) contain mirrored copies of their relevant checks so they can run standalone. When you change what a check does, update it here AND in every command file that mirrors it.
|
|
52
|
+
|
|
53
|
+
### Rules for Scoped Runs:
|
|
54
|
+
- **Execute only the selected checks:** Do not run unselected check scripts or inspect code outside the chosen scope.
|
|
55
|
+
- **Explicit scope transparency:** At the start and in the final summary of the report, clearly state which checks were run and which checks were skipped.
|
|
56
|
+
- **No false safety claims:** A clean scoped scan does **not** mean the app is ready for production. State clearly: *"This was a [scope]-only check. Run a full `/checkmyvibe` audit across all categories prior to launch."*
|
|
57
|
+
|
|
38
58
|
## Before you start
|
|
39
59
|
|
|
40
60
|
1. **Analyze and understand the whole project first:** Walk the directory tree and analyze the repository configuration files before running any checks, generating findings, or providing instructions. Establish a solid high-level understanding of the architecture, components, and data flow.
|
|
@@ -70,7 +90,7 @@ Critical user exposure > auth bypass > IDOR > payment logic > config issues > hy
|
|
|
70
90
|
|
|
71
91
|
The report should help the coding agent make the repo safer in the next commit, not just describe problems.
|
|
72
92
|
|
|
73
|
-
## Check
|
|
93
|
+
## Check 1a: Server-side secrets and credentials
|
|
74
94
|
|
|
75
95
|
**Run the script** `scripts/scan_secrets.py` (located relative to this `SKILL.md` file) against the project root. It flags known key
|
|
76
96
|
prefixes (`sk_live`, `sk_test`, `AIza`, `AKIA`, `ghp_`, `xox[bp]`), high-entropy
|
|
@@ -79,14 +99,13 @@ strings, and variable assignments where a name like `key`, `secret`, `token`, or
|
|
|
79
99
|
|
|
80
100
|
**What counts as a finding:**
|
|
81
101
|
|
|
82
|
-
- A real credential committed directly in source, e.g.:
|
|
83
|
-
`const stripeKey = "sk_live_51H8x..."` — Critical
|
|
84
|
-
- A
|
|
85
|
-
|
|
86
|
-
- A
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
Critical, this is directly shippable to every visitor's browser
|
|
102
|
+
- A real credential committed directly in server-side source, e.g.:
|
|
103
|
+
`const stripeKey = "sk_live_51H8x..."` — **Critical**
|
|
104
|
+
- A **live** Stripe secret key (`sk_live_...`) anywhere in source — **Critical**, charges real cards
|
|
105
|
+
- A **test** Stripe secret key (`sk_test_...`) committed in source — **Should Fix**, not production-critical but test keys still must not be committed; rotate if the repo has ever been shared
|
|
106
|
+
- A server-only credential referenced in frontend code, or a Next.js env var
|
|
107
|
+
missing the required server-only scoping (using a secret key where only
|
|
108
|
+
`NEXT_PUBLIC_`-prefixed vars should appear) — **Critical**, this is directly shippable to every visitor's browser
|
|
90
109
|
|
|
91
110
|
**What is NOT a finding (avoid false positives):**
|
|
92
111
|
|
|
@@ -96,6 +115,20 @@ strings, and variable assignments where a name like `key`, `secret`, `token`, or
|
|
|
96
115
|
configured. Note this distinction explicitly in the report so the user isn't
|
|
97
116
|
confused about why one key is fine and another isn't.
|
|
98
117
|
- Example/placeholder values clearly meant as documentation, e.g. `"your-api-key-here"`
|
|
118
|
+
- Fake credentials inside unit tests, fixtures, or mock files (the scripts already skip these directories; if you find one manually, do not report it)
|
|
119
|
+
|
|
120
|
+
## Check 1b: Client-exposed secrets (frontend scope view)
|
|
121
|
+
|
|
122
|
+
This is the client-facing slice of Check 1a, used by the `frontend` scope. Focus on:
|
|
123
|
+
|
|
124
|
+
- Secrets reachable from the client bundle: any secret referenced in frontend
|
|
125
|
+
code, anything passed through `NEXT_PUBLIC_*` / `VITE_*` / `REACT_APP_*` env
|
|
126
|
+
vars that isn't genuinely public, and secrets inlined in client config files.
|
|
127
|
+
- Service-role keys (Supabase `service_role`, Firebase admin SDK private keys,
|
|
128
|
+
OpenAI/Stripe secret keys) appearing anywhere under `src/`, `app/`,
|
|
129
|
+
`components/`, `public/`, or client entry points — **Critical**.
|
|
130
|
+
|
|
131
|
+
The severity rules and false-positive guidance from Check 1a apply unchanged.
|
|
99
132
|
|
|
100
133
|
## Check 2: .gitignore hygiene
|
|
101
134
|
|
|
@@ -213,6 +246,14 @@ Spot-check forms and API endpoints for:
|
|
|
213
246
|
- User input rendered into HTML without escaping (XSS risk), especially in
|
|
214
247
|
frameworks that don't auto-escape by default
|
|
215
248
|
- File uploads with no restriction on file type or size
|
|
249
|
+
- **Mass assignment:** request bodies spread directly into ORM create/update calls,
|
|
250
|
+
e.g. `await prisma.user.update({ where: { id }, data: req.body })` — lets a user
|
|
251
|
+
set fields they should never control (`role`, `plan`, `isAdmin`, `emailVerified`).
|
|
252
|
+
Flag when the body is not explicitly whitelisted to safe fields. — Critical if a
|
|
253
|
+
privileged field can be set, otherwise Should Fix
|
|
254
|
+
- **No rate limiting on auth endpoints:** login, signup, password reset, and OTP
|
|
255
|
+
endpoints with no throttle/attempt limit allow credential stuffing and SMS-cost
|
|
256
|
+
abuse — Worth Reviewing at minimum, Should Fix for payment-handling apps
|
|
216
257
|
|
|
217
258
|
This check doesn't need to be exhaustive — flag the clearest, highest-impact
|
|
218
259
|
examples rather than every single form field, and note in the summary that a
|
|
@@ -239,6 +280,30 @@ app.post('/api/checkout', async (req, res) => {
|
|
|
239
280
|
});
|
|
240
281
|
```
|
|
241
282
|
|
|
283
|
+
Also check **payment webhook signature verification** — this is the sibling flaw to
|
|
284
|
+
client-side pricing and just as common:
|
|
285
|
+
|
|
286
|
+
- A webhook endpoint (Stripe, Firebase, PayPal, Razorpay) that reads the event body
|
|
287
|
+
and acts on it **without verifying the signature first**. Anyone who finds the URL
|
|
288
|
+
can POST `{ "type": "payment_intent.succeeded", ... }` and get their order marked paid.
|
|
289
|
+
- Correct pattern (Express + Stripe):
|
|
290
|
+
```js
|
|
291
|
+
app.post('/api/webhooks/stripe',
|
|
292
|
+
express.raw({ type: 'application/json' }), // raw body required for signature check
|
|
293
|
+
(req, res) => {
|
|
294
|
+
const event = stripe.webhooks.constructEvent(
|
|
295
|
+
req.body, req.headers['stripe-signature'], process.env.STRIPE_WEBHOOK_SECRET
|
|
296
|
+
);
|
|
297
|
+
// only now is the event trustworthy
|
|
298
|
+
});
|
|
299
|
+
```
|
|
300
|
+
- Equivalent checks: Firebase Cloud Functions `onRequest` deployed with secret
|
|
301
|
+
headers compared server-side, PayPal webhook `verify-webhook-signature` API,
|
|
302
|
+
Razorpay `verifyPaymentSignature`. If a webhook route exists and no signature
|
|
303
|
+
verification call exists anywhere in the flow — **Critical**.
|
|
304
|
+
- Discount/coupon values accepted from the client rather than looked up from a
|
|
305
|
+
trusted source server-side — same severity as price tampering.
|
|
306
|
+
|
|
242
307
|
---
|
|
243
308
|
|
|
244
309
|
## Severity rubric
|
|
@@ -285,6 +350,8 @@ Once the checks are complete, create a readiness review report. **The report mus
|
|
|
285
350
|
- what still needs attention
|
|
286
351
|
- the final readiness verdict
|
|
287
352
|
|
|
353
|
+
**Post-fix verification:** if you applied fixes during this session, re-run the scripts for every category you touched and confirm the finding is actually gone before marking it fixed in the report. Report before/after per check (e.g. "scan_secrets.py: 3 findings → 0 findings"). A fix that hasn't been re-scanned must be listed as "applied, not yet verified", never as resolved.
|
|
354
|
+
|
|
288
355
|
If no issues are found, still produce a short report that says no blocking issues were found in this pass, which categories were checked, and what the remaining scope limits are.
|
|
289
356
|
|
|
290
357
|
## Example report style
|
|
@@ -306,11 +373,9 @@ End every review with, in this order:
|
|
|
306
373
|
2. Total findings by severity, e.g. "2 Critical, 3 Should Fix, 1 Worth Reviewing"
|
|
307
374
|
3. A one-line verdict: "Not ready to ship — fix the Critical items first" or "No
|
|
308
375
|
blocking issues found in this pass — review the Should Fix items when you can"
|
|
309
|
-
4. The scope reminder:
|
|
310
|
-
exposed secrets, auth stubs, database rules, object-level authorization, input validation,
|
|
311
|
-
|
|
312
|
-
handles payment, health, or other regulated data, get a professional external review
|
|
313
|
-
before launch regardless of these results."
|
|
376
|
+
4. The scope reminder:
|
|
377
|
+
- **For Full Audit:** "This review covers common configuration patterns seen in AI-generated code — exposed secrets, auth stubs, database rules, object-level authorization, input validation, and client-side payment logic. It is not a comprehensive third-party safety audit or pentest. If this app handles payment, health, or other regulated data, get a professional external review before launch regardless of these results."
|
|
378
|
+
- **For Scoped Scan:** "This was a focused [SCOPE]-only check ([LIST OF RUN CHECKS]). Skipped checks: [LIST OF SKIPPED CHECKS]. A clean scoped check does not mean the application is production-ready. Always run a full `/checkmyvibe` audit prior to release, and obtain a professional external security review if handling sensitive or regulated data."
|
|
314
379
|
|
|
315
380
|
## Notes for the agent
|
|
316
381
|
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# /checkmyvibe-auth — Missing or fake authentication
|
|
2
|
+
|
|
3
|
+
First, locate the checkmyvibe skill file `SKILL.md`. Check these paths in order:
|
|
4
|
+
|
|
5
|
+
1. `.claude/skills/checkmyvibe/SKILL.md` (project-level install)
|
|
6
|
+
2. `~/.claude/skills/checkmyvibe/SKILL.md` (global install)
|
|
7
|
+
3. If neither exists, search the working directory for a file named `SKILL.md` whose frontmatter contains `name: checkmyvibe`
|
|
8
|
+
|
|
9
|
+
Use SKILL.md **only** for the report format, severity rubric, and final-summary structure. The complete operating instructions for this scope are below — follow them even if SKILL.md cannot be found.
|
|
10
|
+
|
|
11
|
+
**Optional argument:** a target directory may be passed after the command. Default to the project root if not given. Scripts live in the `scripts/` folder next to SKILL.md.
|
|
12
|
+
|
|
13
|
+
## Scope
|
|
14
|
+
|
|
15
|
+
This is an **authentication-only check** (Check 3). Checks 1a/1b, 2, 4, 5, 6, and 7 are skipped and must be listed as skipped in the final summary.
|
|
16
|
+
|
|
17
|
+
## Step 1 — Run the first-pass script
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
python <skill_dir>/scripts/check_auth_patterns.py <target>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
It flags stub names (`mockAuth`, `fakeLogin`, `tempAuth`, `bypassAuth`, ...) and always-true auth functions. If Python is unavailable or it fails, say so and do the equivalent greps manually. The script skips test directories — do not report mock auth inside unit tests even if you see it manually.
|
|
24
|
+
|
|
25
|
+
## Step 2 — Manual reasoning pass (this is where the real findings are)
|
|
26
|
+
|
|
27
|
+
The script is a first pass only. Read the actual auth code: login handlers, middleware, route guards, session checks, and every route that returns or modifies user-specific data.
|
|
28
|
+
|
|
29
|
+
Findings to hunt for:
|
|
30
|
+
|
|
31
|
+
- **Always-true stubs:** `function isAuthenticated() { return true; }`, `const checkAdmin = () => true` — Critical.
|
|
32
|
+
- **Stub-named helpers still wired in:** `mockAuth`, `devAuth`, `bypassAuth` reachable in production paths — Critical. Properly guarded behind `NODE_ENV === 'development'` → Should Fix (env misconfig leaks these constantly); verify the guard actually covers every import/call site.
|
|
33
|
+
- **Protected routes with no auth check at all:** list every route returning user-specific data, then check each one calls the session/auth middleware. A `/api/orders/:id` with no guard is Critical regardless of what the UI does.
|
|
34
|
+
- **Client-side-only enforcement:** UI hides a button/route for logged-out users but the underlying API never verifies the session — Critical. Anyone calls the API directly. To confirm this you MUST read the corresponding server route; do not clear a finding from the frontend alone.
|
|
35
|
+
- **Commented-out auth checks** with an active bypass nearby.
|
|
36
|
+
- **JWT/session verification gaps:** tokens decoded but not verified (`jwt.decode` instead of `jwt.verify`, no algorithm pinning), sessions accepted from client-controlled storage without server validation — Critical.
|
|
37
|
+
|
|
38
|
+
## Step 3 — Judgment rules
|
|
39
|
+
|
|
40
|
+
- Read the function body fully before flagging or clearing — never decide from the name alone.
|
|
41
|
+
- 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 (NextAuth, Clerk, Supabase Auth, custom JWT) first; "missing" means missing relative to how routes access user data, not absence of a specific library.
|
|
43
|
+
|
|
44
|
+
## Report
|
|
45
|
+
|
|
46
|
+
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."
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# /checkmyvibe-backend — Server-side audit
|
|
2
|
+
|
|
3
|
+
First, locate the checkmyvibe skill file `SKILL.md`. Check these paths in order:
|
|
4
|
+
|
|
5
|
+
1. `.claude/skills/checkmyvibe/SKILL.md` (project-level install)
|
|
6
|
+
2. `~/.claude/skills/checkmyvibe/SKILL.md` (global install)
|
|
7
|
+
3. If neither exists, search the working directory for a file named `SKILL.md` whose frontmatter contains `name: checkmyvibe`
|
|
8
|
+
|
|
9
|
+
Use SKILL.md **only** for the report format, severity rubric, and final-summary structure. The complete operating instructions for this scope are below — follow them even if SKILL.md cannot be found.
|
|
10
|
+
|
|
11
|
+
**Optional argument:** a target directory may be passed after the command. Default to the project root if not given. Scripts live in the `scripts/` folder next to SKILL.md.
|
|
12
|
+
|
|
13
|
+
## Scope
|
|
14
|
+
|
|
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
|
+
|
|
17
|
+
## Step 1 — Run all three scripts
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
python <skill_dir>/scripts/scan_secrets.py <target>
|
|
21
|
+
python <skill_dir>/scripts/check_auth_patterns.py <target>
|
|
22
|
+
python <skill_dir>/scripts/check_db_config.py <target>
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Triage per the rules in `/checkmyvibe-secrets`, `/checkmyvibe-auth`, and `/checkmyvibe-db` respectively: live keys Critical / test keys Should Fix; mock-auth hits outside tests need manual reading; missing RLS and `USING (true)` policies are Critical on user-data tables. If Python is unavailable, do each check manually and say so in the report.
|
|
26
|
+
|
|
27
|
+
## Step 2 — IDOR sweep (Check 5 — spend the most time here)
|
|
28
|
+
|
|
29
|
+
This is the single most common serious flaw in AI-generated apps. Enumerate every route that takes an ID (URL param, query string, or body field) and touches a database record:
|
|
30
|
+
|
|
31
|
+
```js
|
|
32
|
+
// Finding example — Critical: any logged-in user reads ANY order
|
|
33
|
+
app.get('/api/orders/:id', requireAuth, async (req, res) => {
|
|
34
|
+
const order = await db.query('SELECT * FROM orders WHERE id = $1', [req.params.id]);
|
|
35
|
+
res.json(order);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// Correct fix pattern: scope by owner, return 404 when absent
|
|
39
|
+
const order = await db.query(
|
|
40
|
+
'SELECT * FROM orders WHERE id = $1 AND user_id = $2', [req.params.id, req.user.id]);
|
|
41
|
+
if (!order) return res.status(404).json({ error: 'Not found' });
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Check GET (exposure), PUT/PATCH (unauthorized modification), and DELETE (often most damaging) for all of them. An auth guard alone is not enough — ownership must be enforced in the query or immediately after fetch.
|
|
45
|
+
|
|
46
|
+
## Step 3 — Server-side input handling (Check 6)
|
|
47
|
+
|
|
48
|
+
- SQL built by string concatenation instead of parameterized queries/ORM → Critical.
|
|
49
|
+
- **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.
|
|
50
|
+
- Unescaped user input into HTML in non-auto-escaping frameworks → flag worst cases.
|
|
51
|
+
- Login/signup/password-reset/OTP endpoints with no rate limiting → Should Fix for payment-handling apps, Worth Reviewing otherwise.
|
|
52
|
+
- File uploads with no type/size restriction.
|
|
53
|
+
|
|
54
|
+
## Step 4 — Payment processing & webhooks (Check 7, server side)
|
|
55
|
+
|
|
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:** every payment webhook route (Stripe, PayPal, Razorpay, Firebase) must verify the signature before trusting the body — e.g. Stripe's `stripe.webhooks.constructEvent(rawBody, sigHeader, webhookSecret)` with the raw body. A webhook route with no signature verification anywhere in its flow → Critical: anyone can POST "payment succeeded" and get their order marked paid.
|
|
58
|
+
- Webhook handlers acting on unverified amounts read from the event body → same severity.
|
|
59
|
+
|
|
60
|
+
## Report
|
|
61
|
+
|
|
62
|
+
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."
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# /checkmyvibe-db — Database & BaaS misconfiguration
|
|
2
|
+
|
|
3
|
+
First, locate the checkmyvibe skill file `SKILL.md`. Check these paths in order:
|
|
4
|
+
|
|
5
|
+
1. `.claude/skills/checkmyvibe/SKILL.md` (project-level install)
|
|
6
|
+
2. `~/.claude/skills/checkmyvibe/SKILL.md` (global install)
|
|
7
|
+
3. If neither exists, search the working directory for a file named `SKILL.md` whose frontmatter contains `name: checkmyvibe`
|
|
8
|
+
|
|
9
|
+
Use SKILL.md **only** for the report format, severity rubric, and final-summary structure. The complete operating instructions for this scope are below — follow them even if SKILL.md cannot be found.
|
|
10
|
+
|
|
11
|
+
**Optional argument:** a target directory may be passed after the command. Default to the project root if not given. Scripts live in the `scripts/` folder next to SKILL.md.
|
|
12
|
+
|
|
13
|
+
## Scope
|
|
14
|
+
|
|
15
|
+
This is a **database-only check** (Check 4). Checks 1a/1b, 2, 3, 5, 6, and 7 are skipped and must be listed as skipped in the final summary.
|
|
16
|
+
|
|
17
|
+
## Step 1 — Run the first-pass script
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
python <skill_dir>/scripts/check_db_config.py <target>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
It scans SQL files for tables created without RLS and permissive policies (`USING (true)` / `WITH CHECK (true)`), Firestore/storage rules for `allow ...: if true`, and Realtime Database rules set to `"true"`. If Python is unavailable or it fails, do the equivalent checks by reading schema/rules files manually and say so in the report.
|
|
24
|
+
|
|
25
|
+
## Step 2 — Supabase (if used)
|
|
26
|
+
|
|
27
|
+
- Every table holding user-specific data must have `ENABLE ROW LEVEL SECURITY`. A table without it → Critical.
|
|
28
|
+
- Policies granting broad access fail: `FOR SELECT USING (true)`, policies `TO public/anon` with unconditional USING/CHECK → Critical.
|
|
29
|
+
- Recommended fix pattern:
|
|
30
|
+
```sql
|
|
31
|
+
CREATE POLICY "users see own orders" ON orders
|
|
32
|
+
FOR SELECT USING (auth.uid() = user_id);
|
|
33
|
+
```
|
|
34
|
+
- Check migrations/schema files under `supabase/migrations/`, `db/`, or wherever `.sql` files live. Also confirm RLS wasn't enabled *after* data was already readable via the anon key in earlier deployments.
|
|
35
|
+
|
|
36
|
+
## Step 3 — Firebase (if used)
|
|
37
|
+
|
|
38
|
+
- `firestore.rules`: any `allow read, write: if true;` on collections holding user data → Critical. Test-mode rules (`allow read, write: if <timestamp>`) pasted into prod-like configs → Should Fix minimum.
|
|
39
|
+
- `database.rules.json` (Realtime DB): `".read": "true"` / `".write": "true"` on user-data nodes → Critical.
|
|
40
|
+
- Rules files present but clearly unused/default → Worth Reviewing; verify which project they deploy to.
|
|
41
|
+
|
|
42
|
+
## Step 4 — Storage buckets
|
|
43
|
+
|
|
44
|
+
Supabase Storage, Firebase Storage, S3:
|
|
45
|
+
|
|
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.
|
|
48
|
+
|
|
49
|
+
## Report
|
|
50
|
+
|
|
51
|
+
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."
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# /checkmyvibe-frontend — Client-side audit
|
|
2
|
+
|
|
3
|
+
First, locate the checkmyvibe skill file `SKILL.md`. Check these paths in order:
|
|
4
|
+
|
|
5
|
+
1. `.claude/skills/checkmyvibe/SKILL.md` (project-level install)
|
|
6
|
+
2. `~/.claude/skills/checkmyvibe/SKILL.md` (global install)
|
|
7
|
+
3. If neither exists, search the working directory for a file named `SKILL.md` whose frontmatter contains `name: checkmyvibe`
|
|
8
|
+
|
|
9
|
+
Use SKILL.md **only** for the report format, severity rubric, and final-summary structure. The complete operating instructions for this scope are below — follow them even if SKILL.md cannot be found.
|
|
10
|
+
|
|
11
|
+
**Optional argument:** a target directory may be passed after the command. Default to the project root if not given. Scripts live in the `scripts/` folder next to SKILL.md.
|
|
12
|
+
|
|
13
|
+
## Scope
|
|
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 of auth/input/payment.
|
|
16
|
+
|
|
17
|
+
## Step 1 — Client-exposed secrets (run script, then manual pass)
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
python <skill_dir>/scripts/scan_secrets.py <target>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Then manually inspect everything reachable from the browser:
|
|
24
|
+
|
|
25
|
+
- Framework env prefixes bundle values INTO shipped JS: `NEXT_PUBLIC_*`, `VITE_*`, `REACT_APP_*`, `EXPO_PUBLIC_*`. Any secret behind one of these → Critical.
|
|
26
|
+
- Supabase `service_role` key, Firebase admin SDK JSON, OpenAI/Stripe secret keys anywhere under `src/`, `app/`, `components/`, `pages/`, `public/`, or client entry files → Critical.
|
|
27
|
+
- Publishable keys (`pk_`, Supabase anon key, Firebase web config `apiKey`) are public-by-design → NOT findings; say so explicitly so the report isn't confusing.
|
|
28
|
+
- Placeholders and test-fixture values → not findings.
|
|
29
|
+
|
|
30
|
+
## Step 2 — UI-only auth enforcement (Check 3, client view)
|
|
31
|
+
|
|
32
|
+
Find every place the UI gates access: redirects on protected pages, hidden nav items, disabled buttons, client route guards:
|
|
33
|
+
|
|
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 calls the API directly").
|
|
35
|
+
- Auth state trusted purely from client storage (localStorage JWT, global store) to protect data → Critical if no server verification exists.
|
|
36
|
+
- You must read the server routes to clear or confirm findings — a clean-looking frontend proves nothing on its own.
|
|
37
|
+
|
|
38
|
+
## Step 3 — Client-controlled pricing (Check 7, client view)
|
|
39
|
+
|
|
40
|
+
Inspect checkout/cart/pricing flows:
|
|
41
|
+
|
|
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.
|
|
43
|
+
- Coupon codes validated only in the UI → flag the endpoint that accepts them without server-side validation.
|
|
44
|
+
- Note exactly which server endpoint accepts the tainted value so the backend fix is obvious.
|
|
45
|
+
|
|
46
|
+
## Report
|
|
47
|
+
|
|
48
|
+
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."
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# /checkmyvibe-payment — Payment & pricing integrity
|
|
2
|
+
|
|
3
|
+
First, locate the checkmyvibe skill file `SKILL.md`. Check these paths in order:
|
|
4
|
+
|
|
5
|
+
1. `.claude/skills/checkmyvibe/SKILL.md` (project-level install)
|
|
6
|
+
2. `~/.claude/skills/checkmyvibe/SKILL.md` (global install)
|
|
7
|
+
3. If neither exists, search the working directory for a file named `SKILL.md` whose frontmatter contains `name: checkmyvibe`
|
|
8
|
+
|
|
9
|
+
Use SKILL.md **only** for the report format, severity rubric, and final-summary structure. The complete operating instructions for this scope are below — follow them even if SKILL.md cannot be found.
|
|
10
|
+
|
|
11
|
+
**Optional argument:** a target directory may be passed after the command. Default to the project root if not given. Scripts live in the `scripts/` folder next to SKILL.md.
|
|
12
|
+
|
|
13
|
+
## Scope
|
|
14
|
+
|
|
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
|
+
|
|
17
|
+
## Step 1 — Map the payment surface
|
|
18
|
+
|
|
19
|
+
Identify the provider (Stripe, PayPal, Razorpay, Firebase-based, custom) and locate: checkout endpoints, webhook routes, cart/price calculation code (client and server), subscription/plan management, and coupon/discount handling. If there is no payment code at all, report "No issues found — no payment flow exists" and stop.
|
|
20
|
+
|
|
21
|
+
## Step 2 — Server-side price trust
|
|
22
|
+
|
|
23
|
+
For each chargeable action:
|
|
24
|
+
|
|
25
|
+
- Is the amount read from the request (body field, query param, hidden form field) or computed from client-supplied data? → Critical:
|
|
26
|
+
```js
|
|
27
|
+
// Finding example — Critical
|
|
28
|
+
const { productId, price } = req.body;
|
|
29
|
+
await chargeCard(req.user.paymentMethod, price);
|
|
30
|
+
|
|
31
|
+
// Correct fix pattern — server looks up the price
|
|
32
|
+
const { productId } = req.body;
|
|
33
|
+
const product = await db.query('SELECT price FROM products WHERE id = $1', [productId]);
|
|
34
|
+
await chargeCard(req.user.paymentMethod, product.price);
|
|
35
|
+
```
|
|
36
|
+
- Quantities, currency, plan tiers, or seat counts accepted from the client and multiplied into totals without server-side lookup → same severity.
|
|
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).
|
|
39
|
+
|
|
40
|
+
## Step 3 — Webhook signature verification (most-missed check)
|
|
41
|
+
|
|
42
|
+
Every payment webhook route must verify authenticity BEFORE trusting or acting on its body:
|
|
43
|
+
|
|
44
|
+
- Stripe: `stripe.webhooks.constructEvent(rawBody, sigHeader, process.env.STRIPE_WEBHOOK_SECRET)` with `express.raw({ type: 'application/json' })` on the route. No signature verification anywhere in the handler chain → Critical: anyone who finds the URL can POST a fake `payment_intent.succeeded` and get orders marked paid for free.
|
|
45
|
+
- PayPal: `verify-webhook-signature` API call missing → Critical.
|
|
46
|
+
- Razorpay: missing `verifyPaymentSignature` / HMAC comparison → Critical.
|
|
47
|
+
- Firebase/custom webhooks: no shared-secret header compared server-side → Critical.
|
|
48
|
+
- Also flag webhook handlers that fulfill orders based on amounts read from the unverified event payload instead of re-fetching them server-side.
|
|
49
|
+
|
|
50
|
+
## Report
|
|
51
|
+
|
|
52
|
+
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."
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# /checkmyvibe-secrets — Exposed secrets & .gitignore hygiene
|
|
2
|
+
|
|
3
|
+
First, locate the checkmyvibe skill file `SKILL.md`. Check these paths in order:
|
|
4
|
+
|
|
5
|
+
1. `.claude/skills/checkmyvibe/SKILL.md` (project-level install)
|
|
6
|
+
2. `~/.claude/skills/checkmyvibe/SKILL.md` (global install)
|
|
7
|
+
3. If neither exists, search the working directory for a file named `SKILL.md` whose frontmatter contains `name: checkmyvibe`
|
|
8
|
+
|
|
9
|
+
Use SKILL.md **only** for the report format, severity rubric, and final-summary structure. The complete operating instructions for this scope are below — follow them even if SKILL.md cannot be found.
|
|
10
|
+
|
|
11
|
+
**Optional argument:** a target directory may be passed after the command. Default to the project root if not given. Scripts live in the `scripts/` folder next to SKILL.md.
|
|
12
|
+
|
|
13
|
+
## Scope
|
|
14
|
+
|
|
15
|
+
This is a **secrets-only check**: Check 1a (server-side secrets) + Check 1b (client-exposed secrets) + Check 2 (.gitignore hygiene). Checks 3–7 are skipped and must be listed as skipped in the final summary.
|
|
16
|
+
|
|
17
|
+
## Step 1 — Run both scripts
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
python <skill_dir>/scripts/scan_secrets.py <target>
|
|
21
|
+
python <skill_dir>/scripts/check_gitignore.py <target>
|
|
22
|
+
```
|
|
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`.
|
|
25
|
+
|
|
26
|
+
## Step 2 — Triage every script finding
|
|
27
|
+
|
|
28
|
+
The scripts over-match on purpose. For each hit, open the file and decide:
|
|
29
|
+
|
|
30
|
+
- **Live Stripe key (`sk_live_...`)** → Critical. Charges real cards. Recommend immediate rotation at dashboard.stripe.com, not just deletion.
|
|
31
|
+
- **Test Stripe key (`sk_test_...`) in source** → Should Fix. Not production-critical but must not be committed; rotate if the repo was ever shared/pushed publicly.
|
|
32
|
+
- **AWS `AKIA`, Google `AIza`, GitHub `ghp_`, Slack tokens in source** → Critical. Recommend revoking at the provider console.
|
|
33
|
+
- **Publishable keys (`pk_live`, `pk_test`, Supabase anon keys, Firebase apiKey config)** → NOT findings. These are public-by-design; say so in one line so the user isn't confused.
|
|
34
|
+
- **Placeholders** (`your-api-key-here`, `<secret>`, dummy values) → not findings.
|
|
35
|
+
- Anything inside test/fixture/mock directories → not findings (the scripts already skip these).
|
|
36
|
+
|
|
37
|
+
## Step 3 — Client-exposure pass (Check 1b)
|
|
38
|
+
|
|
39
|
+
Manually verify secrets aren't reachable from the browser:
|
|
40
|
+
|
|
41
|
+
- 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: any secret used outside a server-only context, or a secret var incorrectly prefixed with `NEXT_PUBLIC_`. In Vite/CRA: secrets behind `VITE_*` / `REACT_APP_*` get bundled into shipped JS — Critical.
|
|
43
|
+
- Supabase `service_role` key, Firebase admin SDK private key JSON, OpenAI/Stripe secret keys appearing anywhere client-reachable → Critical.
|
|
44
|
+
|
|
45
|
+
## Step 4 — .gitignore hygiene (Check 2)
|
|
46
|
+
|
|
47
|
+
From `check_gitignore.py` output plus manual review:
|
|
48
|
+
|
|
49
|
+
- `.env` / `.env.local` present but not ignored → Critical regardless of contents.
|
|
50
|
+
- No `.gitignore` at all with secret files present → Critical.
|
|
51
|
+
- 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 history stays recoverable.
|
|
52
|
+
|
|
53
|
+
## Report
|
|
54
|
+
|
|
55
|
+
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."
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# /checkmyvibe — Full production readiness audit
|
|
2
|
+
|
|
3
|
+
First, locate the checkmyvibe skill file `SKILL.md`. Check these paths in order:
|
|
4
|
+
|
|
5
|
+
1. `.claude/skills/checkmyvibe/SKILL.md` (project-level install)
|
|
6
|
+
2. `~/.claude/skills/checkmyvibe/SKILL.md` (global install)
|
|
7
|
+
3. If neither exists, search the working directory for a file named `SKILL.md` whose frontmatter contains `name: checkmyvibe`
|
|
8
|
+
|
|
9
|
+
If it still cannot be found, tell the user and stop — do not improvise an audit without the skill definitions.
|
|
10
|
+
|
|
11
|
+
**Optional argument:** a target directory may be passed after the command (e.g. `/checkmyvibe src/`). Default to the project root if not given.
|
|
12
|
+
|
|
13
|
+
Then read `SKILL.md` in full and run the **complete audit: Checks 1a, 1b, 2, 3, 4, 5, 6, and 7**:
|
|
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 / BaaS misconfiguration (Supabase RLS, Firebase rules, storage)
|
|
20
|
+
- Check 5 — broken object-level authorization (IDOR/BOLA), route by route
|
|
21
|
+
- Check 6 — unvalidated inputs, SQLi/XSS risk, mass assignment, missing rate limiting on auth endpoints
|
|
22
|
+
- Check 7 — client-side payment/pricing logic AND webhook signature verification
|
|
23
|
+
|
|
24
|
+
Run every script in the skill's `scripts/` folder that maps to Checks 1–4 (`scan_secrets.py`, `check_gitignore.py`, `check_auth_patterns.py`, `check_db_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
|
+
Use the report format, severity rubric, evidence/confidence rules, post-fix verification step, and full-audit final summary structure defined in `SKILL.md`.
|
package/install.js
CHANGED
|
@@ -9,13 +9,17 @@ const readline = require('readline');
|
|
|
9
9
|
const srcSkill = path.join(__dirname, 'SKILL.md');
|
|
10
10
|
const srcScripts = path.join(__dirname, 'scripts');
|
|
11
11
|
const srcReferences = path.join(__dirname, 'references');
|
|
12
|
+
const srcCommands = path.join(__dirname, 'commands');
|
|
12
13
|
|
|
13
14
|
// Destination selection
|
|
14
15
|
const cwd = process.cwd();
|
|
15
16
|
const hasLocalClaude = fs.existsSync(path.join(cwd, '.claude'));
|
|
16
17
|
|
|
17
|
-
const
|
|
18
|
-
const
|
|
18
|
+
const localSkillDest = path.join(cwd, '.claude', 'skills', 'checkmyvibe');
|
|
19
|
+
const localCommandsDest = path.join(cwd, '.claude', 'commands');
|
|
20
|
+
|
|
21
|
+
const globalSkillDest = path.join(os.homedir(), '.claude', 'skills', 'checkmyvibe');
|
|
22
|
+
const globalCommandsDest = path.join(os.homedir(), '.claude', 'commands');
|
|
19
23
|
|
|
20
24
|
function copyRecursiveSync(src, dest) {
|
|
21
25
|
if (fs.statSync(src).isDirectory()) {
|
|
@@ -28,34 +32,54 @@ function copyRecursiveSync(src, dest) {
|
|
|
28
32
|
}
|
|
29
33
|
}
|
|
30
34
|
|
|
31
|
-
function performInstall(
|
|
35
|
+
function performInstall(skillDest, commandsDest) {
|
|
32
36
|
try {
|
|
33
|
-
console.log(`\nInstalling checkmyvibe to: ${
|
|
37
|
+
console.log(`\nInstalling checkmyvibe skill to: ${skillDest}...`);
|
|
34
38
|
|
|
35
|
-
// Clear destination if it already exists (overwrite mode)
|
|
36
|
-
if (fs.existsSync(
|
|
39
|
+
// Clear skill destination if it already exists (overwrite mode)
|
|
40
|
+
if (fs.existsSync(skillDest)) {
|
|
37
41
|
if (fs.rmSync) {
|
|
38
|
-
fs.rmSync(
|
|
42
|
+
fs.rmSync(skillDest, { recursive: true, force: true });
|
|
39
43
|
} else {
|
|
40
|
-
fs.rmdirSync(
|
|
44
|
+
fs.rmdirSync(skillDest, { recursive: true });
|
|
41
45
|
}
|
|
42
46
|
}
|
|
43
|
-
fs.mkdirSync(
|
|
47
|
+
fs.mkdirSync(skillDest, { recursive: true });
|
|
44
48
|
|
|
45
49
|
// Copy SKILL.md
|
|
46
|
-
fs.copyFileSync(srcSkill, path.join(
|
|
50
|
+
fs.copyFileSync(srcSkill, path.join(skillDest, 'SKILL.md'));
|
|
47
51
|
|
|
48
|
-
// Copy folders
|
|
49
|
-
copyRecursiveSync(srcScripts, path.join(
|
|
50
|
-
copyRecursiveSync(srcReferences, path.join(
|
|
52
|
+
// Copy folders into skill destination
|
|
53
|
+
copyRecursiveSync(srcScripts, path.join(skillDest, 'scripts'));
|
|
54
|
+
copyRecursiveSync(srcReferences, path.join(skillDest, 'references'));
|
|
55
|
+
if (fs.existsSync(srcCommands)) {
|
|
56
|
+
copyRecursiveSync(srcCommands, path.join(skillDest, 'commands'));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Install slash commands into agent commands directory
|
|
60
|
+
if (fs.existsSync(srcCommands)) {
|
|
61
|
+
console.log(`Installing slash commands to: ${commandsDest}...`);
|
|
62
|
+
fs.mkdirSync(commandsDest, { recursive: true });
|
|
63
|
+
fs.readdirSync(srcCommands).forEach((cmdFile) => {
|
|
64
|
+
if (cmdFile.endsWith('.md')) {
|
|
65
|
+
fs.copyFileSync(path.join(srcCommands, cmdFile), path.join(commandsDest, cmdFile));
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
}
|
|
51
69
|
|
|
52
70
|
console.log('\n=========================================');
|
|
53
|
-
console.log('🎉 checkmyvibe Agent Skill installed!');
|
|
71
|
+
console.log('🎉 checkmyvibe Agent Skill & Commands installed!');
|
|
54
72
|
console.log('=========================================');
|
|
55
73
|
console.log('\nHow to run checkmyvibe:');
|
|
56
|
-
console.log('
|
|
57
|
-
console.log('
|
|
58
|
-
console.log('
|
|
74
|
+
console.log('• Full Audit:');
|
|
75
|
+
console.log(' /checkmyvibe or "run checkmyvibe"');
|
|
76
|
+
console.log('\n• Focused / Scoped Scans:');
|
|
77
|
+
console.log(' /checkmyvibe secrets (or /checkmyvibe-secrets) -> Exposed secrets & .gitignore');
|
|
78
|
+
console.log(' /checkmyvibe auth (or /checkmyvibe-auth) -> Authentication checks');
|
|
79
|
+
console.log(' /checkmyvibe db (or /checkmyvibe-db) -> Database & BaaS rules / RLS');
|
|
80
|
+
console.log(' /checkmyvibe backend (or /checkmyvibe-backend) -> Server-side (auth, db, IDOR, input, payment)');
|
|
81
|
+
console.log(' /checkmyvibe frontend (or /checkmyvibe-frontend) -> Client-side (bundle leaks, client auth, pricing)');
|
|
82
|
+
console.log(' /checkmyvibe payment (or /checkmyvibe-payment) -> Payment & pricing integrity');
|
|
59
83
|
console.log('=========================================\n');
|
|
60
84
|
} catch (err) {
|
|
61
85
|
console.error('Error installing skill:', err.message);
|
|
@@ -65,7 +89,7 @@ function performInstall(destPath) {
|
|
|
65
89
|
|
|
66
90
|
if (hasLocalClaude) {
|
|
67
91
|
// If .claude folder exists in the project root, install at project level directly
|
|
68
|
-
performInstall(
|
|
92
|
+
performInstall(localSkillDest, localCommandsDest);
|
|
69
93
|
} else {
|
|
70
94
|
// Prompt user for local vs global/personal installation
|
|
71
95
|
const rl = readline.createInterface({
|
|
@@ -74,16 +98,16 @@ if (hasLocalClaude) {
|
|
|
74
98
|
});
|
|
75
99
|
|
|
76
100
|
console.log('No local .claude/ directory detected in the current working directory.');
|
|
77
|
-
console.log(`1. Install locally to current directory: ${path.join('.claude', 'skills', 'checkmyvibe')}`);
|
|
78
|
-
console.log(`2. Install globally/personally: ${
|
|
101
|
+
console.log(`1. Install locally to current directory: ${path.join('.claude', 'skills', 'checkmyvibe')} & ${path.join('.claude', 'commands')}`);
|
|
102
|
+
console.log(`2. Install globally/personally: ${globalSkillDest.replace(os.homedir(), '~')} & ${globalCommandsDest.replace(os.homedir(), '~')}`);
|
|
79
103
|
|
|
80
104
|
rl.question('\nSelect installation destination (1 or 2, default 2): ', (answer) => {
|
|
81
105
|
rl.close();
|
|
82
106
|
const selection = answer.trim();
|
|
83
107
|
if (selection === '1') {
|
|
84
|
-
performInstall(
|
|
108
|
+
performInstall(localSkillDest, localCommandsDest);
|
|
85
109
|
} else {
|
|
86
|
-
performInstall(
|
|
110
|
+
performInstall(globalSkillDest, globalCommandsDest);
|
|
87
111
|
}
|
|
88
112
|
});
|
|
89
113
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
3
|
"name": "checkmyvibe",
|
|
4
|
-
"version": "1.0
|
|
4
|
+
"version": "1.2.0",
|
|
5
5
|
"description": "A structured production readiness and code quality workflow Agent Skill for AI coding assistants to catch common vibe-coded configuration issues.",
|
|
6
6
|
"main": "install.js",
|
|
7
7
|
"bin": {
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
},
|
|
10
10
|
"files": [
|
|
11
11
|
"SKILL.md",
|
|
12
|
+
"commands/",
|
|
12
13
|
"scripts/",
|
|
13
14
|
"references/",
|
|
14
15
|
"install.js",
|
|
@@ -2,12 +2,22 @@
|
|
|
2
2
|
import os
|
|
3
3
|
import sys
|
|
4
4
|
import re
|
|
5
|
+
import fnmatch
|
|
5
6
|
|
|
6
7
|
SKIP_DIRS = {
|
|
7
8
|
'node_modules', '.git', 'build', 'dist', '.next', '.svelte-kit',
|
|
8
|
-
'__pycache__', 'venv', '.venv', 'env', 'coverage', 'out'
|
|
9
|
+
'__pycache__', 'venv', '.venv', 'env', 'coverage', 'out',
|
|
10
|
+
# Test/support directories: mock auth there is intentional, not a finding
|
|
11
|
+
'__tests__', '__mocks__', '__snapshots__', 'tests', 'test', 'spec',
|
|
12
|
+
'fixtures', 'mocks', 'e2e', 'cypress', '.storybook'
|
|
9
13
|
}
|
|
10
14
|
|
|
15
|
+
TEST_FILE_PATTERNS = ['*.test.*', '*.spec.*', '*.stories.*', '*.mock.*']
|
|
16
|
+
|
|
17
|
+
def is_test_file(filename):
|
|
18
|
+
"""Skip unit-test/spec/story/mock files: stubbed auth there is expected."""
|
|
19
|
+
return any(fnmatch.fnmatch(filename, pat) for pat in TEST_FILE_PATTERNS)
|
|
20
|
+
|
|
11
21
|
SKIP_EXTS = {
|
|
12
22
|
'.png', '.jpg', '.jpeg', '.gif', '.ico', '.pdf', '.zip', '.tar',
|
|
13
23
|
'.gz', '.mp3', '.mp4', '.mov', '.db', '.sqlite', '.exe', '.dll',
|
|
@@ -98,7 +108,7 @@ def main():
|
|
|
98
108
|
|
|
99
109
|
for file in files:
|
|
100
110
|
ext = os.path.splitext(file)[1].lower()
|
|
101
|
-
if ext in SKIP_EXTS or file.startswith('.'):
|
|
111
|
+
if ext in SKIP_EXTS or is_test_file(file) or file.startswith('.'):
|
|
102
112
|
continue
|
|
103
113
|
|
|
104
114
|
file_path = os.path.join(root, file)
|
|
@@ -2,8 +2,18 @@
|
|
|
2
2
|
import os
|
|
3
3
|
import sys
|
|
4
4
|
import re
|
|
5
|
+
import fnmatch
|
|
5
6
|
|
|
6
|
-
SKIP_DIRS = {
|
|
7
|
+
SKIP_DIRS = {
|
|
8
|
+
'node_modules', '.git', 'dist', 'build',
|
|
9
|
+
'__tests__', '__mocks__', 'tests', 'test', 'spec', 'fixtures',
|
|
10
|
+
'mocks', 'e2e', 'cypress'
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
TEST_FILE_PATTERNS = ['*.test.*', '*.spec.*', '*.mock.*']
|
|
14
|
+
|
|
15
|
+
def is_test_file(filename):
|
|
16
|
+
return any(fnmatch.fnmatch(filename, pat) for pat in TEST_FILE_PATTERNS)
|
|
7
17
|
|
|
8
18
|
# Permissive rules patterns for Firestore and Firebase Storage
|
|
9
19
|
FIREBASE_PERMISSIVE = re.compile(r'allow\s+[\w\s,]+:\s*if\s+true\s*;')
|
|
@@ -108,6 +118,8 @@ def main():
|
|
|
108
118
|
dirs[:] = [d for d in dirs if d not in SKIP_DIRS and not d.startswith('.')]
|
|
109
119
|
|
|
110
120
|
for file in files:
|
|
121
|
+
if is_test_file(file):
|
|
122
|
+
continue
|
|
111
123
|
file_path = os.path.join(root, file)
|
|
112
124
|
rel_path = os.path.relpath(file_path, target_dir)
|
|
113
125
|
|
package/scripts/scan_secrets.py
CHANGED
|
@@ -3,14 +3,24 @@ import os
|
|
|
3
3
|
import sys
|
|
4
4
|
import re
|
|
5
5
|
import math
|
|
6
|
+
import fnmatch
|
|
6
7
|
|
|
7
8
|
# Directories to skip during scanning
|
|
8
9
|
SKIP_DIRS = {
|
|
9
10
|
'node_modules', '.git', 'build', 'dist', '.next', '.svelte-kit',
|
|
10
11
|
'__pycache__', 'venv', '.venv', 'env', 'coverage', 'out', '.expo',
|
|
11
|
-
'.output', '.nuxt'
|
|
12
|
+
'.output', '.nuxt',
|
|
13
|
+
# Test/support directories: mocked credentials here are expected, not leaks
|
|
14
|
+
'__tests__', '__mocks__', '__snapshots__', 'tests', 'test', 'spec',
|
|
15
|
+
'fixtures', 'mocks', 'e2e', 'cypress', '.storybook'
|
|
12
16
|
}
|
|
13
17
|
|
|
18
|
+
TEST_FILE_PATTERNS = ['*.test.*', '*.spec.*', '*.stories.*', '*.mock.*']
|
|
19
|
+
|
|
20
|
+
def is_test_file(filename):
|
|
21
|
+
"""Skip unit-test/spec/story/mock files: fake keys there are intentional."""
|
|
22
|
+
return any(fnmatch.fnmatch(filename, pat) for pat in TEST_FILE_PATTERNS)
|
|
23
|
+
|
|
14
24
|
# File extensions to skip (binary/media/lockfiles/assets)
|
|
15
25
|
SKIP_EXTS = {
|
|
16
26
|
'.png', '.jpg', '.jpeg', '.gif', '.ico', '.pdf', '.zip', '.tar',
|
|
@@ -20,12 +30,13 @@ SKIP_EXTS = {
|
|
|
20
30
|
'.svg', '.css', '.scss', '.less', '.html', '.xml'
|
|
21
31
|
}
|
|
22
32
|
|
|
23
|
-
# Regexes for known API key formats
|
|
33
|
+
# Regexes for known API key formats (live keys are Critical; test keys are Should Fix)
|
|
24
34
|
API_KEY_PATTERNS = [
|
|
25
35
|
(re.compile(r'AIza[0-9A-Za-z-_]{35}'), 'Google API Key'),
|
|
26
36
|
(re.compile(r'AKIA[0-9A-Z]{16}'), 'AWS Access Key ID'),
|
|
27
37
|
(re.compile(r'ghp_[a-zA-Z0-9]{36,40}'), 'GitHub Personal Access Token'),
|
|
28
|
-
(re.compile(r'
|
|
38
|
+
(re.compile(r'sk_live_[0-9a-zA-Z]{24,96}'), 'Stripe LIVE Secret Key (Critical: charges real cards)'),
|
|
39
|
+
(re.compile(r'sk_test_[0-9a-zA-Z]{24,96}'), 'Stripe TEST Secret Key (Should Fix: not production-critical but must not be committed)'),
|
|
29
40
|
(re.compile(r'xox[bapr]-[0-9]{12}-[0-9]{12}-[0-9]{12}-[a-z0-9]{32}'), 'Slack Token'),
|
|
30
41
|
]
|
|
31
42
|
|
|
@@ -134,7 +145,9 @@ def main():
|
|
|
134
145
|
for file in files:
|
|
135
146
|
ext = os.path.splitext(file)[1].lower()
|
|
136
147
|
# Skip hidden files unless they are .env configuration files
|
|
137
|
-
if ext in SKIP_EXTS or (file
|
|
148
|
+
if ext in SKIP_EXTS or is_test_file(file):
|
|
149
|
+
continue
|
|
150
|
+
if file.startswith('.') and not file.startswith('.env'):
|
|
138
151
|
continue
|
|
139
152
|
|
|
140
153
|
file_path = os.path.join(root, file)
|