🛡️ Sentinel: Add Honeypot to Contact Form #51

Closed
ragusa-it wants to merge 1 commits from sentinel-honeypot-fix-4259546573877746528 into main
ragusa-it commented 2026-02-03 02:08:16 +00:00 (Migrated from github.com)

🛡️ Sentinel: [Security Enhancement] Add Honeypot to Contact Form

Vulnerability:
Automated bots can spam the contact form, exhausting EmailJS quotas and cluttering the inbox.

Impact:

  • Denial of Service (DoS) via quota exhaustion.
  • Increased noise for administrators.

Fix:
Implemented a "honeypot" field (website) that is visually hidden from human users but visible to bots scanning the HTML.
If a bot fills this field:

  1. The submission is silently rejected (no email sent).
  2. The UI shows a success message to fool the bot into thinking it succeeded, preventing it from retrying immediately.

Verification:

  • Added a new test case silently rejects submission when honeypot field is filled in Contact.test.tsx.
  • Verified that existing functionality remains intact for legitimate users (empty honeypot).
  • Fixed existing tests that were using example.com (which is blocked by the app's security logic).

PR created automatically by Jules for task 4259546573877746528 started by @ragusa-it

🛡️ Sentinel: [Security Enhancement] Add Honeypot to Contact Form **Vulnerability:** Automated bots can spam the contact form, exhausting EmailJS quotas and cluttering the inbox. **Impact:** - Denial of Service (DoS) via quota exhaustion. - Increased noise for administrators. **Fix:** Implemented a "honeypot" field (`website`) that is visually hidden from human users but visible to bots scanning the HTML. If a bot fills this field: 1. The submission is silently rejected (no email sent). 2. The UI shows a success message to fool the bot into thinking it succeeded, preventing it from retrying immediately. **Verification:** - Added a new test case `silently rejects submission when honeypot field is filled` in `Contact.test.tsx`. - Verified that existing functionality remains intact for legitimate users (empty honeypot). - Fixed existing tests that were using `example.com` (which is blocked by the app's security logic). --- *PR created automatically by Jules for task [4259546573877746528](https://jules.google.com/task/4259546573877746528) started by @ragusa-it*
google-labs-jules[bot] commented 2026-02-03 02:08:17 +00:00 (Migrated from github.com)

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

👋 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](https://jules.google.com/settings). You can always switch back! New to Jules? Learn more at [jules.google/docs](https://jules.google/docs). --- *_For security, I will only act on instructions from the user who triggered this task._*
chatgpt-codex-connector[bot] (Migrated from github.com) reviewed 2026-02-03 02:10:17 +00:00
chatgpt-codex-connector[bot] (Migrated from github.com) left a comment

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7ef5c5f779

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

### 💡 Codex Review Here are some automated review suggestions for this pull request. **Reviewed commit:** `7ef5c5f779` <details> <summary>ℹ️ About Codex in GitHub</summary> <br/> [Your team has set up Codex to review pull requests in this repo](http://chatgpt.com/codex/settings/general). Reviews are triggered when you - Open a pull request for review - Mark a draft as ready - Comment "@codex review". If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". </details>
chatgpt-codex-connector[bot] (Migrated from github.com) commented 2026-02-03 02:10:17 +00:00

P2 Badge Skip rate limit for honeypot submissions

Because checkRateLimit() runs before the honeypot guard, any submission that accidentally fills the hidden website field (e.g., browser/password manager autofill that ignores autoComplete="off") will still consume the rate‑limit window and return a fake success. That leaves a legitimate user unable to resubmit for the cooldown period even though no email was sent. Consider moving the honeypot check before checkRateLimit() or bypassing the limiter when website is filled.

Useful? React with 👍 / 👎.

**<sub><sub>![P2 Badge](https://img.shields.io/badge/P2-yellow?style=flat)</sub></sub> Skip rate limit for honeypot submissions** Because `checkRateLimit()` runs before the honeypot guard, any submission that accidentally fills the hidden `website` field (e.g., browser/password manager autofill that ignores `autoComplete="off"`) will still consume the rate‑limit window and return a fake success. That leaves a legitimate user unable to resubmit for the cooldown period even though no email was sent. Consider moving the honeypot check before `checkRateLimit()` or bypassing the limiter when `website` is filled. Useful? React with 👍 / 👎.
copilot-pull-request-reviewer[bot] (Migrated from github.com) reviewed 2026-02-03 02:14:11 +00:00
copilot-pull-request-reviewer[bot] (Migrated from github.com) left a comment

Pull request overview

This PR hardens the contact form against bot spam by adding a client-side honeypot field and aligning tests and documentation with the updated security behavior.

Changes:

  • Extend the contact form data model and submit handler to include a hidden website honeypot field that clears and reports success without sending emails when filled.
  • Add styling and a hidden form control for the honeypot, plus a new unit test verifying that honeypot submissions are silently rejected while existing tests are updated to use non-blocked email domains.
  • Update Sentinel documentation to capture lessons learned about using blocked domains in test data.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
src/pages/Contact.tsx Adds website to form state and a honeypot short-circuit in handleSubmit, and renders a visually/semantically hidden honeypot input.
src/pages/__tests__/Contact.test.tsx Updates tests to use safe email domains and placeholders, and adds a honeypot behavior test (currently querying the hidden honeypot field in a way that will fail).
src/pages/Contact.module.css Introduces .honeypot styles to visually hide the honeypot field while keeping it in the DOM.
.jules/sentinel.md Documents the risk of using blocked domains like example.com in tests and recommends safe alternatives.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

## Pull request overview This PR hardens the contact form against bot spam by adding a client-side honeypot field and aligning tests and documentation with the updated security behavior. **Changes:** - Extend the contact form data model and submit handler to include a hidden `website` honeypot field that clears and reports success without sending emails when filled. - Add styling and a hidden form control for the honeypot, plus a new unit test verifying that honeypot submissions are silently rejected while existing tests are updated to use non-blocked email domains. - Update Sentinel documentation to capture lessons learned about using blocked domains in test data. ### Reviewed changes Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment. | File | Description | | ---- | ----------- | | `src/pages/Contact.tsx` | Adds `website` to form state and a honeypot short-circuit in `handleSubmit`, and renders a visually/semantically hidden honeypot input. | | `src/pages/__tests__/Contact.test.tsx` | Updates tests to use safe email domains and placeholders, and adds a honeypot behavior test (currently querying the hidden honeypot field in a way that will fail). | | `src/pages/Contact.module.css` | Introduces `.honeypot` styles to visually hide the honeypot field while keeping it in the DOM. | | `.jules/sentinel.md` | Documents the risk of using blocked domains like `example.com` in tests and recommends safe alternatives. | --- 💡 <a href="/ragusa-it/ragusaitweb/new/main/.github/instructions?filename=*.instructions.md" class="Link--inTextBlock" target="_blank" rel="noopener noreferrer">Add Copilot custom instructions</a> for smarter, more guided reviews. <a href="https://docs.github.com/en/copilot/customizing-copilot/adding-repository-custom-instructions-for-github-copilot" class="Link--inTextBlock" target="_blank" rel="noopener noreferrer">Learn how to get started</a>.
copilot-pull-request-reviewer[bot] (Migrated from github.com) commented 2026-02-03 02:14:11 +00:00

Because the honeypot container is rendered with aria-hidden="true" in Contact.tsx, getByLabelText('Website') with default options will not find the input (Testing Library excludes aria-hidden content from accessibility queries), causing this test to fail. To reliably target the honeypot field while keeping it hidden from assistive tech, query it using an option that includes hidden elements (for example, enabling the hidden flag) or switch to a different selector that does not rely on the accessibility tree (such as a test id or role query that allows hidden elements).

    fireEvent.change(screen.getByRole('textbox', { name: 'Website', hidden: true }), {
      target: { value: 'http://spambot.com' },
    });
Because the honeypot container is rendered with `aria-hidden="true"` in `Contact.tsx`, `getByLabelText('Website')` with default options will not find the input (Testing Library excludes aria-hidden content from accessibility queries), causing this test to fail. To reliably target the honeypot field while keeping it hidden from assistive tech, query it using an option that includes hidden elements (for example, enabling the `hidden` flag) or switch to a different selector that does not rely on the accessibility tree (such as a test id or role query that allows hidden elements). ```suggestion fireEvent.change(screen.getByRole('textbox', { name: 'Website', hidden: true }), { target: { value: 'http://spambot.com' }, }); ```

Pull request closed

Sign in to join this conversation.