Files
nick-doc/09 - Audits/Full Codebase Audit - 2026-05-30.md
Siavash Sameni dceaf82934 audit: 2026-05-30 full-codebase audit — report, issues, docs, runbooks
Full-codebase-audit 2026-05-30 outputs:
- Audit report: 09 - Audits/Full Codebase Audit - 2026-05-30.md
- 81 issue files ISSUE-055..135 (decisions + 1 skipped no-brainer).
- Scanner docs from scratch (was zero): architecture, data model, API ref, payment
  flow, operations runbook + repo README.
- Doc-sync updates across API reference, data models, flows, design system.
- Secret Rotation Runbook (08 - Operations) for the exposed credentials.
- Reusable workflow guide (07 - Development) + .claude/workflows/full-codebase-audit.js.

Issues remain status:open intentionally — the code fixes are uncommitted-then-committed
working-tree changes per repo and aren't "resolved" until merged/deployed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30 18:48:04 +04:00

269 lines
26 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: Full Codebase Audit — 2026-05-30
tags: [audit, index, security, logic, performance]
created: 2026-05-30
status: open
---
# Full Codebase Audit — 2026-05-30
Full-system audit across all three repos (frontend, backend, scanner) triggered as a periodic health pass. 134 findings across security, logic, performance, and supply-chain dimensions. 49 no-brainers were applied automatically; 1 was skipped (requires new persistence layer); 80 decision items were queued for human review.
---
## Findings Summary by Severity and Dimension
| Severity | Security | Logic | Performance | Supply-Chain | Total |
|----------|----------|-------|-------------|--------------|-------|
| Critical | 3 | 2 | 0 | 1 | 6 |
| High | 18 | 12 | 8 | 4 | 42 |
| Medium | 14 | 12 | 8 | 6 | 40 |
| Low | 10 | 6 | 10 | 20 | 46 |
| **Total** | **45** | **32** | **26** | **31** | **134** |
### By Repo
| Repo | Findings | No-Brainers Applied | Skipped | Decision Items |
|------|----------|---------------------|---------|----------------|
| frontend | 49 | 18 (NB-1 NB-17, NB-49) | 0 | 31 (DEC-121, DEC-7480) |
| backend | 55 | 21 (NB-18 NB-38) | 1 (NB-27) | 33 (DEC-2256) |
| scanner | 30 | 10 (NB-39 NB-48) | 0 | 20 (DEC-5773) |
---
## Systemic Themes
Eight root-cause patterns cut across most findings. Addressing these themes eliminates whole clusters at once.
### 1. Missing Authorization on Payment and Admin Endpoints (Broken Access Control)
Routes are gated only by `authenticateToken`/`AuthGuard` with no role or ownership check. Payment status writes, exports, stats, user-payment listings, file deletion, delivery updates, offer selection, dispute evidence, and the entire admin UI tree all trust authentication alone. **Root fix:** a shared `requireAdmin` middleware + ownership-check helper + centralized status-transition validator applied consistently.
### 2. Payment Status State Machine Is Inconsistent and Corruptible
Non-enum statuses (`'released'`, `'funded'`) are written and silently dropped, the provider enum omits `'shkeeper'`, transition guards check fields never set (`escrowState:'funded'`), the transition map omits `'in_negotiation'`, and amount-mismatch is checked after side-effects commit. **Root cause:** schema enums and state machine drifted from the code that writes them.
### 3. Secrets Committed to the Repo and Baked into Images
Telegram bot token, Resend SMTP key, Google secret, JWT secret, admin password, Alchemy keys, and RN secrets appear across `.env.example`, `.env.development`, `.gitleaks.toml`, Dockerfiles, and committed scripts — and `.dockerignore` whitelists `.env.development` into prod images. **Root fix:** placeholder all committed files, remove env files from images, inject at runtime, rotate every exposed credential.
### 4. Test/Debug Bypasses Reachable in Production
Test-payment mode, `force-verify-user`, RN test-webhook signature bypass, the debug panel, and console-suppression hacks all rely on weak runtime `NODE_ENV` checks (or none). **Root fix:** gate on `NODE_ENV` at registration/build time; never honour bypass flags in production.
### 5. N+1 Queries, Unbounded Fan-Out, and Chatty Polling
Per-row DB lookups in `getPurchaseRequestsByBuyer` and `getReferrals`, unbounded notification/seller fan-out, redundant polling alongside sockets, full-collection loads, and per-intent HTTP fan-out in the scanner. **Root fix:** batch with `$in`/aggregation, bound concurrency, replace redundant polling with socket-driven or visibility-gated updates.
### 6. Float Math and Weak Randomness in Money/Crypto Paths
USDT wei conversion via IEEE-754 floats risks under-payment; verification codes use `Math.random` instead of a CSPRNG. **Root fix:** use `parseUnits` for token amounts and `crypto.randomInt` for codes (both already available in the codebase).
### 7. Unhardened Outbound HTTP and Webhook Handling (SSRF / OOM / Retry Leaks)
Scanner accepts arbitrary `callbackUrl` (SSRF), follows third-party `next`-URLs unvalidated, reads RPC/API bodies without size limits (OOM), overrides confirmation thresholds, and spawns unbounded sleeping retry goroutines. **Root fix:** URL allowlisting + private-range blocking at dial time, `io.LimitReader` caps, threshold floors, bounded persisted retry queues.
### 8. CI/CD Supply-Chain Hygiene Gaps
Floating/unpinned images, missing lint/type/test/audit gates on production and manual pipelines, privileged buildx, dual lockfiles, no `engines` pin, and untested manual builds. **Root fix:** digest-pin all CI images, enforce quality gate on every pipeline, unify lockfiles, add audit/vuln scanning.
---
## No-Brainers Applied (49 fixes)
All 49 no-brainers were applied. NB-13/NB-14: lockfile not regenerated (no `yarn install` run per instructions — leave uncommitted for human review). NB-7: requires backend to expose `GET /chat/unread-count` returning `{ data: { count: number } }`. NB-29: depends on DEC-32 outcome; applied `status:'completed'` as interim until enum decision is made.
| ID | Repo | Title | Files |
|----|------|-------|-------|
| NB-1 | frontend | USDT amount-to-wei uses floating-point arithmetic | `src/web3/context/action.ts` |
| NB-2 | frontend | Email verification logs full form data including password | `src/auth/view/jwt/jwt-verify-view.tsx` |
| NB-3 | frontend | Hardcoded Telegram bot ID fallback in widget loader | `src/auth/utils/telegram-login-widget.ts` |
| NB-4 | frontend | releasePayment returns fake success with hardcoded tx hash | `src/actions/payment.ts` |
| NB-5 | frontend | signUp/verifyEmailWithCode bypass StorageUtils.safeSet | `src/auth/context/jwt/action.ts` |
| NB-6 | frontend | Redundant 30s polling on buyer request details page | `src/sections/request/view/buyer/buyer-request-details-view.tsx` |
| NB-7 | frontend | getUnreadCount fetches entire conversation list | `src/actions/chat.ts`, `src/lib/axios.ts` |
| NB-8 | frontend | Debug new Error().stack capture on every step-change | `src/sections/request/view/buyer/buyer-request-details-view.tsx` |
| NB-9 | frontend | transformMessage logs two info calls per message | `src/actions/chat.ts` |
| NB-10 | frontend | Alchemy API keys hardcoded as Dockerfile ARG defaults | `Dockerfile` |
| NB-11 | frontend | Escrow wallet address hardcoded across multiple files | `src/web3/decentralizedPayment.ts`, `step-6-buyer-confirmed.tsx`, `manual-payout.tsx` |
| NB-12 | frontend | NEXT_PUBLIC_MAPBOX_API_KEY missing from Dockerfile ARGs/docs | `Dockerfile` |
| NB-13 | frontend | google-auth-library and @google-cloud/local-auth unused | `package.json` |
| NB-14 | frontend | @depay/widgets unused dependency | `package.json` |
| NB-15 | frontend | MockedUser (demo@minimals.cc) rendered in production nav | `src/layouts/components/nav-upgrade.tsx` |
| NB-16 | frontend | WEB3_PROVIDER_URL declared but never used | `src/global-config.ts` |
| NB-17 | frontend | google-oauth.ts.backup committed to source tree | `src/auth/services/google-oauth.ts.backup` |
| NB-18 | backend | Verification/reset codes logged to server console | `src/services/auth/authController.ts`, `src/services/delivery/DeliveryService.ts` |
| NB-19 | backend | Verification code uses Math.random() | `src/services/auth/authService.ts` |
| NB-20 | backend | Admin password hardcoded fallback in init-admin.ts | `src/infrastructure/database/init-admin.ts` |
| NB-21 | backend | force-verify-user route registered unconditionally | `src/services/auth/authRoutes.ts` |
| NB-22 | backend | getUserPayments queries non-existent 'userId' field | `src/services/payment/paymentService.ts` |
| NB-23 | backend | getPaymentStats sums object-typed amount field | `src/services/payment/paymentService.ts` |
| NB-24 | backend | GET /api/payment/export endpoints lack admin guard | `src/services/payment/paymentControllerRoutes.ts` |
| NB-25 | backend | getUserPayments route lacks ownership check (IDOR) | `src/services/payment/paymentControllerRoutes.ts` |
| NB-26 | backend | GET /api/files/stats missing admin guard | `src/services/file/fileRoutes.ts` |
| NB-28 | backend | updateDeliveryInfo does not enforce seller ownership | `src/services/marketplace/marketplaceController.ts` |
| NB-29 | backend | payout/confirm and release/confirm set non-enum 'released' status | `src/services/payment/requestNetwork/requestNetworkRoutes.ts` |
| NB-30 | backend | N+1 per-request Payment lookup in getPurchaseRequestsByBuyer | `src/services/marketplace/PurchaseRequestService.ts` |
| NB-31 | backend | Full unpaginated load in getPayments admin endpoint | `src/services/marketplace/marketplaceController.ts` |
| NB-32 | backend | 13 sequential countDocuments in getCollectionStats | `src/services/admin/dataCleanupService.ts` |
| NB-33 | backend | Real credentials committed in tracked .env.example | `.env.example` |
| NB-34 | backend | Dockerfile.dev runs --frozen-lockfile before copying yarn.lock | `Dockerfile.dev` |
| NB-35 | backend | Deprecated npm 'crypto' shim in production deps | `package.json` |
| NB-36 | backend | body-parser redundant with Express 5 | `package.json` |
| NB-37 | backend | manual.yml CI missing typecheck gate | `.woodpecker/manual.yml` |
| NB-38 | backend | No engines field / .nvmrc for Node version | `package.json`, `.nvmrc` |
| NB-39 | scanner | Scanner Dockerfile runs as root (no USER) | `Dockerfile` |
| NB-40 | scanner | cleanup.yml uses alpine:latest | `.woodpecker/cleanup.yml` |
| NB-41 | scanner | scanner buildx plugin not pinned | `.woodpecker/development.yml`, `.woodpecker/manual.yml`, `.woodpecker/production.yml` |
| NB-42 | scanner | Scanner RPC/API bodies read without size limit | `chain.go`, `tron_chain.go`, `ton_chain.go` |
| NB-43 | scanner | Scanner manual.yml has no test step | `.woodpecker/manual.yml` |
| NB-44 | scanner | No govulncheck/gosec in scanner CI | `.woodpecker/development.yml`, `.woodpecker/production.yml` |
| NB-45 | scanner | No RPC_TRON/RPC_TON override env vars | `config.go` |
| NB-46 | scanner | EVM scan lag warning uses reorgBuf-adjusted checkpoint | `chain.go` |
| NB-47 | scanner | handleScannerStatus loads full intent rows to count pending | `api.go`, `intent.go` |
| NB-48 | scanner | SQLite no connection pool limit set | `intent.go` |
| NB-49 | frontend | Admin route polling paused when tab hidden | `payments-awaiting-confirmation-list-view.tsx` |
### Skipped No-Brainers
| ID | Reason | Issue Filed |
|----|--------|-------------|
| NB-27 (DELETE /api/files/delete ownership check) | `fileService.deleteFile()` is a pure filesystem path operation with no DB ownership record — no `File` model, no `createdBy`/`owner` field stored anywhere. Adding an ownership check requires creating a new persistence layer, which is a larger-than-mechanical change. | [[ISSUE-055-delete-api-files-delete-has-no-ownership-check-requires-new-pe|ISSUE-055]] |
---
## Decision Queue (80 items)
These items require human judgment before implementation. Each has a corresponding issue file.
### Critical
| Issue | Title | Repo | Recommendation |
|-------|-------|------|----------------|
| [[ISSUE-056-backend-verifypayment-and-paymentcallback-routes-unauthenticat|ISSUE-056]] | verifyPayment and paymentCallback routes unauthenticated | backend | Auth + HMAC on callback; remove isWeb3Payment bypass |
### High
| Issue | Title | Repo |
|-------|-------|------|
| [[ISSUE-057-frontend-admin-ui-routes-lack-role-based-authorization-guard|ISSUE-057]] | Admin UI routes lack role-based authorization guard | frontend |
| [[ISSUE-058-frontend-test-payment-mode-enablable-in-production-via-env-var|ISSUE-058]] | Test payment mode enablable in production via NEXT_PUBLIC env var | frontend |
| [[ISSUE-059-frontend-auth-provider-clears-tokens-on-any-non-403-error|ISSUE-059]] | Auth provider clears tokens on any non-403 error including network failures | frontend |
| [[ISSUE-060-frontend-contacts-popover-reads-userid-from-non-existent-local|ISSUE-060]] | contacts-popover reads userId from non-existent localStorage 'user' key | frontend |
| [[ISSUE-061-frontend-socket-context-helpers-accumulate-listeners-without-d|ISSUE-061]] | Socket context helpers accumulate listeners without dedup | frontend |
| [[ISSUE-062-backend-payment-update-routes-lack-ownership-role-guards|ISSUE-062]] | Backend payment update routes lack ownership/role guards | backend |
| [[ISSUE-063-backend-legacy-marketplace-patch-payments-id-lets-any-user-set|ISSUE-063]] | Legacy marketplace PATCH /payments/:id lets buyer/seller set any status | backend |
| [[ISSUE-064-backend-request-network-allow-test-webhooks-bypasses-signature|ISSUE-064]] | REQUEST_NETWORK_ALLOW_TEST_WEBHOOKS bypasses signature verification | backend |
| [[ISSUE-065-backend-rn-webhook-advances-purchaserequest-to-non-existent-fu|ISSUE-065]] | RN webhook advances PurchaseRequest to non-existent 'funded' status | backend |
| [[ISSUE-066-backend-payout-and-release-confirm-set-non-enum-status|ISSUE-066]] | payout/confirm and release/confirm set non-enum status 'released' | backend |
| [[ISSUE-067-backend-amount-mismatch-check-runs-after-payment-saved-and-offe|ISSUE-067]] | amount-mismatch check runs after payment saved and offers accepted | backend |
| [[ISSUE-068-backend-datacleanuservice-deletes-payments-without-provider-sco|ISSUE-068]] | dataCleanupService deletes Payments without provider scoping | backend |
| [[ISSUE-069-backend-cleanupoldpendingpayments-deletes-pending-rn-payments-m|ISSUE-069]] | cleanupOldPendingPayments deletes pending RN payments mid-flow | backend |
| [[ISSUE-070-backend-notifyallsellersaboutnewrequest-unbounded-fan-out|ISSUE-070]] | notifyAllSellersAboutNewRequest unbounded fan-out | backend |
| [[ISSUE-071-backend-getreferrals-n-plus-1-purchaserequest-and-pointtransac|ISSUE-071]] | getReferrals N+1 (PurchaseRequest + PointTransaction per referral) | backend |
| [[ISSUE-072-backend-chat-messages-stored-as-embedded-array-unbounded-growth|ISSUE-072]] | Chat messages stored as embedded array (unbounded document growth) | backend |
| [[ISSUE-073-backend-payment-provider-enum-missing-shkeeper|ISSUE-073]] | Payment provider enum missing 'shkeeper' | backend |
| [[ISSUE-074-backend-env-development-committed-with-live-telegram-and-smtp-s|ISSUE-074]] | Backend Telegram bot token + SMTP key committed in .env.development | backend |
| [[ISSUE-075-backend-dockerignore-whitelists-env-development-into-prod-image|ISSUE-075]] | .dockerignore whitelists .env.development into prod image | backend |
| [[ISSUE-076-scanner-ssrf-via-unvalidated-callbackurl|ISSUE-076]] | Scanner: SSRF via unvalidated callbackUrl | scanner |
| [[ISSUE-077-scanner-caller-can-override-confirmation-threshold-down-to-1|ISSUE-077]] | Scanner: caller can override confirmation threshold down to 1 | scanner |
| [[ISSUE-078-scanner-idempotency-path-ignores-mismatched-parameters|ISSUE-078]] | Scanner: idempotency path ignores mismatched parameters | scanner |
| [[ISSUE-079-frontend-telegram-bot-token-committed-in-gitleaks-toml-allowli|ISSUE-079]] | Frontend: Telegram bot token committed in .gitleaks.toml allowlist | frontend |
### Medium
| Issue | Title | Repo |
|-------|-------|------|
| [[ISSUE-080-frontend-open-redirect-via-unvalidated-returnto-in-guestguard|ISSUE-080]] | Open redirect via unvalidated returnTo in GuestGuard | frontend |
| [[ISSUE-081-frontend-tokens-stored-in-localstorage-xss-accessible|ISSUE-081]] | Tokens stored in localStorage (XSS-accessible) | frontend |
| [[ISSUE-082-frontend-wallet-ownership-signature-verification-is-a-no-op|ISSUE-082]] | Wallet ownership signature verification is a no-op on frontend | frontend |
| [[ISSUE-083-frontend-no-content-security-policy-header-in-next-config|ISSUE-083]] | No Content-Security-Policy header in Next.js config | frontend |
| [[ISSUE-084-frontend-console-error-warn-suppression-masks-prod-errors|ISSUE-084]] | console.error/warn suppression masks prod errors | frontend |
| [[ISSUE-085-frontend-token-refresh-queue-dispatches-with-undefined-authori|ISSUE-085]] | Token refresh queue dispatches with undefined Authorization | frontend |
| [[ISSUE-086-frontend-paymentdetailsview-status-dropdown-exposed-to-all-use|ISSUE-086]] | PaymentDetailsView status dropdown exposed to all users | frontend |
| [[ISSUE-087-frontend-getpaymentstatus-and-checkpaymentstatus-hit-different|ISSUE-087]] | getPaymentStatus and checkPaymentStatus hit different endpoints | frontend |
| [[ISSUE-088-frontend-adminwalletpayout-falls-back-to-literal-admin-string|ISSUE-088]] | adminWalletPayout falls back to literal 'admin' adminUserId | frontend |
| [[ISSUE-089-frontend-admin-payments-awaiting-confirmation-polls-every-12s|ISSUE-089]] | Admin payments-awaiting-confirmation polls every 12s unconditionally | frontend |
| [[ISSUE-090-frontend-chat-views-re-fetch-full-conversation-on-every-new-me|ISSUE-090]] | Chat views re-fetch full conversation on every new-message event | frontend |
| [[ISSUE-091-frontend-dual-socket-connections-socketprovider-and-socketserv|ISSUE-091]] | Dual socket connections (SocketProvider + socketService singleton) | frontend |
| [[ISSUE-092-backend-jwt-refresh-and-access-tokens-share-same-secret|ISSUE-092]] | JWT refresh and access tokens share the same secret; middleware skips type check | backend |
| [[ISSUE-093-backend-addevidence-no-participant-ownership-check-on-disputes|ISSUE-093]] | addEvidence: no participant ownership check on disputes | backend |
| [[ISSUE-094-backend-selectoffer-does-not-verify-buyer-owns-purchase-request|ISSUE-094]] | selectOffer does not verify buyer owns the purchase request | backend |
| [[ISSUE-095-backend-getuserstats-no-ownership-admin-check-idor|ISSUE-095]] | getUserStats: no ownership/admin check (IDOR) | backend |
| [[ISSUE-096-backend-validatestatustransition-requires-escrowstate-funded-n|ISSUE-096]] | validateStatusTransition requires escrowState 'funded' never set on completed payments | backend |
| [[ISSUE-097-backend-validtransitions-map-missing-in-negotiation-key|ISSUE-097]] | validTransitions map missing 'in_negotiation' key | backend |
| [[ISSUE-098-backend-in-memory-seendeliveryids-resets-on-restart|ISSUE-098]] | validateStatusTransition: in-memory seenDeliveryIds resets on restart | backend |
| [[ISSUE-099-backend-on-demand-rn-reconciliation-in-getpaymentbyid-can-race|ISSUE-099]] | On-demand RN reconciliation in getPaymentById can race | backend |
| [[ISSUE-100-backend-updatepurchaserequest-does-findbyid-then-findbyidandupd|ISSUE-100]] | updatePurchaseRequest does findById then findByIdAndUpdate | backend |
| [[ISSUE-101-backend-config-loads-env-development-unconditionally|ISSUE-101]] | Backend config loads .env.development unconditionally | backend |
| [[ISSUE-102-backend-14-high-severity-npm-vulns-no-audit-step-in-ci|ISSUE-102]] | 14 high-severity npm vulns, no audit step in CI | backend |
| [[ISSUE-103-backend-react-react-dom-in-backend-production-dependencies|ISSUE-103]] | react/react-dom in backend production dependencies | backend |
| [[ISSUE-104-backend-bcrypt-native-addon-alongside-used-bcryptjs|ISSUE-104]] | bcrypt native addon present alongside used bcryptjs | backend |
| [[ISSUE-105-backend-no-startup-validation-of-required-env-vars|ISSUE-105]] | No startup validation of required env vars | backend |
| [[ISSUE-106-backend-dual-lockfiles-yarn-lock-and-package-lock-json-diverge|ISSUE-106]] | Dual lockfiles (yarn.lock + package-lock.json) diverge | backend |
| [[ISSUE-107-scanner-tronGrid-pagination-next-url-used-unvalidated|ISSUE-107]] | Scanner: TronGrid pagination next-URL used unvalidated | scanner |
| [[ISSUE-108-scanner-unauthenticated-startup-when-scanner-api-key-unset|ISSUE-108]] | Scanner: unauthenticated startup when SCANNER_API_KEY unset | scanner |
| [[ISSUE-109-scanner-tron-lag-metric-reported-in-ms-not-blocks|ISSUE-109]] | Scanner: Tron lag metric reported in ms, not blocks | scanner |
| [[ISSUE-110-scanner-ton-worker-on-http-fan-out-per-scan-cycle|ISSUE-110]] | Scanner: TON worker O(N) HTTP fan-out per scan cycle | scanner |
| [[ISSUE-111-scanner-deliverwebhook-goroutines-use-blocking-time-sleep|ISSUE-111]] | Scanner: deliverWebhook goroutines use blocking time.Sleep (leak risk) | scanner |
| [[ISSUE-112-scanner-unbounded-goroutine-fan-out-for-webhook-retries|ISSUE-112]] | Scanner: unbounded goroutine fan-out for webhook retries | scanner |
| [[ISSUE-113-scanner-rpc-response-bodies-read-without-size-limit-oom|ISSUE-113]] | Scanner/backend: RPC response bodies read without size limit (OOM) | scanner |
| [[ISSUE-114-frontend-walletconnect-google-client-ids-hardcoded-dockerfile|ISSUE-114]] | Frontend: WalletConnect/Google client IDs hardcoded as Dockerfile ARG defaults | frontend |
| [[ISSUE-115-frontend-real-plaintext-credentials-in-committed-scripts|ISSUE-115]] | Frontend: real plaintext credentials in committed scripts | frontend |
| [[ISSUE-116-frontend-backend-scanner-ci-images-not-pinned-to-digests|ISSUE-116]] | Frontend/scanner/backend: CI images not pinned to digests | frontend |
| [[ISSUE-117-frontend-backend-scanner-production-manual-ci-pipelines-lack-g|ISSUE-117]] | Frontend/scanner/backend: production/manual CI pipelines lack lint/type/test/audit gates | frontend |
### Low
| Issue | Title | Repo |
|-------|-------|------|
| [[ISSUE-118-frontend-notification-title-rendered-via-dangerouslysetinnerht|ISSUE-118]] | Notification title rendered via dangerouslySetInnerHTML | frontend |
| [[ISSUE-119-frontend-telegramdebugpanel-exposed-in-production-via-url-flag|ISSUE-119]] | TelegramDebugPanel exposed in production via URL/localStorage flag | frontend |
| [[ISSUE-120-frontend-50ms-setinterval-console-suppression-script-in-root-l|ISSUE-120]] | 50ms setInterval console-suppression script in root layout | frontend |
| [[ISSUE-121-frontend-transferfunds-and-createpayment-post-to-same-endpoint|ISSUE-121]] | transferFunds and createPayment POST to the same endpoint | frontend |
| [[ISSUE-122-backend-missing-compound-index-for-seller-visibility-purchase-r|ISSUE-122]] | Missing compound index for seller-visibility purchase-request query | backend |
| [[ISSUE-123-backend-notification-unread-count-chatty-db-access|ISSUE-123]] | Notification unread-count chatty DB access | backend |
| [[ISSUE-124-backend-per-seller-socket-emit-loop-in-updatepurchaserequeststatu|ISSUE-124]] | Per-seller socket emit loop in updatePurchaseRequestStatus | backend |
| [[ISSUE-125-backend-getcategorypath-unbounded-sequential-findbyid-loop|ISSUE-125]] | getCategoryPath unbounded sequential findById loop | backend |
| [[ISSUE-126-backend-getuserpoints-writes-full-user-document-on-read|ISSUE-126]] | getUserPoints writes full User document on read when fields missing | backend |
| [[ISSUE-127-scanner-get-intents-id-exposes-salt-and-callbackurl|ISSUE-127]] | Scanner: GET /intents/:id exposes salt and callbackUrl | scanner |
| [[ISSUE-128-scanner-post-intents-returns-200-instead-of-201|ISSUE-128]] | Scanner: POST /intents returns 200 instead of 201 | scanner |
| [[ISSUE-129-scanner-ton-processTransfer-doesnt-verify-jettonmasteraddress|ISSUE-129]] | Scanner: TON processTransfer doesn't verify JettonMasterAddress vs intent.TokenAddress | scanner |
| [[ISSUE-130-scanner-config-getchaingettokengetrpc-on-linear-scans|ISSUE-130]] | Scanner: Config.GetChain/GetToken/GetRPC O(N) linear scans | scanner |
| [[ISSUE-131-scanner-tron-ton-workers-dont-share-http-transport|ISSUE-131]] | Scanner: Tron/TON workers don't share HTTP transport | scanner |
| [[ISSUE-132-scanner-evm-checkpoint-saved-every-2000-block-chunk|ISSUE-132]] | Scanner: EVM checkpoint saved every 2000-block chunk | scanner |
| [[ISSUE-133-scanner-ci-buildx-steps-run-privileged-true|ISSUE-133]] | Scanner: CI buildx steps run privileged: true | scanner |
| [[ISSUE-134-frontend-sentry-source-map-upload-configured-but-no-auth-token|ISSUE-134]] | Frontend: Sentry source-map upload configured but no auth token injected | frontend |
| [[ISSUE-135-backend-uploads-directory-served-without-authentication|ISSUE-135]] | Backend uploads directory served without authentication | backend |
---
## Documentation Gaps Identified (Doc Sync)
The following gaps were identified but not filled during this audit pass. They should be tracked as separate doc tasks:
- **Frontend:** Admin dashboard sub-pages (confirmation-thresholds, networks, payments-awaiting-confirmation, trezor) missing from Admin API doc.
- **Frontend:** Trezor registration and break-glass UI (commit c9ce345) not reflected in Trezor API or Trezor Safekeeping Flow docs.
- **Frontend:** Cloudflare Turnstile/CAPTCHA behavior (3 failed logins) not documented in Authentication Flow or Authentication API docs.
- **Frontend:** AMN Pay Scanner lag column and per-row probe button have no dedicated flow or operations doc.
- **Frontend:** Telegram startup notification (TG_NOTIFY_BOT_TOKEN) not in Operations/Environment Variables doc.
- **Frontend:** Amaneh UI variant toggle — state key and exact behavior not fully described in Settings & Theming.
- **Frontend:** `productLink` made truly optional; `deliveryType` required marker dropped — Purchase Request Flow wizard narrative needs update.
- **Backend:** Sweep signer strategy (PermitPullSweepSigner + GasTopUpSweepSigner) has no operations runbook.
- **Backend:** Native token sweep (BNB/ETH to derived destinations) not reflected in Payment API or sweep operations runbook.
- **Backend:** AML screening (OFAC SDN provider) has no dedicated flow doc covering when screening fires, seller opt-in, fee deduction.
- **Backend:** GET /api/health response field names not verified against live `healthCheckService` output.
- **Backend:** RequestTemplate budget currency restriction (USDT/USDC only) not reflected in Marketplace API or RequestTemplate model docs.
- **Backend:** Sweep integration tests (Anvil + INTEGRATION_TEST=1) not covered in Testing.md.
- **Backend:** Telegram startup notification (app startup `tgNotify`) not in Monitoring.md.
- **Backend:** AMN Pay Scanner adapter internals (amnPayAdapter, amnScannerWebhookRoutes) have no doc.
- **Backend:** New env vars (OFAC_SDN_URL, TURNSTILE_SECRET_KEY, TURNSTILE_SITE_KEY, AMN_SCANNER_URL, AMN_SCANNER_WEBHOOK_SECRET) may not be in Environment Variables doc.
- **Backend:** Seller Offer Flow does not reflect selectedOfferId persistence fix and atomic offer rejection on payment.
- **Backend:** ISSUE-021 (POST /api/marketplace/offers/:id/withdraw) should be marked resolved (implemented in commit 3e47713).
- **Scanner:** No doc for CI pipeline structure (.woodpecker/ steps, secrets, image push flow).
- **Scanner:** No doc for test suite (chain_validate_test.go / reference_test.go / tron_chain_test.go) and how to extend it.
- **Scanner:** Multi-chain reorg edge cases and exact ReorgBuffer formula not in troubleshooting doc.
- **Scanner:** TON scaling limitation (O(pending intents) API calls per cycle) noted but no mitigation/batching design documented.
- **Scanner:** RN proxy address discrepancy in supported-chains.json (ETH v0.1.0 vs v0.2.0) not documented.
---
## References
- [[Security Audit - 2026-05-24]]
- [[Logic Audit - 2026-05-24]]
- [[Performance Audit - 2026-05-24]]
- [[Doc vs Code Audit Report - 2026-05-29]]