Skip to content

[Security] Server-Side Request Forgery via IMAP Email Server Configuration #148

Description

@keyblues

Summary

The email sync feature allows users to configure custom IMAP server host and port. In lib/email-sync/imap-client.ts:5-18, buildImapConfig() passes these user-controlled parameters directly to imap-simple, which establishes a TCP connection to the specified host and port. An attacker can configure a malicious IMAP server address through addEmailServerAction() and trigger SSRF.

Details

In app/(app)/apps/email/actions.ts:20-50, addEmailServerAction() accepts user-controlled serverData including host and port without validation. The stored config is used by syncServer() in lib/email-sync/ingest.ts:38-48, calling client.fetchMessages(). Inside buildImapConfig() (lib/email-sync/imap-client.ts:5-18), user-provided host and port are directly used in the IMAP connection config. imaps.connect() at line 22 establishes a TCP connection to the attacker-specified host and port. testImapConnection() at line 60-67 also uses the same vulnerable function.

Core vulnerable code path:

// app/(app)/apps/email/actions.ts:20-35
export async function addEmailServerAction(
  serverData: Omit<EmailServer, "id" | "status" | "lastSync" | "addedAt">
): Promise<{ success: boolean; error?: string }> {
    const newServer: EmailServer = {
      ...serverData,

User-controlled host and port in serverData are accepted without validation

// lib/email-sync/imap-client.ts:5-18
function buildImapConfig(config: ImapConnectConfig) {
  return {
    imap: {
      host: config.host,
      port: config.port,
      tls: config.tls,
    },
  }
}

User-controlled host and port directly used in IMAP connection config

// lib/email-sync/imap-client.ts:20-23
export const realImapClient: ImapClient = {
  async fetchMessages(config: ImapConnectConfig, criteria: ImapSearchCriteria[]): Promise<ImapMessage[]> {
    const connection = await imaps.connect(buildImapConfig(config))

imaps.connect() establishes TCP connection to attacker-specified host:port

POC

Call addEmailServerAction with host='internal.service' and port=6379. Then call testEmailConnectionAction to trigger connection. Server makes TCP connection to internal.service:6379.

Impact

SSRF via TCP connection enabling internal network scanning, service fingerprinting, and firewall bypass.

Remediation

Restrict host to valid DNS names, block private IP ranges, limit ports to 143/993.

Disclosure Notes

Confirmed via source audit. No CVE ID.

Supplemental Information

Affected products

  • Ecosystem: self-hosted
  • Package name: vas3k/TaxHacker
  • Affected versions: main
  • Patched versions: none confirmed

Severity

  • Scoring method: CVSS v3.1
  • Score: 7.5
  • Vector string: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N

Weaknesses

  • CWE: CWE-918 Server-Side Request Forgery

Activity

  1. changed the title [-]Server-Side Request Forgery via IMAP Email Server Configuration[/-] [+][Security] Server-Side Request Forgery via IMAP Email Server Configuration[/+] on Jul 7, 2026
  2. 2W0-5T3P commented on Jul 31, 2026

    @2W0-5T3P
    Contributor

    @vas3k

    Is TaxHacker meant to support connecting to self-hosted/private-network IMAP servers?

    If not I've created a PR to fix this issue

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

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions