You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Fix retry API auth, secret-key exposure, spoofable rate limiting, and idempotency race condition
- Require auth (and admin for circuit-breaker reset) on all /api/v1/retry
routes, scoping attempts/transaction lookups to the caller's own
transactions (#914)
- Drop raw sourceSecretKey from POST /api/v1/retry/transaction; retries now
resubmit the caller's stored, owned transaction by hash instead (#915)
- Add TRUST_PROXY_HOPS config and app.set('trust proxy', ...), and derive
the rate limiter's client IP from req.ip instead of a manually parsed,
spoofable X-Forwarded-For header (#916)
- Add an atomic Redis SETNX claim to the idempotency middleware so
concurrent duplicate requests can't both bypass the cache check, and
replace silent Redis-failure/cache-write swallowing with logging plus an
idempotency_bypass_total metric (#917)
Copy file name to clipboardExpand all lines: backend/CONFIGURATION.md
+1Lines changed: 1 addition & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -33,6 +33,7 @@ Everything else has a safe default for local development.
33
33
|`CONFIG_VERSION`| integer | — |`1`| Config schema version. Must match the expected value or startup fails. |`1`|
34
34
|`CONFIG_WATCH`| boolean | — |`false`| Reload config when `.env*` files change (ignored in `test`). |`true`|
35
35
|`PORT`| integer | — |`3001`| TCP port the Express server listens on. |`3001`|
36
+
|`TRUST_PROXY_HOPS`| integer | — |`0`| Number of trusted reverse-proxy hops in front of this server. Passed to Express's `app.set('trust proxy', n)`, which controls how many `X-Forwarded-For` entries (from the right) are trusted when deriving `req.ip`. Set this to match your actual topology — an incorrect value either lets clients spoof their IP (too high) or rate-limits everyone as the proxy's IP (too low). `0` = no proxy, connect directly (default). `1` = single load balancer/reverse proxy in front. `2` = CDN + load balancer. |`1`|
Copy file name to clipboardExpand all lines: backend/src/monitoring/metrics.js
+2Lines changed: 2 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -15,6 +15,7 @@ const counters = {
15
15
payments_total: 0,
16
16
payments_failed_total: 0,
17
17
accounts_created_total: 0,
18
+
idempotency_bypass_total: 0,
18
19
};
19
20
20
21
// ── Business gauges ──────────────────────────────────────────────────────────
@@ -161,6 +162,7 @@ export function toPrometheusText() {
161
162
counter('payments_total','Total number of successful payments',counters.payments_total);
162
163
counter('payments_failed_total','Total number of failed payments',counters.payments_failed_total);
163
164
counter('accounts_created_total','Total number of accounts created',counters.accounts_created_total);
165
+
counter('idempotency_bypass_total','Total requests where idempotency protection was bypassed due to a Redis failure',counters.idempotency_bypass_total);
164
166
165
167
// Business gauges
166
168
gauge('active_streams','Number of currently active payment streams',gauges.active_streams);
0 commit comments