Skip to content

πŸ›‘οΈ Sentinel: Fix brute force vulnerability on authentication actions#79

Open
projectamazonph wants to merge 1 commit into
mainfrom
jules-5824063639222886420-4d0a232d
Open

πŸ›‘οΈ Sentinel: Fix brute force vulnerability on authentication actions#79
projectamazonph wants to merge 1 commit into
mainfrom
jules-5824063639222886420-4d0a232d

Conversation

@projectamazonph

@projectamazonph projectamazonph commented Jul 24, 2026

Copy link
Copy Markdown
Owner

πŸ›‘οΈ Sentinel: [HIGH] Fix brute force vulnerability on authentication actions

🚨 Severity

HIGH

πŸ’‘ Vulnerability

Singly rate-limiting Server Actions by target email address allowed distributed credential stuffing or IP cycling to bypass rate limiting.

🎯 Impact

Malicious users could brute force credentials or run credential-stuffing campaigns against users.

πŸ”§ Fix

Implemented dual rate-limiting (IP-based + target/email-based) on unauthenticated entry points signUpAction and signInAction.

βœ… Verification

Added Vitest integration tests to verify that:

  • IP-based rate limiting blocks multiple requests from the same IP targeting different emails.
  • Target-based rate limiting blocks multiple requests targeting the same email even from different IPs.
    All 214 tests pass successfully. Linter check runs clean with zero errors. Production build is fully verified and successful.

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

Summary by CodeRabbit

  • Security Improvements

    • Added dual rate limiting for sign-in and sign-up attempts based on both email address and originating IP address.
    • Helps prevent repeated authentication attempts from bypassing protections by switching email addresses or network locations.
    • Added clearer feedback when requests are blocked due to IP-based limits.
  • Bug Fixes

    • Improved handling of forwarded client IP addresses when applying authentication safeguards.

- Retrieve client IP address using 'x-forwarded-for' and 'x-real-ip' headers.
- Rate-limit unauthenticated entry points (signInAction, signUpAction) using both IP-based and target-based keys.
- Mock headers in test suites to prevent failures and added integration tests verifying dual rate-limiting behaviors.

Co-authored-by: projectamazonph <286085559+projectamazonph@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 24, 2026 13:10
@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.

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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@ecc-tools

ecc-tools Bot commented Jul 24, 2026

Copy link
Copy Markdown

Analyzing 200 commits...

@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown

Review Change Stack

πŸ“ Walkthrough

Walkthrough

Authentication sign-in and sign-up actions now apply IP-based rate limiting alongside email-target limiting. Tests add controllable request-header mocks and verify both blocking paths.

Changes

Authentication rate limiting

Layer / File(s) Summary
Authentication rate-limit enforcement
.jules/sentinel.md, src/app/actions/auth.ts
signInAction and signUpAction derive client IPs from request headers and apply IP-based limits before email-target limits.
Rate-limit test coverage and header mocks
src/app/actions/__tests__/auth-actions.test.ts, src/__tests__/setup.ts, src/app/actions/__tests__/*-actions.test.ts
Mocks support headers().get(), and authentication tests cover email-target blocking after five attempts and IP blocking after ten attempts.

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

Sequence Diagram(s)

sequenceDiagram
  participant signInAction
  participant RequestHeaders
  participant RateLimiters
  signInAction->>RequestHeaders: Read client IP headers
  RequestHeaders-->>signInAction: Return IP or fallback
  signInAction->>RateLimiters: Check IP limit
  RateLimiters-->>signInAction: Allow or reject
  signInAction->>RateLimiters: Check email-target limit
  RateLimiters-->>signInAction: Allow or reject
Loading

Possibly related PRs

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 matches the main change: fixing a brute-force vulnerability in authentication 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 jules-5824063639222886420-4d0a232d

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.


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

@ecc-tools

ecc-tools Bot commented Jul 24, 2026

Copy link
Copy Markdown

Analysis Complete

Generated ECC bundle from 1 commits | Confidence: 55%

View Pull Request #80

Repository Profile
Attribute Value
Language TypeScript
Framework Not detected
Commit Convention conventional
Test Directory mixed
Changed Files (6)
Metric Value
Files changed 6
Additions 109
Deletions 6

Top hotspots

Path Status +/-
src/app/actions/__tests__/auth-actions.test.ts modified +68 / -0
src/app/actions/auth.ts modified +27 / -6
.jules/sentinel.md modified +5 / -0
src/__tests__/setup.ts modified +3 / -0
src/app/actions/__tests__/progress-actions.test.ts modified +3 / -0

Top directories

Directory Files Total changes
src/app/actions/__tests__ 3 74
src/app/actions 1 33
.jules 1 5
src/__tests__ 1 3
Analysis Depth Readiness (commit-history, 7%)

ECC Tools uses this to decide whether recommendations should stay at commit-history/setup guidance or expand into CI, security, harness, reference-set, AI-routing, and team backlog work.

Area Status Evidence / Next Step
Commit history Partial 1 commits sampled
CI/CD signals Missing Add workflow files or CI troubleshooting evidence so ECC Tools can reason about pipeline setup.
Security evidence Missing Add AgentShield, audit, SARIF, SBOM, or security review evidence so recommendations can cover security posture.
Harness configuration Missing Add Claude, Codex, OpenCode, Zed, dmux, MCP, plugin, or cross-harness config evidence for harness-agnostic recommendations.
Reference/eval evidence Missing Add fixtures, golden traces, reference sets, or evaluator benchmarks so deeper recommendations have regression evidence.
AI routing and cost controls Missing Add model-routing, budget, usage, or cost-control files before relying on AI-heavy automation recommendations.
Team handoff and project tracking Missing Add roadmap, runbook, project, Linear, or follow-up tracking docs so generated work can land in a team queue.
Reference Set Readiness (0/7, 0%)
Area Status Evidence / Next Step
Deep analyzer corpus Missing Add analyzer fixture, golden, benchmark, or reference-set files that can catch analyzer regressions.
RAG/evaluator comparison Missing Add retrieval or evaluator reference-set comparison fixtures with expected ranking behavior.
PR salvage/review corpus Missing Add stale-PR, review-thread, reopen-flow, or salvage reference cases for queue cleanup automation.
Discussion triage corpus Missing Add public discussion triage fixtures, golden cases, or reference sets for informational, answered, and no-response classifications.
Harness compatibility Missing Add cross-harness, adapter-compliance, or harness-audit evidence for Claude, Codex, OpenCode, Zed, dmux, and agent surfaces.
Security evidence Missing Attach security evidence such as SBOMs, SARIF, audit reports, or AgentShield evidence packs.
CI failure-mode evidence Missing Add captured CI failure logs, dry-run fixtures, or troubleshooting docs for common workflow failure modes.
Likely Future Issues (2)
Severity Signal Why it may show up
HIGH Auth or permission changes may ship without security regression coverage 1 auth/permission paths changed; 0 auth-focused integration or e2e tests changed
HIGH Security-sensitive changes may ship without scanner evidence 1 security-sensitive paths changed; 0 security scanner or security-focused validation artifacts changed
  • Auth or permission changes may ship without security regression coverage: The PR changes auth, session, middleware, or permission-sensitive files without touching any obvious auth-focused integration or end-to-end tests.
  • Security-sensitive changes may ship without scanner evidence: The PR touches billing, secrets, auth, webhooks, agent, or CI-sensitive surfaces without adding obvious security scanner, code scanning, or security-focused validation evidence.
Suggested Follow-up Work (2)
Type Suggested title Targets
PR test: add auth coverage for src/app/actions/auth.ts src/app/actions/auth.ts
PR security: add scanner evidence for src/app/actions/auth.ts src/app/actions/auth.ts
  • test: add auth coverage for src/app/actions/auth.ts: Backfill auth or permission regression coverage before another access-control change lands on the touched surface.
  • security: add scanner evidence for src/app/actions/auth.ts: Backfill explicit scanner or code-scanning evidence before another security-sensitive change lands on the touched surface.

Copy-ready bodies

test: add auth coverage for src/app/actions/auth.ts

## Summary
- Add auth, session, or permission regression coverage for the recently changed security-sensitive surface.

## Why
- Backfill auth or permission regression coverage before another access-control change lands on the touched surface.

## Touched paths
- `src/app/actions/auth.ts`

## Validation
- Add or extend integration / e2e coverage for the changed auth, session, middleware, or permission surface.
- Exercise allowed and denied flows, invalid or expired credentials, or equivalent access-control boundary cases.

security: add scanner evidence for src/app/actions/auth.ts

## Summary
- Add security scanner or code-scanning evidence for the recently changed security-sensitive surface.

## Why
- Backfill explicit scanner or code-scanning evidence before another security-sensitive change lands on the touched surface.

## Touched paths
- `src/app/actions/auth.ts`

## Validation
- Run or add the relevant security scanner, code scanning, secret scanning, or dependency/security review check for the touched surface.
- Attach the scanner output, SARIF/code-scanning result, or focused security regression test to the follow-up PR.
- Confirm the changed auth, billing, webhook, secret-handling, agent, or CI surface has an explicit pass/fail gate.
Review Activity (1 reviews, 0 inline comments, 0 unresolved threads)
Signal Count
Approvals 0
Change requests 0
Comment-only reviews 1
Dismissed reviews 0
Pending reviews 0
Review threads 0
Unresolved threads 0
Outdated threads 0
Latest review Commented
Latest submitted at 2026-07-24T13:10:15Z

Latest reviewer states

Reviewer State Submitted
@copilot-pull-request-reviewer[bot] Commented 2026-07-24T13:10:15Z
Review Follow-up Signals (1)
Severity Signal Evidence
MEDIUM Get an explicit approval No approving review is recorded for this PR

Recommended next actions

  • Ask for an approval after requested changes and unresolved discussions are addressed.
Generated Instincts (20)
Domain Count
git 4
code-style 9
testing 7

After merging, import with:

/instinct-import .claude/homunculus/instincts/inherited/amph-v2-instincts.yaml

Files

  • .claude/ecc-tools.json
  • .claude/skills/amph-v2/SKILL.md
  • .agents/skills/amph-v2/SKILL.md
  • .agents/skills/amph-v2/agents/openai.yaml
  • .claude/identity.json
  • .codex/config.toml
  • .codex/AGENTS.md
  • .codex/agents/explorer.toml
  • .codex/agents/reviewer.toml
  • .codex/agents/docs-researcher.toml
  • .claude/homunculus/instincts/inherited/amph-v2-instincts.yaml

ECC Tools | Everything Claude Code

@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.

Actionable comments posted: 3

πŸ€– 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.

Inline comments:
In @.jules/sentinel.md:
- Around line 8-11: Rewrite the β€œDual-Layer Rate Limiting on Authentication
Actions” section in plain language for non-security readers: replace or define
credential stuffing, brute force, target-based key, and β€œsingly rate-limiting,”
and explain the purpose of both account-based and IP-based limits without
changing the documented prevention guidance.

In `@src/app/actions/__tests__/auth-actions.test.ts`:
- Around line 151-209: Add equivalent dual rate-limiting regression tests for
signUpAction alongside the existing signInAction cases: verify repeated attempts
for the same email across different IPs are blocked at the target limit, and
different emails from one IP are blocked at the IP limit. Reuse the existing
mockHeadersGet and database setup patterns, and assert the expected non-blocked
and blocked error messages.

In `@src/app/actions/auth.ts`:
- Around line 36-48: Replace the raw x-forwarded-for/x-real-ip lookups used for
IP-based rate limiting in src/app/actions/auth.ts lines 36-48 and 139-151 with a
trusted canonical client-IP source or proxy-boundary helper, and use that value
for both signup and signin rate-limit keys. Do not allow callers to control the
limiter identity by supplying forwarding headers.
πŸͺ„ Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

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

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: bae08b36-2e08-4c12-b94f-53469f607152

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between dabee94 and 93c70f6.

πŸ“’ Files selected for processing (6)
  • .jules/sentinel.md
  • src/__tests__/setup.ts
  • src/app/actions/__tests__/auth-actions.test.ts
  • src/app/actions/__tests__/progress-actions.test.ts
  • src/app/actions/__tests__/tool-actions.test.ts
  • src/app/actions/auth.ts

Comment thread .jules/sentinel.md
Comment on lines +8 to +11
## 2026-07-24 - Dual-Layer Rate Limiting on Authentication Actions
**Vulnerability:** Singly rate-limiting Next.js Server Actions by target email allows a distributed credential stuffing/brute force attack where attackers change targets or IPs to bypass simple limits.
**Learning:** Target-based limits alone do not prevent brute-forcing different accounts from a single IP, and IP-based limits alone can easily block innocent users behind shared proxies/NATs if they hit limits too early.
**Prevention:** Implement dual rate-limiting on unauthenticated entry points (like sign-in and sign-up). Combine a target-based key (e.g. `signup:${email.toLowerCase()}`) with an IP-based key retrieved via request headers (`x-forwarded-for` / `x-real-ip`) to secure authentication actions robustly.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

πŸ“ Maintainability & Code Quality | 🟑 Minor | ⚑ Quick win

Define the security terms in plain language.

β€œCredential stuffing,” β€œbrute force,” and β€œtarget-based key” are not defined, and β€œsingly rate-limiting” is unclear. Rewrite this for readers without security background.

πŸ€– 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 @.jules/sentinel.md around lines 8 - 11, Rewrite the β€œDual-Layer Rate
Limiting on Authentication Actions” section in plain language for non-security
readers: replace or define credential stuffing, brute force, target-based key,
and β€œsingly rate-limiting,” and explain the purpose of both account-based and
IP-based limits without changing the documented prevention guidance.

Source: Coding guidelines

Comment on lines +151 to +209
describe('Dual Rate-Limiting', () => {
it('target-based rate limiting blocks the same email after 5 attempts even with different IPs', async () => {
const email = 'target-limit@rate.com';
(db.user.findUnique as unknown as ReturnType<typeof vi.fn>).mockResolvedValue(null);

// Make 5 successful non-blocked attempts with different IPs
for (let i = 1; i <= 5; i++) {
mockHeadersGet.mockImplementation((key: string) => {
if (key === 'x-forwarded-for') return `9.9.1.${i}`;
return null;
});
const result = await signInAction({ email, password: 'wrong' });
expect(result.success).toBe(false);
// It fails because the user doesn't exist/wrong password, but it is NOT blocked yet
if (!result.success) {
expect(result.error).toBe('Email or password is incorrect.');
}
}

// The 6th attempt with a new IP should be blocked by the target-based rate limiter
mockHeadersGet.mockImplementation((key: string) => {
if (key === 'x-forwarded-for') return '9.9.1.6';
return null;
});
const result = await signInAction({ email, password: 'wrong' });
expect(result.success).toBe(false);
if (!result.success) {
expect(result.error).toContain('Too many attempts.');
expect(result.error).not.toContain('from this IP');
}
});

it('IP-based rate limiting blocks different emails from the same IP after 10 attempts', async () => {
// Use a static IP for all requests
mockHeadersGet.mockImplementation((key: string) => {
if (key === 'x-forwarded-for') return '9.9.9.9';
return null;
});
(db.user.findUnique as unknown as ReturnType<typeof vi.fn>).mockResolvedValue(null);

// Make 10 attempts targeting different emails from the same IP
for (let i = 1; i <= 10; i++) {
const email = `ip-limit-${i}@rate.com`;
const result = await signInAction({ email, password: 'wrong' });
expect(result.success).toBe(false);
if (!result.success) {
expect(result.error).toBe('Email or password is incorrect.');
}
}

// The 11th attempt targeting a fresh email from the same IP should be blocked by the IP-based rate limiter
const email = 'ip-limit-11@rate.com';
const result = await signInAction({ email, password: 'wrong' });
expect(result.success).toBe(false);
if (!result.success) {
expect(result.error).toContain('Too many attempts from this IP.');
}
});
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟑 Minor | ⚑ Quick win

Add rate-limit regression tests for signUpAction.

This suite verifies only signInAction, while signUpAction gained the same IP and email limit logic. Add target-limit and IP-limit cases for sign-up so its security path cannot silently regress.

As per coding guidelines, β€œNew features must include tests; admin and business-layer features require tests.”

πŸ€– 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/app/actions/__tests__/auth-actions.test.ts` around lines 151 - 209, Add
equivalent dual rate-limiting regression tests for signUpAction alongside the
existing signInAction cases: verify repeated attempts for the same email across
different IPs are blocked at the target limit, and different emails from one IP
are blocked at the IP limit. Reuse the existing mockHeadersGet and database
setup patterns, and assert the expected non-blocked and blocked error messages.

Source: Coding guidelines

Comment thread src/app/actions/auth.ts
Comment on lines +36 to +48
const heads = await headers();
const ip = heads.get('x-forwarded-for') ?? heads.get('x-real-ip') ?? '127.0.0.1';

// 1. IP-based rate limiting to prevent distributed brute force / event-loop starvation
const ipRl = rateLimit(`signup:ip:${ip}`, 10, 60_000);
if (!ipRl.allowed) {
throw new Error(`Too many attempts from this IP. Try again in ${ipRl.retryAfterSeconds}s.`);
}

// 2. Target-based rate limiting to protect specific accounts
const targetRl = rateLimit(`signup:${data.email.toLowerCase()}`, 5, 60_000);
if (!targetRl.allowed) {
throw new Error(`Too many attempts. Try again in ${targetRl.retryAfterSeconds}s.`);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

πŸ”’ Security & Privacy | 🟠 Major | πŸ—οΈ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n## auth.ts\n'
sed -n '1,240p' src/app/actions/auth.ts

printf '\n## rateLimit references\n'
rg -n "function rateLimit|const rateLimit|rateLimit\(" src -g '*.ts' -g '*.tsx'

printf '\n## rateLimit implementation files\n'
fd -a "rateLimit" src

printf '\n## headers() usage in auth-related files\n'
rg -n "headers\(\)|x-forwarded-for|x-real-ip" src/app src/lib src/components -g '*.ts' -g '*.tsx'

Repository: projectamazonph/amph-v2

Length of output: 9985


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n## src/lib/rate-limit.ts\n'
sed -n '1,220p' src/lib/rate-limit.ts

printf '\n## src/lib/admin-audit.ts\n'
sed -n '1,120p' src/lib/admin-audit.ts

printf '\n## tests touching x-forwarded-for\n'
sed -n '1,260p' src/app/actions/__tests__/auth-actions.test.ts

Repository: projectamazonph/amph-v2

Length of output: 11932


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n## search for proxy/IP handling\n'
rg -n "trusted proxy|canonical IP|client IP|x-forwarded-for|x-real-ip|proxy" src docs . -g '*.ts' -g '*.tsx' -g '*.md' -g '*.mdx' -g '*.json'

printf '\n## middleware / edge / request handling files\n'
fd -a "middleware|proxy|ip|headers" src docs

Repository: projectamazonph/amph-v2

Length of output: 3613


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n## src/middleware.ts\n'
sed -n '1,220p' src/middleware.ts

printf '\n## src/lib/middleware-context.ts\n'
sed -n '1,220p' src/lib/middleware-context.ts

printf '\n## any request-ip helpers\n'
rg -n "ipAddress|clientIp|canonical.*ip|forwarded.*for|real-ip|headers\(\).*get\('x-forwarded-for'" src/lib src/app -g '*.ts' -g '*.tsx'

Repository: projectamazonph/amph-v2

Length of output: 6739


Do not use raw forwarding headers for rate-limit identity.

x-forwarded-for can be client-supplied and multi-hop, and x-real-ip is only trustworthy if a proxy sets it. With no canonical client-IP helper or trusted proxy boundary here, callers can vary the header value and sidestep the per-IP limiter.

  • src/app/actions/auth.ts#L36-L48: sign-up throttling is easy to evade.
  • src/app/actions/auth.ts#L139-L151: same issue on sign-in.
πŸ“ Affects 1 file
  • src/app/actions/auth.ts#L36-L48 (this comment)
  • src/app/actions/auth.ts#L139-L151
πŸ€– 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/app/actions/auth.ts` around lines 36 - 48, Replace the raw
x-forwarded-for/x-real-ip lookups used for IP-based rate limiting in
src/app/actions/auth.ts lines 36-48 and 139-151 with a trusted canonical
client-IP source or proxy-boundary helper, and use that value for both signup
and signin rate-limit keys. Do not allow callers to control the limiter identity
by supplying forwarding headers.

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