Security hardening: tenant isolation, slippage protection, sliding-window rate limiting, withdrawal allowlist#535
Merged
Smartdevs17 merged 1 commit intoJun 26, 2026
Conversation
…ow rate limiting, withdrawal allowlist Implements four security hardening features: - Cross-tenant data isolation: a Prisma client extension enforces tenant boundaries at query time (throws on cross-tenant access instead of silently leaking), backed by a static AST scanner that flags queries on tenant-scoped models missing a tenantId filter, plus a CI workflow that runs both on every PR touching routes/services/repositories/schema. - Slippage protection: a pre-execution swap simulation service estimates expected output, detects sandwich-attack price signatures, and computes a hard minAmountOut floor; a new SlippageGuard.sol contract enforces that floor on-chain regardless of what the off-chain simulation predicted. - Sliding-window rate limiting: a true sliding-window-log limiter with per-endpoint configuration and graduated warning/throttle/block penalties, layered on top of the existing token-bucket limiter. - Withdrawal allowlist: per-wallet allowlisted withdrawal addresses, with multi-signature approval required for non-allowlisted destinations and hourly/daily velocity checks on withdrawal amount and count. Closes Smartdevs17#522, Smartdevs17#521, Smartdevs17#520, Smartdevs17#519
|
@Akanimoh12 is attempting to deploy a commit to the smartdevs17's projects Team on Vercel. A member of the Team first needs to authorize it. |
|
@Akanimoh12 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Four independent security hardening features, implemented together:
backend/src/security/tenant-isolation/guard.ts) binds anAsyncLocalStorage-scoped tenant context and throwsCrossTenantAccessErrorif any query against a tenant-scoped model targets a different tenant, or omits a tenant filter on bulk operations, while a tenant context is active. A companion static scanner (scan.ts) walksroutes/,services/, andrepositories/with the TypeScript AST and flags Prisma calls on tenant-scoped models with notenantIdin theirwhereclause — it already surfaces a real gap insandbox-db.ts(getAccountById/getAccountByWalletAddressquery by raw id with no tenant filter). Both the scan and a runtime test suite run in a new CI workflow (.github/workflows/tenant-isolation.yml) gated on changes to routes/services/repositories/schema.backend/src/services/slippage-protection.tssimulates expected swap output from a quoted price and recent price history, scores sandwich-attack risk (front-run price spikes, sub-second tick bursts, oversized trades relative to pool liquidity, quote/market divergence), and computes a hardminAmountOutfloor.contracts/evm/contracts/SlippageGuard.solenforces that same floor on-chain —executeGuardedSettlementreverts if realized output falls belowminAmountOutor the quote has expired, independent of what the off-chain simulation predicted, and clamps any requested tolerance to a 5% hard cap.backend/src/middleware/sliding-window-rate-limit.tsadds a true sliding-window-log limiter (Redis sorted-set backed, with in-memory fallback) layered on top of the existing token-bucket limiter. Replaces fixed-window boundary bursting with smooth enforcement, adds per-endpoint configs (withdrawals, auth, invoice get tighter windows than the global default), graduated warning → throttle → block penalties, and IP+User-Agent fingerprinting for anonymous clients so they can't evade limits by dropping headers.backend/src/services/withdrawal-allowlist.tsandbackend/src/routes/withdrawals.tslet each wallet configure an allowlist of withdrawal destinations. Withdrawals to allowlisted addresses can auto-approve; withdrawals to anywhere else require reaching a configurable multi-signature approval threshold from an authorized approver set. Every withdrawal, regardless of destination, is checked against hourly/daily amount and hourly count velocity limits before it's allowed to proceed.Test plan
cd backend && npm install && npm run db:generatenpm run tenant-isolation:scan— static scan reports the existingsandbox-db.tsfinding, exits non-zero only on high-severity violationsnpm test— covers sliding-window rate limiting, tenant isolation guard + scanner, withdrawal allowlist lifecycle, and slippage simulationcd contracts/evm && npm install && npm test— coversSlippageGuard.sol(tolerance clamping, slippage floor enforcement, quote expiry, zero-amount guard)POST /api/v1/swap/simulateandPOST /api/v1/withdrawals/:walletId/requestsagainst a running backendCloses #522
Closes #521
Closes #520
Closes #519