Full technical report — wenakita/4626
| Report ID | 4626-FABLE-2026-06 |
|---|---|
| Date | June 2026 |
| Repository | wenakita/4626 |
| Review type | Read-only technical security assessment |
| Lead session | 0a513245… |
Executive summary available: For critical and high findings only, read the executive summary first. This document is the complete technical report.
Method: Multi-pass read-only review. Baseline validation commands, parallel subsystem workstreams, manual verification of high-severity candidates. Findings graded VERIFIED / REFUTED / ALREADY-KNOWN with file:line evidence.
Scope: Full monorepo — frontend SPA, ~350 Vercel API handlers, Foundry contracts, KPR keepers, Solana program, Railway messaging runtime.
1. Executive summary
The repository is a large, mature monorepo with engineering hygiene above average: SHA-pinned CI actions, no pull_request_target, RLS on every new table, transactional profile-merge, race-safe keeper-job claiming, tombstone/alias cascades on identity lookups, and a documented canonical-CSW invariant enforced by CI.
No remotely exploitable unauthenticated RCE or web-tier fund-drain was identified. Material risks concentrate in:
- Impairment side-pocket v1 — three on-chain issues (missing
totalClaimSupplycap + uncapped shared escrow; coin-balance accounting gap on recovery; stale-root lifecycle afterclearImpairmentTrip). These require a malicious or faulty manager or keeper (semi-trusted roles), not anonymous exploitation. Side-pocket code has thin test coverage. - x402 strategy activation — USDC settles on-chain before entitlement validation; a post-settlement database failure can leave a settled payment with no entitlement record.
- CI enforcement gaps — Semgrep likely non-blocking due to pipe behavior; boundary guards not fully wired into gating CI; a control-plane cron workflow fails at install (lockfile mismatch).
- Working-tree drift — typecheck (6 errors) and Vitest (78 failures) were red on the dirty tree at review time (uncommitted WIP, not a shipped regression).
Release-readiness verdict: NOT READY to tag a clean release from the reviewed working tree. Resolve or explicitly risk-accept impairment and x402 findings (with updated disclosures) before deploying those paths. Repair CI gates and commit/clean the tree before tagging.
2. Commands run (baseline, Pass 0)
| Command | Result | Root cause / note |
|---|---|---|
pnpm install (root) + pnpm -C frontend install | OK | Two lockfiles, as documented. |
pnpm -C frontend lint | PASS (exit 0) | Clean. |
pnpm -C frontend guard:canonical-csw | PASS (exit 0) | No retired env / stray CSW literals. |
pnpm -C kpr typecheck | PASS (exit 0) | No-regression gate holds. |
forge build | PASS | Submodules present. |
forge test | 1 FAIL | Environmental only — one test reaches wss://eu.endpoints.matrixed.link (RPC) and fails offline. Not a code defect; token in URL is env-supplied, not committed. |
pnpm -C frontend typecheck | FAIL (6 errors) | Dirty working tree (uncommitted WIP in AccountSetupWorkspaceView.tsx, useAccountSetupController.ts, useMyReferralCode.ts, xmtp/provider.tsx). Not a committed regression. |
pnpm -C frontend test (Vitest) | FAIL (78 tests / 19 files) | Predominantly api/__tests__ and src/features/waitlist; attributable to working-tree drift + test content drift. |
pnpm -C frontend guard:schema | FAIL | Raw DDL string in committed frontend/server/_lib/agents/base-mcp/approvalFlow.ts — guard catches it but CI may not run this guard in the gating job (see §6). |
pnpm -C frontend guard:frontend-boundaries | FAIL | 5 api-no-src violations in committed code (_vanityPerVaultVersion.ts, _vanityShareOftSalt.ts, v2/session/_createCore.ts, _preview-add-owner.ts ×2). Not wired into any workflow. |
pnpm -C frontend guard:server-core-boundary | FAIL | 7 violations in committed code (`admin/ethos/_health |
pnpm audit --prod (root) | 1 low | Acceptable. |
pnpm -C frontend audit --prod | 6 moderate, 4 high | See §8 (dependency posture). |
pnpm security:local (Semgrep) | Skipped | Needs Docker; environmental. |
Working-tree note: ~20 modified files are uncommitted (notably
_continueCore.ts,_dryRunCore.ts,_paymaster.ts,keeperJobRunner.ts,schemaBootstrap.ts,_solanaReconcile.ts,dailyBrief.ts,txRouter.ts, plus the new20260711000000_solana_share_mesh_mappings.sqlmigration). They are part of the reviewed state and are the proximate cause of the red typecheck/Vitest.
3. Architecture map
Three Vercel HTML shells share one React bundle; host decided at runtime:
4626.fun/→public/immersive/index.html(static marketing island); other4626.funpaths →index.htmlSPA (waitlist, FAQ, explore, positions).app.4626.fun/*→app.htmlSPA (swap, deploy, admin).app.4626.fun/waitlist*→ 308 to4626.fun/waitlist.- API:
/api/(.*)→ frontend/api/[...path].ts → static route map in_handlers/_routes*.ts(~350 handlers across inline + prefixed +v1loaders).
Auth lanes: Privy X-Privy-Token (verifyAuthToken); HttpOnly cv_auth_session HMAC cookie (SIWE); Vercel cron CRON_SECRET; machine KPR_API_KEY (constant-time); admin (session address/email, ADMIN_API_TOKEN, or dual session+CRON_SECRET for profile merge). cv_auth_session uses Domain=.4626.fun so sessions survive marketing↔app navigation.
Background: 31 Vercel crons (creator metrics, AlfaClub bridge, AMOE, Zora/Ethos sync, keeper-job enqueue) using getDbForCron; keeper_jobs queue (claim/run/complete) with allowlisted outbound; 16 KPR workflows + Solana orchestrator; Railway XMTP/Eliza + Hermit runtimes.
Data: 127 Supabase migrations (SSoT); runtime schemaBootstrap.ts delegates via ensureMigrationApplied (no raw DDL allowed); profile-merge + tombstone/alias infra.
Riskiest boundaries (judgment): /api/paymaster JSON-RPC proxy (~3.8k lines, sponsors UserOps), machine-auth keeper surface, webhook ingress (Telegram/Stripe), POST /api/admin/profiles/merge, deploy-session owner delegation, Privy-token-vs-session split, Solana provisioner/orchestrator, AlfaClub chat-bridge cron.
4. Prioritized findings
Severity reflects exploitability and trust assumptions. "Manager/keeper" = semi-trusted protocol roles (not anonymous).
CRITICAL
C-1 — x402 strategy activation settles USDC on-chain before entitlement check; failed insert loses all payment records
Status: VERIFIED · frontend/api/_handlers/creator/strategy/_x402-activate.ts
- Line ~206
settleX402Payment(parsed.payment)broadcasts the EIP-3009transferWithAuthorization(creator USDC → treasury) before anyhasLiveActivationForFeaturepre-check. - Lines ~225–247 only then run
insertPendingActivationinsiderunInTransaction. Alive_activation_existsconflict returns 409 — but USDC is already moved. upsertPaymentOrder(~249) andrecordPaymentEvent(~262) share the same transaction as the failing insert, so rollback erases them too. Net: a settled on-chain payment with zero rows in any payment table — only the on-chain tx and a 409 response. Thedb_errorcatch (~279–285) has the same property.- The plain-USDC path (
_activate.ts) is safer because the creator broadcasts the transfer; here the server initiates the irreversible move.
Fix: call hasLiveActivationForFeature (exists at activations.ts:114) before settleX402Payment; on any post-settlement failure, durably record the orphaned settlement outside the rolled-back tx for refund ops.
Regression test: unit test on _x402-activate with a mocked settle that succeeds and an insertPendingActivation that throws live_activation_exists; assert (a) settle is not reached when a live activation already exists, and (b) when an orphan does occur, a durable payment_event/orphan row survives.
C-2 — Impairment: no on-chain totalClaimSupply cap + uncapped shared escrow → cross-epoch drain
Status: VERIFIED · contracts/vault/modules/CreatorOVaultCoreModule.sol:964-1015, contracts/vault/CreatorORecoveryEscrow.sol:24-33
mintImpairmentClaim(964) verifies the Merkle proof and blocks per-account double-mint, but never checks cumulative minted claims againstepoch.totalClaimSupply.- Payout
gross = (totalRecovered * claimUnits) / totalClaimSupply(line 1002). If the manager-proposed Merkle leaves sum to more thantotalClaimSupply, total payouts exceedtotalRecovered. CreatorORecoveryEscrow.claimRecovery(29-33) holds multiple epochs' assets in one ERC20 balance, incrementsclaimedByEpochAssetbut never enforcesclaimed <= recoveredbeforesafeTransfer. So one epoch's over-claim drains tokens reserved for other epochs.
Fix: enforce a cumulative cap in mintFromVault (claims contract) or check recoveredByEpochAsset[epochId][asset] >= claimedByEpochAsset[...] + amount in escrow.claimRecovery.
Regression test: Foundry test: propose a root whose leaves sum to 2 * totalClaimSupply, fund recovery for epoch A only, mint+claim epoch A to drain past recoveredByEpochAsset, assert a second epoch B claim does not lose funds (expect revert / cap).
C-3 — Impairment: stale root lifecycle after clearImpairmentTrip leaves a live claim surface on false-alarm epochs
Status: VERIFIED · CreatorOVaultCoreModule.sol:885-897, 964-995
clearImpairmentTrip(885) sets statusResolvedbut does not clearsnapshotRoot,totalClaimSupply, orrecoveryAsset. (ContrastclearImpairmentRootAfterChallengeat 932 which does zero them.)- Both
mintImpairmentClaim(972) andnotifyImpairmentRecovery(987) acceptResolved. So a manager can trip →proposeImpairmentRoot→clearImpairmentTrip(bypassing challenge/finalize), leaving a claimable root on a "false alarm" epoch. If a keeper later callsnotifyImpairmentRecovery, claimants extract value against a stale epoch.
Fix: clearImpairmentTrip should reject when a root was already proposed (force clearImpairmentRootAfterChallenge), or zero the root/supply/asset on clear; and/or restrict mintImpairmentClaim/notify to Finalized only.
Regression test: Foundry: trip → propose root → clear trip → assert mintImpairmentClaim reverts (root surface gone) and notifyImpairmentRecovery reverts on the cleared epoch.
C-2/C-3 contradict docs/reference/impairment-v1-disclosures.md (which implies finalization/challenge gating governs claims). These are new, not previously disclosed. Update disclosures or fix.
HIGH
H-1 — Impairment: notifyImpairmentRecovery inflates totalAssets() when recovery asset == creator coin; keeper has no amount limit
Status: VERIFIED · CreatorOVaultCoreModule.sol:985-995
IERC20(epoch.recoveryAsset).safeTransfer(escrow, amount)(991) is a raw transfer that does not decrement the vault's trackedcoinBalance.recoveryAssetis set arbitrarily atproposeImpairmentRootand can be the creator coin. Until the next_syncCoinBalance()(deposit/withdraw),totalAssets()overstates PPS, so depositors in that window mint fewer shares at an inflated price.notifyImpairmentRecoveryhas no zero-amount guard and no cap; a keeper can move arbitrary vault-owned creator coin into escrow for distribution to claim holders — a semi-trusted-role escalation.
Fix: if recoveryAsset == creatorCoin, route through the coin-balance accounting (decrement tracked balance), or recompute totalAssets from live balances; add an amount cap / source check.
Regression test: Foundry: set recoveryAsset = creator coin, notifyImpairmentRecovery(amount), assert totalAssets() does not double-count the transferred amount and a subsequent depositor's share price is unchanged.
H-2 — Deploy: "1-Click Deploy" button ignores dryRunBusy (live deploy during in-flight dry-run)
Status: VERIFIED · frontend/src/pages/deploy/DeployVault.tsx:4544-4547, 8314-8321
submit()early-returns onbusy || exportBusybut notdryRunBusy; the primary deploy button isdisabled={disabled || exportBusy}only. Dry-run gates itself but does not block the real gas-sponsored deploy.
Fix: add dryRunBusy to the submit() guard and the deploy button disabled.
Regression test: RTL test: set dryRunBusy=true, assert deploy button disabled and submit() is a no-op.
H-3 — Swap: auto-quote can abort an in-progress review/submit
Status: VERIFIED · frontend/src/pages/Swap.tsx:903-913, frontend/src/hooks/useSwapExecution.ts:1737-1740
- The debounced quote effect only skips on
txState === 'signing'andbusyRef === 'executeSwap'; it does not skip duringbusy === 'review'/'quote'.handleReviewTradeandhandleQuotesharequoteRunRef, so an auto-quote bumps the epoch and makes review bail mid-flight (if (runId !== quoteRunRef.current) return) — potentially after partial approval/sign work.handleReviewTradealso doesn't guard on generalbusy.
Fix: pause auto-quote when busy ∈ {review, quote} or txState === 'pending'; guard handleReviewTrade on busy.
Regression test: hook test: enter review, fire input-change debounce, assert no new quote epoch is started and review completes.
H-4 — CI: Semgrep documented as blocking but | tee masks its exit code
Status: VERIFIED · .github/workflows/security-scanning.yml:217-227
docker run ... semgrep ... | tee "$RUNNER_TEMP/semgrep.txt"with noset -o pipefail/shell: bash; the step takestee's exit (0). No follow-upexit 1on findings (only anif: always()summary). AGENTS.md and docs/audits/README.md claim blocking Semgrep — it likely is not.
Fix: add shell: bash + set -o pipefail, or drop the pipe and add an explicit findings-gate step.
H-5 — CI: gating guards not all wired into test.yml; committed code fails three guards
Status: VERIFIED · .github/workflows/test.yml, guard runs in §2
guard:frontend-boundariesis in no workflow; committed code has 5 violations.guard:server-core-boundaryviolations exist in committed code (7).guard:schemaflags committedapprovalFlow.ts.pnpm -C kpr typecheckis not in any workflow either.- Net:
maincan be green in CI while these guards would fail locally — the guards exist but don't gate.
Fix: add guard:frontend-boundaries, guard:server-core-boundary (confirm presence), guard:schema, and pnpm -C kpr typecheck to the api-tests gating job; fix the existing violations or allowlist them explicitly.
H-6 — CI: control-plane-stuck-scan.yml is broken (npm/lockfile mismatch) → chronic silent red
Status: VERIFIED · .github/workflows/control-plane-stuck-scan.yml:15-27
- Uses
cache: npm+cache-dependency-path: frontend/package-lock.jsonandnpm ci, butfrontend/is pnpm (nopackage-lock.json). The*/30cron likely fails at install every run — a stuck-control-plane detector that itself never runs. Operational blind spot.
Fix: rewrite to pnpm + frontend/pnpm-lock.yaml (mirror alfaclub-auth-health-monitor.yml).
MEDIUM
M-1 — Cron-reachable stores use plain getDb() (or a fallback that defeats getDbForCron)
Status: VERIFIED · multiple — server/_lib/zora/creatorMetricsSync.ts:542,589,848,1223 ((await getDbForCron()) ?? (await getDb()) — fallback fires exactly when the deadline-protected connect failed, then blocks with no deadline); lottery/amoeReplayStore.ts:273, amoeBurnRefund.ts:171, amoeLedgerPublisher.ts:968; alfaclub/chatTokenStore.ts (127,154,192,284,314,398), chatIngestStore.ts:82, and sibling AlfaClub cron-tick stores. Repo policy requires getDbForCron() on cron paths to avoid :00 pile-ups.
Fix: drop the ?? getDb() fallback in creatorMetricsSync.ts; migrate AMOE/AlfaClub cron-reachable stores to getDbForCron.
M-2 — x402 nonce unique index is dead (column never written)
Status: VERIFIED · supabase/migrations/20260419180000_creator_strategy_payment_paths.sql:39-43, _x402-activate.ts:240
- The
UNIQUE (payment_from, x402_authorization_nonce) WHERE x402_authorization_nonce IS NOT NULLindex is documented as replay protection, but the nonce is only written intometadataJSON (x402Nonce); the dedicated column is never populated, so the predicate never matches. Real replay protection currently rests on on-chain EIP-3009 nonce consumption +unique_payment_tx— so this is a defense-in-depth gap, not an active exploit. Fix: writex402_authorization_nonceinto its column in the same insert.
M-3 — isUniqueViolation over-broad fallback misclassifies constraint violations
Status: VERIFIED · server/_lib/creatorStrategy/activations.ts:193-200
- The
|| /creator_strategy_features_/ifallback returns true for any constraint on the table, so aunique_payment_tx(duplicate hash / replay) is reported aslive_activation_exists, misrouting ops/refund triage. Same risk ininsertStripeCheckoutActivation. Fix: match the specific constraint name only.
M-4 — Two profile lookups skip the alias cascade
Status: VERIFIED · server/_lib/agents/base-mcp/accountResolver.ts:73-76 (direct WHERE privy_user_id = ... AND merged_into_profile_id IS NULL, no privy_user_aliases consult → merged account resolves null, Base MCP sees no execution context); api/_handlers/auth/_privy.ts:168 (resolvePersistedSessionAddress direct lookup, no alias, no tombstone filter).
Fix: route both through listProfileIdsForPrivyUser / the alias cascade.
M-5 — runInTransaction silent atomicity drop + single-client starvation under POSTGRES_POOL_MAX=1
Status: VERIFIED (guard-rail) · server/_lib/db/postgres.ts:179-184,499
- When
cachedRawPoollacksconnect, it runsfn(db)with no transaction and no warning — callers likeexecuteProfileMergeInTransactionbelieve they're atomic. With pool max 1, a callback that internally callsgetDb()/pool.connect()would deadlock until timeout. No current callback does this (all threadtxDb), so it's a latent hazard. Fix: log/throw in the no-pool fallback (at least for merge); document the "threadtxDb, never callgetDb()inside" rule.
M-6 — Creator-strategy UI allows concurrent payments across features; no Stripe URL allowlist; no tx-hash validation
Status: VERIFIED · frontend/src/pages/CreatorStrategyFeatures.tsx:115-119,141,161-166
inflightFeatureis per-key, so Stripe on feature A + x402 on feature B can run concurrently (duplicate authorizations / conflicting wallet prompts).window.location.href = json.data.sessionUrlhas nohttps://checkout.stripe.com/allowlist. USDC path sends any non-emptywindow.promptstring with no^0x[0-9a-fA-F]{64}$check. Fix: global single in-flight payment; restrict redirect host; client-side tx-hash regex.
M-7 — CI: duplicate Cloudflare proxy deploy on every main push to proxy paths; inconsistent action pinning
Status: VERIFIED · cloudflare-alfaclub-proxy-deploy.yml + deploy-alfaclub-proxy.yml
- Both fire on the same paths/branch (one
wrangler-action@v3tag, onepnpm exec wranglerwith@v4tag actions) → double deploy + drift. Fix: consolidate to one workflow; pin by SHA.
M-8 — Stripe webhook reconstructs raw body via JSON.stringify → can drop legitimate paid activations
Status: VERIFIED (availability, not forgery) · frontend/api/_handlers/creator/strategy/stripe/_webhook.ts:54-70, frontend/api/[...path].ts:1-16
- The per-handler
config = { api: { bodyParser: false } }export is dead — the deployed function is the[...path].tscatch-all, which exports no such config. If the platform pre-parses the JSON body,readRawBodyfalls back toBuffer.from(JSON.stringify(req.body)); StripeconstructEventneeds byte-exact raw payload, so the HMAC fails and legitimatecheckout.session.completedevents are rejected (400). Fails closed — no forgery, but real$499Stripe activations can silently fail. Runtime-dependent (only breaks if the catch-all pre-parses for that content-type). Fix: disable body parsing at the dispatched function level (or special-case the Stripe webhook to read the raw stream before any parse) and verify against untouched bytes. Regression test: integration test posting a real Stripe test-mode signature through the catch-all; assert the event verifies and the activation row is written.
M-9 — CSP ships script-src 'unsafe-inline', negating XSS containment
Status: VERIFIED · frontend/vercel.json:195
script-src 'self' 'unsafe-inline' 'wasm-unsafe-eval' …; script-src-elem 'self' 'unsafe-inline' …. Any injected inline<script>/handler executes, so a single stored-XSS sink (creator names, Zora handles, chat content) becomes fully exploitable.object-src 'none',base-uri 'self',frame-ancestors 'self'are correctly set, so this is the main CSP weakness. Fix: move to nonce/hash-basedscript-src 'self' 'nonce-<per-request>'; drop'unsafe-inline'; keep'wasm-unsafe-eval'only if WASM needs it.
LOW
- L-1 —
pointsNULLsource_idunprotected for non-csw_linksources (latent; every current call site passes non-null).supabase/migrations/20260402100000_*:195-199,waitlistPoints.ts:206,225. - L-2 — Daily check-in points award non-atomic with check-in row; failed points insert is a permanent dead-end (6 pts).
lottery/lotteryAmoe.ts. - L-3 —
api/_handlers/zora/_metrics.ts:267-269runs three full-tableSUM()oncreator_coinsper request on a public endpoint (one-row results; seq-scan shaped on a growing table). - L-4 —
toParsableAmountvalidates viaNumber()beforeparseUnits(precision edge cases for very long fractional / scientific notation).useSwapExecution.ts:369-376. - L-5 —
openTelegramExternalLink/ Stripe redirect lack a scheme allowlist (current callers pass fixed URLs).telegram/telegramWebApp.ts:257-273. - L-6 — Swap submit is check-then-act (
busychecked, set later) — UI disables the button, but StrictMode/programmatic timing leaves a thin double-submit window. Add a ref mutex.useSwapExecution.ts:2838-2852. - L-7 — Deploy server-continue auto-resume effect re-fires whenever
busyflips false if a transient poll error left the session in localStorage.DeployVault.tsx:3320-3351. - L-8 —
gitleaks.tomlglobalbAlanciaga-master/exemption disables all detectors for that tree; tracked.env.backup/.env.productionare rule-scoped exempt fromgeneric-api-key. - L-9 — Several workflows lack explicit
permissions:blocks (rely on repo default).test.yml,docs.yml, others. - L-10 — docs/audits/README.md says Slither is "report-only" but
security-scanning.yml:283-298blocks on high-impact onmain. Doc drift. - L-11 — Non-constant-time secret comparisons: Solana route provisioner
header === \Bearer ${secret}`(deploy/_provisionSolanaRoute.ts:76-82) and Telegram webhookx-telegram-bot-api-secret-token!==(telegram/_webhook.runtime.ts). Both fail closed; usecrypto.timingSafeEquallikerequireKeeprApiKey`. - L-12 — Public-ish
VITE_THEGRAPH_API_KEY/VITE_ZORA_PUBLIC_API_KEYinlined into the client bundle (quota/billing risk only; no server secrets leak viaVITE_*). Confirm they are intentional rate-limited public keys or proxy server-side.
REFUTED / NOT A DEFECT
- Impaired strategy withdrawable / contributes to
totalAssets— REFUTED._getStrategyAssetsSafereturns 0 for impaired strategies and_withdrawFromStrategiesskips them entirely;finalizeImpairmentexcludes book value. The side-pocket exclusion works as designed. claimImpairmentRecoveryclaimable from cleared epoch — mostly mitigated: it lacks an explicit status check but fails safe (totalClaimSupply == 0or zerototalRecovered→NothingToClaim). The real exposure is C-3's stale-root path, not this function alone.- Merkle leaf/second-preimage — sound: leaf preimage is 96 bytes (
abi.encode(epochId, account, amount)) vs 64-byte internal nodes; proper domain separation. - Reentrancy on impairment functions — sound:
nonReentrantat the wrapper,SafeERC20in escrow. forge testfailure — environmental (offline RPC), not a code defect; the token in the URL is env-supplied, not committed.- Profile merge atomicity, keeper-job claim races, Telegram link-token single-use, AMOE replay index, Stripe entitlement gate, payment numeric handling, migration RLS posture — VERIFIED SOUND (see §VERIFIED in data-layer review).
5. Test-coverage gaps (by pyramid layer)
- Contracts (unit/invariant): impairment side-pocket is the largest gap. Missing: cross-epoch escrow drain (C-2), stale-root after clear (C-3), recovery-asset == creator-coin accounting (H-1),
totalClaimSupplymismatch (under/over). Add Foundry invariant tests for the impairment state machine. - API (integration): x402 failure ordering (C-1) has no test for "settle succeeds, insert fails." Cron
getDbForCronenforcement (M-1) is untested. No test asserts the x402 nonce column is written (M-2). - Frontend (component/hook): deploy
dryRunBusygating (H-2), auto-quote-vs-review interaction (H-3), concurrent cross-feature payment (M-6) lack tests. - CI (meta): no test that Semgrep actually fails on a seeded finding (H-4); no check that all canonical guards are wired into the gating job (H-5).
6. Suggested test commands (once fixes land)
# contracts
forge test --match-contract Impairment -vvv
forge test --match-test testCrossEpochEscrowDrain
# api / hooks
npx vitest run frontend/api/__tests__/creator-strategy-x402.test.ts
npx vitest run frontend/src/hooks/useSwapExecution.test.ts
# guards (wire these into test.yml)
pnpm -C frontend guard:schema && pnpm -C frontend guard:frontend-boundaries && pnpm -C frontend guard:server-core-boundary
pnpm -C kpr typecheck
7. CI/CD + security recommendations
- Fix Semgrep gate (
shell: bash+set -o pipefailor explicit findings step) — H-4. - Wire
guard:frontend-boundaries,guard:server-core-boundary,guard:schema,pnpm -C kpr typecheckinto the gatingtest.ymljob; fix the existing committed violations — H-5. - Rewrite
control-plane-stuck-scan.ymlto pnpm — H-6. - Consolidate the two Cloudflare deploy workflows; SHA-pin
wrangler-actionand remaining@v3/@v4actions; pin Semgrep/Slither/ACP CLI versions — M-7. - Add
pnpm -C kpr audittosecurity-scanning.yml; reconcile docs/audits/README.md with actual Slither/Semgrep behavior. - Tighten
gitleaks.tomlglobal allowlist; add explicitpermissions: contents: readto workflows missing it.
8. Dependency posture
- Root audit: 1 low. Frontend audit (
--prod): 6 moderate + 4 high — review the high advisories (the surfaced one wasGHSA-2gcr-mfcq-wcc3); confirm they are transitive/dev-reachable only or pin via the existingoverridesset. - Heavy but intentional override/patch surface (axios, undici, ws,
svix>uuid@10, patchedelliptic@6.6.1),onlyBuiltDependenciesallowlist, nopostinstall/preinstallin frontend — sane supply-chain posture. Dependabot covers/,/frontend,/kpr, Actions.
9. Quick wins (low risk, high value)
- Add
dryRunBusyto deploysubmit()+ buttondisabled(H-2) — one-line guard. - Pause auto-quote on
busy ∈ {review, quote}(H-3). - Fix
isUniqueViolationto match the specific constraint (M-3) — same module as the payment handlers. - Write
x402_authorization_nonceinto its column (M-2). - Fix
control-plane-stuck-scan.ymlinstall (H-6). - Add Stripe redirect host allowlist + tx-hash regex (M-6).
10. Release-readiness verdict
NOT READY for a clean release tag from the reviewed working tree.
- Blockers for a clean tag: dirty working tree with failing typecheck (6) and Vitest (78) — commit/clean first; repair CI gates (H-4, H-5, H-6) so green CI reflects enforced guards.
- Blockers for impairment / x402 paths: resolve or explicitly risk-accept (with updated disclosures) C-1, C-2, C-3, and H-1 before production deployment on those paths.
- Otherwise: web tier, auth model, identity/merge, keeper-job queue, and migration/RLS posture are in good shape. No anonymous unauthenticated fund-drain or RCE was found in the application tier.
Was this page helpful?