SEE IT WORK BEFORE YOU BUY
A real example report
These are real outputs of the Master of All Skills Claude Code plugin (version 1.1), run on a small sample online-shop app built for this demonstration. Nothing was written by hand or polished afterwards; only local folder paths were removed.
/master-of-all-skills:inspect
Inspect
Read-only inspection of the project: stack, routes, data, integrations, risks.
Show the full output
Inspection report: sample-shop
I only read files. Nothing was changed, installed or run beyond
git commands, and I made no ledger entry because this skill
only asks for one when files change, checks run or outside services are
called.
Git state
- Branch:
main. The working tree is clean, so there's no uncommitted work to protect. - History (2 commits):
377d861added the pages, contact form, orders API and admin page.0f8a8b1added the project map and ledger in.mos/. git diff --stat: empty.- Project map:
.mos/project-map.mdwas recorded at377d861. Since then only.mos/files changed, so the map is still accurate and I checked it against the code.
Stack
| Item | Finding | Tag |
|---|---|---|
| Framework | Next.js 15.0.0 using the app/ folder, React 19.0.0,
plain JavaScript |
Observed: package.json:5 |
| Database | Firestore via firebase-admin 13.0.0, set up on the
server only |
Observed: lib/firebase.js:1-4 |
| CLAUDE.md / AGENTS.md | None | Observed |
.gitignore, lockfile, node_modules |
None | Observed: file listing |
| README | One line describing the project | Observed: README.md:3 |
Pages and API endpoints
| Route | File | Auth | Notes | Tag |
|---|---|---|---|---|
/ |
app/page.js:2 |
none | Static page that links to /contact |
Observed |
/contact |
missing | — | The link on the home page leads to a 404 | Observed |
/admin |
app/admin/page.js:1 |
none | Shows only a heading and loads no data | Observed |
POST /api/contact |
app/api/contact/route.js:1-4 |
none | Reads the message, then throws it away: nothing is stored or emailed | Observed |
GET /api/orders |
app/api/orders/route.js:2-5 |
none | Returns up to 20 full order records to anyone | Observed |
POST /api/orders |
app/api/orders/route.js:6-10 |
none | Saves whatever data it receives, unchecked | Observed |
None of the routes handle errors, check their input or limit request rates. Nothing in the app calls either API.
Data, rules and integrations
- Firestore
orders: there's no defined shape for an order. It's whatever the caller sends (observed). firestore.rules:4:allow read, write: if truelets anyone who has the project ID read, change or delete every order through the Firebase client libraries (observed). The server routes use the admin SDK, which skips these rules anyway (inferred).- Environment variable names in
.env.example:FIREBASE_PROJECT_IDis read atlib/firebase.js:3.SMTP_USERandSMTP_APP_PASSWORDare never read (observed). - Firebase credentials: none are passed in code, so the app falls back to the host's default Google credentials (inferred).
- Email: SMTP is set up in the env file but not built, and no mail library is installed (observed).
- Login, payments, file storage, analytics, AI providers: none found (observed).
Checks
- Scripts:
dev,buildandstartonly (package.json:4). There are no tests, linting or type-checking (observed). - I ran no checks. A build would need
npm install, which this read-only skill doesn't allow. There are no tests to run.
Deployment
- Hosting: there's no
vercel.json,firebase.json, Dockerfile or CI setup (observed). It probably targets Vercel or a generic Node host (inferred). - Firestore rules: no config shows whether they are deployed.
Risks
- Public database rules: anyone can read and write all orders.
- Open orders API: order data can be read without logging in, and anyone can write unchecked records.
- Admin page:
/adminhas no login. It's harmless today because it shows no data, but it will matter once it does. - Contact form: the endpoint silently drops messages,
and the
/contactpage doesn't exist. - Route safety: there's no error handling, rate limiting, input checking or check that environment variables are set at startup.
- No
.gitignore: a real.envfile could be committed by accident. - No lockfile: Next 15.0.0 is an early release with
security advisories that later patches fix.
npm auditwas not run.
Unknowns
- Where the app is deployed, and whether it's live.
- Which Firestore rules are actually deployed.
- How Firebase credentials are supplied at runtime.
- What an order should contain, and who may create or read orders.
- Which SMTP provider sends contact messages, and who receives them.
TASK: Read-only inspection of sample-shop
STATUS: Review — inspection complete, no changes made
LANES: single
TESTS: 0 passed, 0 failed, 0 not run (no test suite exists; build/npm audit NOT RUN — needs npm install)
DEPLOYMENT: 0f8a8b1 — not deployed / deployment target unknown
APPROVALS: none pending
RISKS: public read/write Firestore rules; unauthenticated, unvalidated orders API; unprotected /admin; contact submissions dropped, /contact missing; no .gitignore or lockfile; next@15.0.0 advisories unchecked
NEXT: Choose whether to (a) plan fixes starting with Firestore rules and orders API auth (security/data approvals required), (b) allow npm install + build + npm audit, or (c) confirm deployment target and Firebase credentials setup
/master-of-all-skills:map
Project map
The living project map, pinned to a commit, that later changes are checked against.
Show the full output
Project map — sample-shop
- Commit:
377d8611206c1503b3a4777ca35d27b549171862(main, "Sample Shop: pages, contact form, orders API, admin") - Date: 2026-11-11
- Working tree at mapping time: clean
- Previous map: none (first map — no drift to report)
Legend: [O] observed in the named file · [I] inferred (not directly evidenced)
Stack
| Item | Value | Source |
|---|---|---|
| Framework | Next.js 15.0.0, App Router (app/), React 19.0.0 |
[O] package.json, app/ |
| Language | JavaScript (no TypeScript) | [O] file extensions |
| Database | Firestore via firebase-admin 13.0.0 (server SDK) |
[O] lib/firebase.js |
| Package lock | none committed | [O] file listing |
.gitignore |
none committed | [O] file listing |
Pages / routes
| Route | File | Renders | Auth | Data | Tag |
|---|---|---|---|---|---|
/ |
app/page.js |
Static heading, tagline, link to /contact |
none | none | [O] |
/admin |
app/admin/page.js |
Static "Orders admin" heading only; does not fetch orders | none | none | [O] |
/contact |
— (no app/contact/page.js) |
Linked from /, but the page does not exist → 404 |
— | — | [O] missing |
Shared components and layouts
| Item | File | Notes | Tag |
|---|---|---|---|
| Root layout | app/layout.js |
<html lang="en"><body>;
metadata.title = 'Sample Shop' |
[O] |
| Shared components | none | No components/ directory |
[O] |
API endpoints / server actions
| Method + path | File | Auth | Validation | Rate limit | Data touched | Tag |
|---|---|---|---|---|---|---|
POST /api/contact |
app/api/contact/route.js |
none | none | none | Parses JSON body and discards it; returns { ok: true }.
Sends no email, stores nothing. |
[O] |
GET /api/orders |
app/api/orders/route.js |
none | — | none | Reads up to 20 docs from Firestore orders; returns full
document data publicly |
[O] |
POST /api/orders |
app/api/orders/route.js |
none | none — arbitrary JSON written as-is | none | Writes a new doc to Firestore orders |
[O] |
| Server actions | none found | — | — | — | — | [O] |
No route has try/catch; errors surface as unhandled 500s. [O]
Data stores and collections
| Store | Collection | Read by | Written by | Tag |
|---|---|---|---|---|
Firestore (Admin SDK, initialised in
lib/firebase.js) |
orders |
app/api/orders/route.js GET |
app/api/orders/route.js POST |
[O] |
Document schema for orders: undefined — whatever the
client posts. [O]
Security rules and policies
| File | Rule | Effect | Tag |
|---|---|---|---|
firestore.rules |
match /orders/{id} { allow read, write: if true; } |
Any client-SDK caller who knows the project ID can read, modify and delete all orders | [O] |
| — | Admin SDK bypasses Firestore rules, so the API routes are unaffected by this file | — | [I] (standard firebase-admin behaviour) |
| Middleware / auth | none (middleware.js absent, no auth library) |
— | [O] |
| Deployment of rules | No firebase.json / .firebaserc; how and
whether firestore.rules is deployed is unknown |
— | [O] absent / unknown |
Environment variables (names only)
| Name | Declared in | Read in | Tag |
|---|---|---|---|
FIREBASE_PROJECT_ID |
.env.example |
lib/firebase.js:3 |
[O] |
SMTP_USER |
.env.example |
not read anywhere | [O] |
SMTP_APP_PASSWORD |
.env.example |
not read anywhere | [O] |
Firebase Admin credentials: none passed explicitly;
initializeApp will rely on Application Default Credentials
(GOOGLE_APPLICATION_CREDENTIALS or the hosting runtime's
service account). [I] No env validation at startup. [O]
External integrations
| Integration | Status | Files | Tag |
|---|---|---|---|
| Google Firebase / Firestore | Active | lib/firebase.js, app/api/orders/route.js,
firestore.rules |
[O] |
| SMTP email (likely Gmail app password) | Declared but not implemented; no mail library in
package.json |
.env.example |
[O] declared / [I] provider |
Background jobs and schedules
None found (no cron config, no vercel.json, no Cloud
Functions). [O]
Deployment targets and config
| Item | Finding | Tag |
|---|---|---|
| Hosting config | None committed (no vercel.json,
firebase.json, Dockerfile, CI workflows) |
[O] |
| Likely target | Vercel or any Node host via next build /
next start |
[I] |
| Scripts | dev, build, start |
[O] package.json |
Tests
None. No test runner, no test files, no test script. All
areas uncovered. [O]
Dependency table
| Dependency | Depended on by | Tag |
|---|---|---|
Firestore orders collection |
GET /api/orders, POST /api/orders
(app/api/orders/route.js); /admin is
named for orders but does not use it yet |
[O] / [I] for admin intent |
lib/firebase.js (db) |
app/api/orders/route.js |
[O] |
FIREBASE_PROJECT_ID |
lib/firebase.js → all orders endpoints |
[O] |
firestore.rules |
Any client-SDK access to orders (none in this
repo) |
[O] |
POST /api/contact |
No caller in repo (intended /contact page is
missing) |
[O] |
GET/POST /api/orders |
No caller in repo (no UI fetches it) | [O] |
SMTP (SMTP_USER, SMTP_APP_PASSWORD) |
Nothing yet; presumably intended for /api/contact |
[I] |
app/layout.js |
All pages (/, /admin) |
[O] |
Risks observed (for follow-up; not fixed by this service)
firestore.rulesallows public read/write oforders.GET /api/ordersexposes order data without authentication.POST /api/ordersaccepts unauthenticated, unvalidated arbitrary JSON./adminhas no authentication (currently harmless — renders no data).- Contact form endpoint silently drops submissions;
/contactpage missing (broken link on/). - No try/catch, rate limiting, input validation or env validation on any route.
- No
.gitignore— a local.envornode_modulescould be committed accidentally. - No lockfile;
next@15.0.0is an early 15.x release with published security advisories in later patch releases — checknpm audit(not run).
Unknowns
- Where the app is deployed and whether a production deployment exists.
- Whether
firestore.ruleshas been deployed to the Firebase project, and what rules are live. - How Firebase Admin credentials are provided at runtime.
- Intended
ordersschema and who should be allowed to create/read orders. - Intended SMTP provider and recipient for contact submissions.
- Whether there are other Firestore collections in the live project not referenced by code.
/master-of-all-skills:plan
Scope Contract and plan
Plan for a real request, with approval checkpoints and parallel lanes. Nothing is changed before approval.
Show the full output
Scope Contract: lock down orders and make the contact form send email
Basis: repo at 0f8a8b1.
.mos/project-map.md was made at 377d861, and
only .mos/ files have changed since, so the map is still
accurate. Working tree clean. Today is Wed 2026-11-11, so the deadline
is Fri 2026-11-13.
| Goal | Only signed-in admins can read or change orders. Contact form submissions arrive as email. |
| In scope | Admin sign-in using Firebase Auth (the project already uses
Firebase) with an admin flag on each admin account.
Admin-only GET/POST /api/orders. A protected
/admin page that lists orders. Firestore rules that block
all direct client access. A real contact page and contact API that sends
mail through SMTP (SMTP_USER/SMTP_APP_PASSWORD
already exist). Input validation, try/catch, rate limits and safe errors
on the routes I touch. .gitignore, lockfile, tests. |
| Out of scope | A customer checkout flow. Customer accounts. Upgrading Next.js (risk noted below). Hosting changes. Auditing or cleaning up existing order data. Styling beyond basic accessible forms. |
| Must not change | Home page content and layout. Root layout. Existing
orders documents and their shape. The
GET /api/orders response shape for admins. Existing env var
names. Firestore project. |
| Acceptance tests | AT1 GET /api/orders: no session → 401,
non-admin → 403, admin → 200 with the same array shape as now.
AT2 POST /api/orders: same auth results,
and a bad body from an admin → 400. AT3
/admin: signed out → redirect to /login;
non-admin → 403 with no order data in the HTML; admin → orders listed.
AT4 Firestore rules emulator: signed-out and signed-in
client reads and writes on orders/{id} are all denied.
AT5 POST /api/contact: valid → 200 and
mail goes to CONTACT_TO with reply-to set to the sender;
invalid → 400; hidden spam-trap field filled → 200 with nothing sent;
6th request per IP per minute → 429; SMTP failure → 502 with a generic
message and no secrets in logs. AT6
/contact works at 375px, fields have labels, success and
error states show, and the home page link no longer 404s.
AT7 npm run build and
npm test pass. AT8 Session cookie is
HttpOnly, Secure in production and SameSite=Lax; sign-out revokes it.
Manual: one real email is received in the inbox,
confirmed by you. |
| Risks | Firestore rules are publicly read/write right now, so the leak is
live until the rules are deployed. Next 15.0.0 has known advisories,
including a middleware auth bypass, so auth checks go in each route and
page, not in middleware. I don't know where the app is hosted or how it
gets Firebase admin credentials. Session cookies need service-account
credentials. An in-memory rate limit only holds per server instance.
Gmail allows roughly 500 sends a day. Something outside this repo may
use the client SDK on orders. |
| Approval mode | standard |
| Approvals needed | A1 Auth and permission change: admin-only orders
API and /admin, plus a new /api/session route.
A2 Firestore rules change to
allow read, write: if false on orders, plus a
new firebase.json. A3 New service and
keys: turn on Firebase Authentication (email/password), add the client
firebase SDK, add NEXT_PUBLIC_FIREBASE_* and
service-account env vars. A4 Give the admin flag to the
accounts you name, using a script you run. A5 Send
email through Gmail SMTP with an app password, using the
nodemailer package and a new CONTACT_TO env
var. A6 Public-facing text on /contact and
/login. A7 Production deploys, split into
A7a Firestore rules and A7b app. |
| Est. changes | About 20 files (about 11 new, 9 modified) in 7–9 commits on one branch, with one PR. |
| Deadline | Fri 2026-11-13 |
Questions to answer in your edits:
- Q1 Who may create orders? I recommend admins only,
since nothing in the repo calls
POST. If you choose public, I'll keepPOSTopen but validated against a field allowlist and rate-limited. - Q2 Which inbox should contact mail go to, and which account sends it?
- Q3 Admin email address(es)?
- Q4 Where is the app hosted, and how does it get Firebase admin credentials?
- Q5 Sign in with email/password (recommended) or Google?
Tasks
| # | Task | Files / mapped areas | Depends on | Acceptance | Check to run | Risk | Approval | Paid / new access |
|---|---|---|---|---|---|---|---|---|
| T0 | Create the branch. Add .gitignore, all new dependencies
(firebase, nodemailer, vitest,
@firebase/rules-unit-testing) and the lockfile. Run a
baseline build. |
package.json, .gitignore |
none | AT7 baseline | npm install && npm run build |
Low | none | No |
| T1 | Add startup env checks. Let lib/firebase.js accept
explicit service-account credentials or fall back to the host's default
credentials. Add a shared rate limiter. Add every new env var name to
.env.example. |
lib/env.js, lib/firebase.js,
lib/rate-limit.js, .env.example. Env:
FIREBASE_PROJECT_ID + new vars |
T0 | Unit tests: missing vars fail clearly | npm test |
Med | A3 | Service-account key |
| T2 | Add server auth helpers (check the session cookie and the admin
flag). Add POST/DELETE /api/session to sign in and
out. |
lib/auth.js, app/api/session/route.js (new
endpoint) |
T1 | AT8, plus unit tests for helpers | npm test |
High | A1, A3 | Firebase Auth enabled |
| T3 | Build the /login page using the client SDK. |
app/login/page.js, lib/firebase-client.js
(new route) |
T2 | Sign in, then land on /admin |
build + manual | Med | A3, A6 | No |
| T4 | Lock down the orders API: admin check, try/catch, body validation, 401/403/400. | app/api/orders/route.js. Collection:
orders |
T2 | AT1, AT2 | npm test |
High | A1 | No |
| T5 | Protect /admin (redirect or 403) and list orders for
admins. |
app/admin/page.js. Collection: orders |
T2 | AT3 | npm test + manual |
High | A1 | No |
| T6 | Add scripts/set-admin.mjs <email> to set the
admin flag. You run it. |
scripts/ |
T2 | The account's token shows admin: true |
you run it | Med | A4 | No |
| T7 | Change the rules to deny all client access to orders,
add firebase.json, add an emulator test. |
firestore.rules, firebase.json,
tests/rules.test.js |
T0 | AT4 | firebase emulators:exec "npm run test:rules" (BLOCKED
if Java isn't installed) |
High | A2 | No |
| T8 | Contact API: validation, spam-trap field, rate limit, mail through
lib/mailer.js, safe errors, logs with personal data
removed. |
app/api/contact/route.js, lib/mailer.js.
Env: SMTP_*, CONTACT_TO |
T1 | AT5, with the mail transport mocked | npm test |
Med | A5 | Gmail app password |
| T9 | Build the /contact page form. |
app/contact/page.js (new route) |
T8 | AT6 | build + 375px check | Low | A6 | No |
| T10 | Independent review of the auth and rules changes by a fresh subagent, checked against this plan, as the policy requires. | diff for T2–T7 | T2–T7 | Findings fixed or accepted | — | — | — | No |
| T11 | Full verification, README update, ledger entry, PR. | README.md, .mos/ledger.md |
T0–T10 | AT1–AT8 | npm run build && npm test |
— | — | No |
| T12 | Deploy the rules first, then the app, then check the deployment for that exact commit. | Deployment targets | T11 | Live 401 on /api/orders, plus the manual email |
verify-deploy |
High | A7a, A7b | Hosting access |
Parallel lanes
- Lane 0 (sequential, first): T0 → T1. These change
package.json,.env.exampleandlib/firebase.js, which everything else depends on. Adding all dependencies and env var names up front means no later lane needs to touch those files. - Lane A (sequential): T2 → T3, T4, T5, T6. These all
share
lib/auth.js, the session cookie and the Firebase Auth env vars, so they stay in one lane. - Lane B: T8 → T9. These touch only the contact files and the SMTP env vars. They share no files, collections, rules or deploy settings with A or C.
- Lane C: T7. It touches only
firestore.rulesandfirebase.json. The server code uses the admin SDK, which ignores Firestore rules, so this lane doesn't affect A. - Final (sequential): T10 → T11 → T12.
Suggested order for Friday: do T7 and A7a on Thursday. That closes the open Firestore hole without waiting for the app deploy.
Costs (nothing gets purchased)
I didn't fetch pricing pages this session. Treat every line as verify at checkout.
- Firebase Authentication, email/password: free on Spark and Blaze for up to about 50k monthly active users (from my knowledge, not checked today). Phone/SMS sign-in costs extra and isn't used here. Source: firebase.google.com/pricing.
- Firestore: already in use, no change in usage.
- Gmail SMTP with an app password: free on a personal Gmail account (needs 2-Step Verification), with a limit of roughly 500 sends a day. Sending from a business domain needs Google Workspace; plans are listed at workspace.google.com/pricing.
- npm packages:
firebase,nodemailer,vitest,@firebase/rules-unit-testing,firebase-toolsare open source and free. - Hosting: unchanged, provider unknown (Q4).
Approve, edit, or reject? I'll wait for your answer,
and answers to Q1–Q5, before changing anything. Once you approve, I'll
save this to .mos/approved-brief.md with the date and your
exact edits.
TASK: Admin-only orders + contact form email (deadline Fri 2026-11-13)
STATUS: Planned — Scope Contract and 13-task plan waiting for approval
LANES: Lane 0 (T0–T1) → parallel A (auth/orders), B (contact), C (rules) → final review/verify/deploy
TESTS: 0 passed, 0 failed, all not run (planning only; repo has no tests yet)
DEPLOYMENT: not deployed (HEAD 0f8a8b1; live hosting unknown)
APPROVALS: plan approval pending; A1–A7 to be requested at their tasks
RISKS: Firestore rules publicly read/write right now; Next 15.0.0 advisories; admin credentials/hosting unknown; per-instance rate limit; possible outside client-SDK use of orders
NEXT: Approve, edit or reject the plan, and answer Q1–Q5
I didn't write a ledger entry for this step because no files were changed and no external services were called. The only commands run were read-only git commands.
/master-of-all-skills:security-review
Security review
Read-only security findings with file and line, the attack each allows, and the fix.
Show the full output
I found 2 critical and 3 high-severity issues. The most urgent: the Firestore rules let anyone read, change or delete every order, and the orders API has no login check at all. The installed Next.js and React versions are also in ranges with a published unauthenticated remote-code-execution advisory.
What I checked (commit 0f8a8b1): I read
every file in the repo. The map from 377d861 is still
accurate, since only .mos/ files changed after it.
- Secrets: none committed. The search covers history too, because the app files haven't changed since the first commit.
- Logging: the app logs nothing, so nothing sensitive leaks, but there's also no record of who did what.
npm audit: not run. There's no lockfile, and creating one in the scratchpad was blocked by this session's permissions. The dependency finding (C3) comes from published advisories I know of, not from an audit.- Ledger: writing to
.mos/ledger.mdwas blocked by the same permissions, so the entry has not been added. The text is ready; say the word and I'll append it.
Critical
C1. The database rules allow public read and write:
firestore.rules:4
(allow read, write: if true)
- Attack: the Firebase project ID is meant to be public. Anyone with it can use the client SDK to read every order, change or delete orders, and write junk you pay to store.
- Fix:
allow read, write: if false;. The server's Admin SDK ignores these rules, so the API keeps working. Later, add an admin-only rule if needed. - Unknown: whether this file has been deployed. Check the live rules in the Firebase console.
C2. Anyone can list orders:
app/api/orders/route.js:2-5
- Attack: an anonymous
GET /api/ordersreturns the full contents of up to 20 orders, including any names and addresses stored in them. - Fix: check the user's sign-in token on the server and require an admin role. Return only the fields the admin view needs.
C3. Vulnerable framework versions:
package.json:5 (next@15.0.0,
react@19.0.0)
- Attack: these versions fall inside the published React Server Components advisories (CVE-2025-55182 / CVE-2025-66478), which allow unauthenticated remote code execution against App Router apps. This app uses the App Router.
- Other advisories: a middleware auth bypass (CVE-2025-29927, fixed in 15.2.3) will matter as soon as login is added through middleware.
- Fix: upgrade to the latest patched 15.x of
nextand the matchingreact/react-dom, commit a lockfile, then runnpm audit.
High
H1. Orders can be forged:
app/api/orders/route.js:6-10
- Attack: whatever JSON a caller sends is stored as
an order, with no login and no checks. Anyone can create orders with a
made-up price or
"paid": true, overwrite fields, or send documents up to 1 MiB to run up costs. - Fix: require sign-in, check the request against a schema that only allows known fields and caps size, and work out prices and status on the server. Store the customer's user ID on each order.
H2. No rate limiting on any route
(/api/orders, /api/contact)
- Attack: spam, write floods and a growing Firestore bill.
- Fix: a per-IP limit, and/or Firebase App Check.
H3. Customers aren't separated from each other
- Orders have no owner field, so once customers can view their own orders, the code has no way to restrict them to their own.
- Fix: add a
uidfield and filter queries by the signed-in user. This also needs a matching database rule.
Medium
- M1. No error handling
(
orders/route.js:3,7-8;contact/route.js:2): sending malformed JSON or a Firestore failure produces an unhandled 500 with no log entry. Add try/catch, return 400 for bad input, and log errors with personal data removed. - M2.
/adminneeds no login (app/admin/page.js:1): it shows no data today, but it becomes C2 as soon as it does. Check login and role inside the page or its layout on the server. Don't rely on middleware alone. - M3. No
.gitignore: a local.envfile or a service-account key file could be committed by accident. Ignore.env*(keep.env.example),node_modules,.nextand*service-account*.json.
Low
- L1. No startup check of settings
(
lib/firebase.js:3): ifFIREBASE_PROJECT_IDis missing, the app quietly falls back to whatever credentials the host provides. - L2. Contact form (
contact/route.js): submissions are thrown away. When email sending is added, validate and limit the length of fields, and strip line breaks from header fields to block email header injection.SMTP_APP_PASSWORDis not used anywhere yet.
Needs a specialist
- Penetration test: before launch, once the fixes for C1–H3 are in.
- Legal / compliance: if the open rules (C1) were ever live with real customer data, get a privacy lawyer to assess whether this was a reportable breach under GDPR or CCPA. The Firestore audit logs show whether anyone accessed the data.
- Payments: card details must never go into
orders. Use a hosted checkout from a payment provider so PCI DSS card-security rules stay minimal.
Fixes awaiting your approval
| ID | Change | Covers |
|---|---|---|
| A1 | Change firestore.rules to deny all client access |
C1 |
| A2 | Server-side login and admin-role checks on /api/orders
and /admin, and a uid owner field on
orders |
C2, H1, H3, M2 |
| A3 | Upgrade next/react/react-dom
to patched versions and commit a lockfile |
C3 |
| A4 | Rate limiting (may need a new service, possibly paid) or App Check | H2 |
| A5 | Schema validation, try/catch, startup settings check,
.gitignore |
H1, M1, M3, L1 |
A1, A2 and A3 change security or authentication, so another reviewer will check those changes before I propose merging them.
TASK: Security review of sample-shop (read-only)
STATUS: Review — 2 critical, 3 high, 3 medium, 2 low findings
LANES: single
TESTS: 2 passed (file review, secret search), 0 failed, 2 not run (npm audit and git history search: blocked by permissions; no test suite exists)
DEPLOYMENT: 0f8a8b1 — not deployed (no deployment config)
APPROVALS: A1–A5 pending; ledger write blocked by permissions, entry not added
RISKS: live Firestore rules unknown; dependency advisories not confirmed by npm audit; whether data was exposed is unknown
NEXT: approve A1 + A3 first (urgent), then A2/A5; allow the ledger write and npm audit
/master-of-all-skills:fix
Fix with proof
An approved bug fix on a branch, with a test that fails before and passes after.
Show the full output
I fixed the crash: POST /api/contact now returns a 400
instead of a 500 when the body isn't valid JSON. The new test failed on
3 of 4 cases before the fix and passes 4 of 4 after it. I haven't run
the app itself or next build, because there's no
node_modules here.
Cause: app/api/contact/route.js:2 calls
await req.json() with no error handling. A malformed, empty
or plain-text body throws a SyntaxError there, and Next.js
turns that into a 500.
Fix (app/api/contact/route.js, branch
fix/contact-invalid-json, commit b92811b):
- If the body can't be read as JSON, it returns 400
with
{ ok: false, error: "Request body must be valid JSON." }. - I also wrapped the whole handler in a try/catch, as the project's policy requires. Any other error returns a plain 500 message and logs only the error type, never what was submitted.
- Valid requests behave the same as before
(
200 { ok: true }). - Risk is low: only bad requests change behaviour, and they now get a 400 where they used to get a 500.
Test (tests/contact-route.test.mjs): it
uses Node's built-in test runner, so it needs no new packages. It checks
one valid request and three bad ones (malformed JSON, plain text, empty
body).
- Before the fix: 1 passed, 3 failed with the
SyntaxErroratroute.js:2. - After the fix: 4 passed. Command:
node --test tests/contact-route.test.mjs, on Node v22.23.4.
Also:
- There's no
testscript inpackage.json; adding one would go beyond the scope you approved. Until then, run the test withnode --test tests/. - I added an entry to
.mos/ledger.mdas the project policy requires, in a separate commit (bb7450f), so you can drop it from the PR if you want. - Nothing has been pushed or deployed.
TASK: Return 400 instead of 500 when POST /api/contact gets a body that isn't valid JSON
STATUS: Review — fixed on branch fix/contact-invalid-json (b92811b + ledger bb7450f), not pushed
LANES: single
TESTS: 4 passed, 0 failed (node --test tests/contact-route.test.mjs); not run: next build, HTTP request to a running app, npm audit
DEPLOYMENT: not deployed (bb7450f exists only locally)
APPROVALS: none pending
RISKS: not checked inside the actual Next.js runtime; the contact form still throws submissions away and has no field validation or rate limiting; no test script in package.json
NEXT: push the branch and open a PR? and whether to approve adding "test": "node --test tests/" to package.json
/master-of-all-skills:status
Mission Control
The status view of work in progress, approvals and risks.
Show the full output
Here's where things stand. The contact-form fix is finished and its tests passed, but it hasn't been reviewed, pushed or deployed yet. I didn't change any files.
Sources read: .mos/ledger.md,
.mos/project-map.md, git status,
git log and the branches. There is no
.mos/approved-brief.md, so no Scope Contract has been
approved yet.
Repo: you're on branch
fix/contact-invalid-json. Nothing is uncommitted. It is 2
commits ahead of main (b92811b is the fix and
bb7450f is its ledger entry), and main itself
is at 0f8a8b1.
Deployment: NOT CHECKED. The repo has no git remote
and no hosting config (no vercel.json or
firebase.json), and neither the vercel nor the
firebase CLI is installed. So nothing tells me where
bb7450f would deploy.
Project map: it is out of date. It was made at
377d861, and app/api/contact/route.js, which
the map covers, has changed since. Run map again before
relying on it for the contact endpoint.
Board
| Stage | Items |
|---|---|
| Planned | — (there's no approved brief) |
| Building | — |
| Review | Contact-form fix: a request with invalid JSON now gets a 400 error
instead of 500 (b92811b). It needs your review, plus a push
or merge, which only you can approve. |
| Verified | — (only the unit tests ran; the fix hasn't been checked on a running app) |
| Deployed | — |
| Blocked | — |
Lanes: single.
NOT RUN / NOT VERIFIED
next build: NOT RUN (node_modulesisn't installed).- A real request to a running dev server: NOT RUN.
npm audit: NOT RUN.- Deployment of
bb7450f: NOT CHECKED (no remote and no hosting set up). - The map doesn't reflect the contact route as it is now.
Open risks (from the ledger and map)
- Firestore: the
ordersrules let anyone read and write. - Orders API: it has no login check and no input validation.
/admin: the page has no protection.- Contact form:
- It still throws submissions away and has no field validation or rate limiting.
- The
/contactpage it links to is missing, so it returns 404.
- SMTP: the variables are defined but nothing uses them.
- Repo hygiene:
- There's no
.gitignoreor lockfile. - There's no
testscript inpackage.json.
- There's no
No ledger entry was added because this service only read files and git state.
TASK: Contact-form fix — return 400 instead of 500 on invalid JSON (branch fix/contact-invalid-json)
STATUS: Review — committed at b92811b (+ ledger bb7450f); 4/4 unit tests passed; not pushed, merged or deployed
LANES: single
TESTS: 4 passed, 0 failed, 3 not run (passed: node --test tests/contact-route.test.mjs; not run: next build, real request to a dev server, npm audit)
DEPLOYMENT: bb7450f — NOT CHECKED (no remote, no hosting config, no hosting CLI); not deployed
APPROVALS: none pending with IDs; merge/push of fix/contact-invalid-json needs your explicit approval
RISKS: orders Firestore rules let anyone read/write; orders API has no login or validation; /admin unprotected; contact form discards submissions and /contact page is 404; map out of date; no .gitignore or lockfile; fix not checked on a running app
NEXT: Review the fix and decide whether to merge it into main. Separately, tell me where the app is hosted, and whether to run /master-of-all-skills:map and /master-of-all-skills:plan for the security risks.
Get this for your own projects
The plugin runs in your own Claude Code with your own accounts. You approve every change that matters.
One-off purchase with 12 months of updates. Claude subscription and usage are not included.