Skip to content

πŸ›‘οΈ Sentinel: add dual rate limiting to authentication server actions - #101

Open
projectamazonph wants to merge 1 commit into
mainfrom
fix/dual-rate-limiting-16242830136162380155
Open

πŸ›‘οΈ Sentinel: add dual rate limiting to authentication server actions#101
projectamazonph wants to merge 1 commit into
mainfrom
fix/dual-rate-limiting-16242830136162380155

Conversation

@projectamazonph

@projectamazonph projectamazonph commented Aug 1, 2026

Copy link
Copy Markdown
Owner

πŸ›‘οΈ Sentinel: [security improvement]

🚨 Severity

MEDIUM

πŸ’‘ Vulnerability

Prior to this change, the sign-up and sign-in Server Actions only rate-limited incoming requests by the targeted lowercase email. This left the application vulnerable to distributed credential-stuffing or brute-force attacks where many different emails are targeted from a single client IP (or small set of client IPs) without hitting the single-email rate limits.

🎯 Impact

Attackers could execute high-volume password-spraying or credentials-stuffing attacks, potentially compromising user accounts while remaining undetected by the target-based rate limiter.

πŸ”§ Fix

  1. Implemented rateLimitDual inside src/lib/rate-limit.ts which uses next/headers to safely extract client IP (supporting x-forwarded-for and x-real-ip with safe indexing and error-handling fallbacks) and performs sliding-window rate limiting on both the target email and the client IP address.
  2. Updated signUpAction and signInAction in src/app/actions/auth.ts to use rateLimitDual.
  3. Added a dedicated and robust unit test suite in src/lib/__tests__/rate-limit.test.ts to test all scenarios including header fallbacks, multi-IP parsing, Map cleanup, and timing lockout calculations, achieving 100% line coverage for the module.
  4. Documented learnings in .jules/sentinel.md.

βœ… Verification

  1. Running pnpm test executes and passes all 223 unit/integration tests successfully.
  2. Running pnpm test:coverage reports 100% line, statement, and function coverage on src/lib/rate-limit.ts.
  3. Running pnpm typecheck and pnpm lint yields zero errors.

PR created automatically by Jules for task 16242830136162380155 started by @projectamazonph

Summary by CodeRabbit

  • Security Enhancements
    • Added layered rate limiting for sign-up and sign-in attempts.
    • Limits are applied by account target and client IP address to better mitigate automated credential-stuffing attacks.
    • Authentication behavior remains unchanged when limits are exceeded.
  • Tests
    • Added comprehensive coverage for rate-limit thresholds, expiration, retry timing, key handling, IP detection, and fallback behavior.

Co-authored-by: projectamazonph <286085559+projectamazonph@users.noreply.github.com>
Copilot AI review requested due to automatic review settings August 1, 2026 12:56
@google-labs-jules

Copy link
Copy Markdown
Contributor

πŸ‘‹ Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a πŸ‘€ emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown

Review Change Stack

πŸ“ Walkthrough

Walkthrough

Changes

Authentication rate limiting

Layer / File(s) Summary
Dual rate-limit implementation and coverage
src/lib/rate-limit.ts, src/lib/__tests__/rate-limit.test.ts, src/__tests__/setup.ts
Added rateLimitDual with normalized target keys, client IP extraction, fallback handling, and doubled IP limits. Added tests for limiting behavior and failures.
Signup and signin integration
src/app/actions/auth.ts, .jules/sentinel.md
Signup and signin now use rateLimitDual with action and email arguments. The Sentinel Journal records the dual-limit approach.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant AuthActions
  participant rateLimitDual
  participant headers
  participant RateLimitStore
  AuthActions->>rateLimitDual: submit signup or signin action and email
  rateLimitDual->>RateLimitStore: enforce normalized target limit
  rateLimitDual->>headers: read client IP headers
  headers-->>rateLimitDual: return IP or unavailable
  rateLimitDual->>RateLimitStore: enforce doubled IP limit
  rateLimitDual-->>AuthActions: return allowance or denial
Loading

Possibly related PRs

  • projectamazonph/amph-v2#73: Implements dual IP/email rate limiting in the same authentication actions with related mocks and tests.
  • projectamazonph/amph-v2#79: Implements the same dual rate-limiting changes across authentication, utilities, tests, and documentation.
  • projectamazonph/amph-v2#97: Modifies the same authentication actions and rateLimitDual helper for dual IP-and-email limiting.

Suggested reviewers: copilot

πŸš₯ Pre-merge checks | βœ… 5
βœ… Passed checks (5 passed)
Check name Status Explanation
Description Check βœ… Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check βœ… Passed The title clearly and concisely describes the main change: dual rate limiting for authentication server actions.
Docstring Coverage βœ… Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check βœ… Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check βœ… Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
πŸ“ Generate docstrings
  • Create stacked PR
  • Commit on current branch
πŸ§ͺ Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/dual-rate-limiting-16242830136162380155

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

πŸ”§ ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❀️ Share

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR strengthens authentication throttling by introducing dual-layer rate limiting (per target email and per client IP) and wiring it into the sign-up and sign-in server actions to better mitigate credential stuffing and brute-force attempts.

Changes:

  • Added rateLimitDual() in src/lib/rate-limit.ts, combining target-key and IP-based sliding-window limits.
  • Updated signUpAction and signInAction to use rateLimitDual() instead of target-only limiting.
  • Added a unit test suite for the rate limiter and updated Vitest setup mocks; documented the security learning in .jules/sentinel.md.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/lib/rate-limit.ts Adds dual-layer rate limiting using request headers for IP extraction.
src/lib/tests/rate-limit.test.ts Introduces unit tests covering the sliding-window limiter and dual limiter behavior.
src/app/actions/auth.ts Switches auth server actions to use the new dual limiter.
src/tests/setup.ts Extends the next/headers mock to include headers() for tests.
.jules/sentinel.md Documents the security finding and the applied mitigation approach.

πŸ’‘ Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/lib/rate-limit.ts
Comment on lines +74 to +81
const heads = await headers();
const xff = heads.get('x-forwarded-for');
const ip = (xff ? xff.split(',')[0]?.trim() : null) ?? heads.get('x-real-ip') ?? 'unknown';
const ipPrefixed = `${actionType}:ip:${ip}`;
const ipResult = rateLimit(ipPrefixed, limit * 2, windowMs);
if (!ipResult.allowed) {
return ipResult;
}
Comment on lines +153 to +163
it('falls back to unknown if no IP headers are present', async () => {
(headers as unknown as ReturnType<typeof vi.fn>).mockResolvedValue({
get: () => null,
});

await rateLimitDual('unknown-ip-test', 'email1@example.com', { limit: 1 });
await rateLimitDual('unknown-ip-test', 'email2@example.com', { limit: 1 });

const res = await rateLimitDual('unknown-ip-test', 'email3@example.com', { limit: 1 });
expect(res.allowed).toBe(false);
});
Comment thread src/app/actions/auth.ts
} from '@/lib/auth';
import { logger } from '@/lib/logger';
import { rateLimit } from '@/lib/rate-limit';
import { rateLimitDual } from '@/lib/rate-limit';

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/lib/rate-limit.ts (1)

82-84: πŸ”’ Security & Privacy | πŸ”΅ Trivial | ⚑ Quick win

Log the header-access failure instead of silently swallowing it.

The catch block discards the error without any logging. If headers() fails repeatedly in production, the IP-based layer of rateLimitDual is silently disabled and only the target-based layer remains, with no visibility into the degradation.

As per coding guidelines, use the structured logger from src/lib/logger.ts instead of leaving the error unlogged.

πŸ› οΈ Proposed fix
   } catch {
-    // Graceful degradation if headers() throws or is unavailable
+    // Graceful degradation if headers() throws or is unavailable.
+    logger.warn({ actionType }, 'rateLimitDual: headers() unavailable, IP-based limit skipped');
   }
πŸ€– Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/rate-limit.ts` around lines 82 - 84, Update the catch block in
rateLimitDual to log the headers() access failure using the structured logger
from logger.ts, including the caught error and clear context, while preserving
the existing graceful-degradation behavior.

Source: Coding guidelines

πŸ€– Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/lib/rate-limit.ts`:
- Around line 82-84: Update the catch block in rateLimitDual to log the
headers() access failure using the structured logger from logger.ts, including
the caught error and clear context, while preserving the existing
graceful-degradation behavior.

ℹ️ Review info
βš™οΈ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: a5fcb1d6-d48d-4f7f-bf94-e61ed659bf20

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between 9d0e0bf and e5f53d0.

πŸ“’ Files selected for processing (5)
  • .jules/sentinel.md
  • src/__tests__/setup.ts
  • src/app/actions/auth.ts
  • src/lib/__tests__/rate-limit.test.ts
  • src/lib/rate-limit.ts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants