Skip to content

[Bug]: Unauthenticated email relay on task invite/funding/report #1624

Description

@a1woareS

Contact Details

alnaeem961@gmail.com

What happened?

Severity: Medium
CVSS 3.1: AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N → 5.3
CWE: CWE-770 (Allocation of Resources Without Limits or Throttling), CWE-183 (Permissive List of Allowed Inputs)
Affected versions: All versions (master @ ab67c6d)
Patched versions: None
Affected products: worknenjoy/gitpay — backend (src/)

Summary
Three task routes are registered before the secure middleware and therefore require no authentication. Each one sends email through the platform's SendGrid identity to a recipient and with content supplied by the caller. There is no rate limit. This lets an unauthenticated attacker use Gitpay as an email relay for phishing or spam that appears to originate from Gitpay, or to flood any mailbox.

Affected code
src/app/routes/tasks.ts:12-14 (all before router.use(secure))
12: router.post('/:id/invite/', controllers.inviteUserToTask)
13: router.post('/:id/funding/', controllers.inviteToFundingTask)
14: router.post('/:id/report', controllers.reportTask)
​
src/modules/tasks/taskInvite.ts — sends to body.email with body.name / body.message and the task's title/URL.
src/modules/tasks/taskFunding.ts — sends to body.email with body.comment, suggestedValue, username.
src/modules/tasks/taskReport.ts — builds an approval URL containing jwt.sign(task.id, SECRET_PHRASE) and emails it to the internal report address, using body.baseUrl, task.title, and body.reason.

Proof of concept
Runnable PoC: poc/09-unauthenticated-email-relay.js

POST /tasks/1/invite/ HTTP/1.1
Host:
Content-Type: application/json

{
"email": "attacker-controlled@example.com",
"name": "Gitpay Security",
"message": "Verify your account at https://attacker.example/login"
}
​
No Authorization header is required. The platform sends the email to the supplied address with the attacker's text, wrapped in Gitpay branding and a link to the task.
The same applies to:
POST /tasks/1/funding/
Content-Type: application/json

{"email":"victim@example.com","comment":"...","suggestedValue":"...","username":"..."}
​
Expected: authentication required; recipient fixed to the registered user; rate limiting.
Actual: unauthenticated send to an arbitrary address.

Impact
Gitpay's verified sending domain is used to deliver attacker-controlled content to arbitrary recipients (phishing/spam), and any address can be mailbox-flooded. The taskReport endpoint also lets an unauthenticated caller generate report emails containing signed task-deletion links.

Workarounds / Remediation
Move all three routes behind secure. Require the caller to own the task for invite/funding. Never take the recipient address from the client for invite/funding; send to the registered user's email. Add per-IP and per-account rate limits. For report, rate-limit and ignore client-supplied baseUrl.

References

router.post('/:id/invite/', controllers.inviteUserToTask)
router.post('/:id/funding/', controllers.inviteToFundingTask)
router.post('/:id/report', controllers.reportTask)

https://github.com/worknenjoy/gitpay/blob/ab67c6d741a7245ec200636c1b81c7bcc468d677/src/modules/tasks/taskInvite.ts
https://github.com/worknenjoy/gitpay/blob/ab67c6d741a7245ec200636c1b81c7bcc468d677/src/modules/tasks/taskFunding.ts
https://github.com/worknenjoy/gitpay/blob/ab67c6d741a7245ec200636c1b81c7bcc468d677/src/modules/tasks/taskReport.ts

regards
Alwoares

09-unauthenticated-email-relay.js

What browsers are you seeing the problem on?

Chrome

Relevant log output

💰 Is there a bounty for this issue?

Yes

💵 Bounty Amount (if any)

No response

📜 Bounty Details (if applicable)

No response

Activity

  1. johannschiffer commented on Oct 26, 2026

    @johannschiffer

    I have submitted a comprehensive fix for the unauthenticated email relay and authorization defects reported here in PR #1634 (#1634).

    Summary of Fix:

    1. Route Protection (src/app/routes/tasks.ts): Moved POST /tasks/:id/invite/, POST /tasks/:id/funding/, and POST /tasks/:id/report behind router.use(secure), enforcing bearer token authentication (returns 401 Unauthorized).
    2. Task Ownership Enforcement (src/modules/tasks/taskInvite.ts & taskFunding.ts): Strictly verifies Number(task.userId) === Number(user.id), returning 403 Forbidden if a caller tries to send invitations or funding notifications on someone else's task.
    3. Task Existence Verification (src/modules/tasks/taskInvite.ts, taskFunding.ts, taskReport.ts): Verifies the target task exists before sending any emails, returning 404 Not Found on non-existent IDs.
    4. Phishing Prevention & URL Sanitization (src/modules/tasks/taskReport.ts): Replaces client-supplied approveURL with trusted server base URL (process.env.API_HOST || process.env.FRONTEND_HOST || 'https://gitpay.me').
    5. Controller Error Status Propagation (src/app/controllers/task.ts): Passes req.user to modules and propagates 400/401/403/404 HTTP statuses.
    6. Automated Regression Tests: Added integration tests to test/api/task/taskCrud.test.ts verifying 401 unauthenticated, 403 unauthorized, and 404 non-existent task handling across all three endpoints.
  2. alfredoalvarado53-ui commented on Nov 10, 2026

    @alfredoalvarado53-ui

    Implemented in #1660:

    • Moved task invite, funding, and report routes behind router.use(secure).
    • Enforced task ownership checks in taskInvite so only the task owner can send invitations.
    • Sanitized taskReport to use trusted server host environment variables rather than client-supplied baseUrl.
    • Added automated regression tests in test/api/task/taskInviteFundingAuth.test.ts.

    PR: #1660
    Contributor Payout Address: 0xa554a9f6b26e6a418df3623b41e222e18a3b8da6

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions